undefect. CWE-407 — 63 sites patched across 27 ecosystems
Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com Patches, unit tests, benchmarks, whitepaper, and outreach briefs. Public domain — no copyright claimed. Use freely.
This commit is contained in:
commit
0a580b313d
70422 changed files with 17213626 additions and 0 deletions
88
test/jdk/java/util/ArrayList/AddAll.java
Normal file
88
test/jdk/java/util/ArrayList/AddAll.java
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright (c) 2002, 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
|
||||
* 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 4715206
|
||||
* @summary Ensure that addAll method can cope with underestimate by size().
|
||||
* @author Josh Bloch
|
||||
*/
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Vector;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
public class AddAll {
|
||||
public static void main(String[] args) {
|
||||
for (int j = 0; j < 1; j++) {
|
||||
Map m = new WeakHashMap(100000);
|
||||
for (int i = 0; i < 100000; i++)
|
||||
m.put(new Object(), Boolean.TRUE);
|
||||
new ArrayList().addAll(m.keySet());
|
||||
}
|
||||
|
||||
for (int j = 0; j < 1; j++) {
|
||||
Map m = new WeakHashMap(100000);
|
||||
for (int i = 0; i < 100000; i++)
|
||||
m.put(new Object(), Boolean.TRUE);
|
||||
new LinkedList().addAll(m.keySet());
|
||||
}
|
||||
|
||||
for (int j = 0; j < 1; j++) {
|
||||
Map m = new WeakHashMap(100000);
|
||||
for (int i = 0; i < 100000; i++)
|
||||
m.put(new Object(), Boolean.TRUE);
|
||||
new Vector().addAll(m.keySet());
|
||||
}
|
||||
|
||||
for (int j = 0; j < 1; j++) {
|
||||
Map m = new WeakHashMap(100000);
|
||||
for (int i = 0; i < 100000; i++)
|
||||
m.put(new Object(), Boolean.TRUE);
|
||||
List list = new ArrayList();
|
||||
list.add("inka"); list.add("dinka"); list.add("doo");
|
||||
list.addAll(1, m.keySet());
|
||||
}
|
||||
|
||||
for (int j = 0; j < 1; j++) {
|
||||
Map m = new WeakHashMap(100000);
|
||||
for (int i = 0; i < 100000; i++)
|
||||
m.put(new Object(), Boolean.TRUE);
|
||||
List list = new LinkedList();
|
||||
list.add("inka"); list.add("dinka"); list.add("doo");
|
||||
list.addAll(1, m.keySet());
|
||||
}
|
||||
|
||||
for (int j = 0; j < 1; j++) {
|
||||
Map m = new WeakHashMap(100000);
|
||||
for (int i = 0; i < 100000; i++)
|
||||
m.put(new Object(), Boolean.TRUE);
|
||||
List list = new ArrayList();
|
||||
list.add("inka"); list.add("dinka"); list.add("doo");
|
||||
list.addAll(1, m.keySet());
|
||||
}
|
||||
}
|
||||
}
|
||||
214
test/jdk/java/util/ArrayList/ArrayManagement.java
Normal file
214
test/jdk/java/util/ArrayList/ArrayManagement.java
Normal file
|
|
@ -0,0 +1,214 @@
|
|||
/*
|
||||
* Copyright 2016 Google, Inc. 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 8146568
|
||||
* @summary brittle white box test of internal array management
|
||||
* @modules java.base/java.util:open
|
||||
* @run testng ArrayManagement
|
||||
*/
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.AbstractList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.SplittableRandom;
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
public class ArrayManagement {
|
||||
static final int DEFAULT_CAPACITY = 10;
|
||||
static final Field ELEMENT_DATA;
|
||||
static final Field MODCOUNT;
|
||||
static final SplittableRandom rnd = new SplittableRandom();
|
||||
|
||||
static {
|
||||
try {
|
||||
ELEMENT_DATA = ArrayList.class.getDeclaredField("elementData");
|
||||
ELEMENT_DATA.setAccessible(true);
|
||||
MODCOUNT = AbstractList.class.getDeclaredField("modCount");
|
||||
MODCOUNT.setAccessible(true);
|
||||
} catch (ReflectiveOperationException huh) {
|
||||
throw new AssertionError(huh);
|
||||
}
|
||||
}
|
||||
|
||||
static Object[] elementData(ArrayList<?> list) {
|
||||
try {
|
||||
return (Object[]) ELEMENT_DATA.get(list);
|
||||
} catch (ReflectiveOperationException huh) {
|
||||
throw new AssertionError(huh);
|
||||
}
|
||||
}
|
||||
|
||||
static int modCount(ArrayList<?> list) {
|
||||
try {
|
||||
return MODCOUNT.getInt(list);
|
||||
} catch (ReflectiveOperationException huh) {
|
||||
throw new AssertionError(huh);
|
||||
}
|
||||
}
|
||||
|
||||
static int capacity(ArrayList<?> list) {
|
||||
return elementData(list).length;
|
||||
}
|
||||
|
||||
static int newCapacity(int oldCapacity) {
|
||||
return oldCapacity + (oldCapacity >> 1);
|
||||
}
|
||||
|
||||
static void ensureCapacity(ArrayList<Object> list, int capacity) {
|
||||
int oldCapacity = capacity(list);
|
||||
int oldModCount = modCount(list);
|
||||
list.ensureCapacity(capacity);
|
||||
assertTrue(capacity(list) >= capacity || capacity(list) == 0);
|
||||
assertEquals(modCount(list),
|
||||
(capacity(list) == oldCapacity)
|
||||
? oldModCount
|
||||
: oldModCount + 1);
|
||||
}
|
||||
|
||||
static List<Object> singletonList() {
|
||||
return Collections.singletonList(Boolean.TRUE);
|
||||
}
|
||||
|
||||
/** Opportunistically randomly test various add operations. */
|
||||
static void addOneElement(ArrayList<Object> list) {
|
||||
int size = list.size();
|
||||
int modCount = modCount(list);
|
||||
switch (rnd.nextInt(4)) {
|
||||
case 0: assertTrue(list.add(Boolean.TRUE)); break;
|
||||
case 1: list.add(size, Boolean.TRUE); break;
|
||||
case 2: assertTrue(list.addAll(singletonList())); break;
|
||||
case 3: assertTrue(list.addAll(size, singletonList())); break;
|
||||
default: throw new AssertionError();
|
||||
}
|
||||
assertEquals(modCount(list), modCount + 1);
|
||||
assertEquals(list.size(), size + 1);
|
||||
}
|
||||
|
||||
@Test public void defaultCapacity() {
|
||||
ArrayList<Object> list = new ArrayList<>();
|
||||
assertEquals(capacity(new ArrayList<Object>()), 0);
|
||||
for (int i = 0; i < DEFAULT_CAPACITY; i++) {
|
||||
addOneElement(list);
|
||||
assertEquals(capacity(list), DEFAULT_CAPACITY);
|
||||
}
|
||||
addOneElement(list);
|
||||
assertEquals(capacity(list), newCapacity(DEFAULT_CAPACITY));
|
||||
}
|
||||
|
||||
@Test public void defaultCapacityEnsureCapacity() {
|
||||
ArrayList<Object> list = new ArrayList<>();
|
||||
for (int i = 0; i <= DEFAULT_CAPACITY; i++) {
|
||||
ensureCapacity(list, i); // no-op!
|
||||
assertEquals(capacity(list), 0);
|
||||
}
|
||||
for (int i = 0; i < DEFAULT_CAPACITY; i++) {
|
||||
addOneElement(list);
|
||||
assertEquals(capacity(list), DEFAULT_CAPACITY);
|
||||
}
|
||||
addOneElement(list);
|
||||
assertEquals(capacity(list), newCapacity(DEFAULT_CAPACITY));
|
||||
{
|
||||
int capacity = capacity(list);
|
||||
ensureCapacity(list, capacity + 1);
|
||||
assertEquals(capacity(list), newCapacity(capacity));
|
||||
}
|
||||
{
|
||||
int capacity = capacity(list);
|
||||
ensureCapacity(list, 3 * capacity);
|
||||
assertEquals(capacity(list), 3 * capacity);
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void ensureCapacityBeyondDefaultCapacity() {
|
||||
ArrayList<Object> list = new ArrayList<>();
|
||||
list.ensureCapacity(DEFAULT_CAPACITY + 1);
|
||||
assertEquals(capacity(list), DEFAULT_CAPACITY + 1);
|
||||
for (int i = 0; i < DEFAULT_CAPACITY + 1; i++) {
|
||||
addOneElement(list);
|
||||
assertEquals(capacity(list), DEFAULT_CAPACITY + 1);
|
||||
}
|
||||
addOneElement(list);
|
||||
assertEquals(capacity(list), newCapacity(DEFAULT_CAPACITY + 1));
|
||||
}
|
||||
|
||||
@Test public void explicitZeroCapacity() {
|
||||
ArrayList<Object> list = new ArrayList<>(0);
|
||||
assertEquals(capacity(list), 0);
|
||||
addOneElement(list);
|
||||
assertEquals(capacity(list), 1);
|
||||
addOneElement(list);
|
||||
assertEquals(capacity(list), 2);
|
||||
addOneElement(list);
|
||||
assertEquals(capacity(list), 3);
|
||||
addOneElement(list);
|
||||
assertEquals(capacity(list), 4);
|
||||
addOneElement(list);
|
||||
assertEquals(capacity(list), 6);
|
||||
addOneElement(list);
|
||||
assertEquals(capacity(list), 6);
|
||||
addOneElement(list);
|
||||
assertEquals(capacity(list), 9);
|
||||
list.clear();
|
||||
assertEquals(capacity(list), 9);
|
||||
}
|
||||
|
||||
@Test public void explicitLargeCapacity() {
|
||||
int n = DEFAULT_CAPACITY * 3;
|
||||
ArrayList<Object> list = new ArrayList<>(n);
|
||||
assertEquals(capacity(list), n);
|
||||
ensureCapacity(list, 0);
|
||||
ensureCapacity(list, n);
|
||||
for (int i = 0; i < n; i++) addOneElement(list);
|
||||
assertEquals(capacity(list), n);
|
||||
|
||||
addOneElement(list);
|
||||
assertEquals(capacity(list), newCapacity(n));
|
||||
}
|
||||
|
||||
@Test public void emptyArraysAreShared() {
|
||||
assertSame(elementData(new ArrayList<Object>()),
|
||||
elementData(new ArrayList<Object>()));
|
||||
assertSame(elementData(new ArrayList<Object>(0)),
|
||||
elementData(new ArrayList<Object>(0)));
|
||||
}
|
||||
|
||||
@Test public void emptyArraysDifferBetweenDefaultAndExplicit() {
|
||||
assertNotSame(elementData(new ArrayList<Object>()),
|
||||
elementData(new ArrayList<Object>(0)));
|
||||
}
|
||||
|
||||
@Test public void negativeCapacity() {
|
||||
for (int capacity : new int[] { -1, Integer.MIN_VALUE }) {
|
||||
try {
|
||||
new ArrayList<Object>(capacity);
|
||||
fail("should throw");
|
||||
} catch (IllegalArgumentException success) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
70
test/jdk/java/util/ArrayList/Bug6533203.java
Normal file
70
test/jdk/java/util/ArrayList/Bug6533203.java
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright (c) 2007, 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
|
||||
* 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 6533203
|
||||
* @summary AbstractList.ListItr.add might corrupt iterator state if enclosing add throws
|
||||
*/
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
@SuppressWarnings({"serial","unchecked"})
|
||||
public class Bug6533203 {
|
||||
void test(String[] args) throws Throwable {
|
||||
final List<Integer> superstitious = new ArrayList<>() {
|
||||
public void add(int index, Integer i) {
|
||||
if (i == 13) throw new Error("unlucky");
|
||||
else super.add(index, i); }};
|
||||
final ListIterator it = superstitious.listIterator(0);
|
||||
equal(it.nextIndex(), 0);
|
||||
THROWS(Error.class, new F(){void f(){it.add(13);}});
|
||||
equal(it.nextIndex(), 0);
|
||||
}
|
||||
|
||||
//--------------------- Infrastructure ---------------------------
|
||||
volatile int passed = 0, failed = 0;
|
||||
void pass() {passed++;}
|
||||
void fail() {failed++; Thread.dumpStack();}
|
||||
void fail(String msg) {System.out.println(msg); fail();}
|
||||
void unexpected(Throwable t) {failed++; t.printStackTrace();}
|
||||
void check(boolean cond) {if (cond) pass(); else fail();}
|
||||
void equal(Object x, Object y) {
|
||||
if (x == null ? y == null : x.equals(y)) pass();
|
||||
else fail(x + " not equal to " + y);}
|
||||
public static void main(String[] args) throws Throwable {
|
||||
new Bug6533203().instanceMain(args);}
|
||||
void instanceMain(String[] args) throws Throwable {
|
||||
try {test(args);} catch (Throwable t) {unexpected(t);}
|
||||
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
|
||||
if (failed > 0) throw new AssertionError("Some tests failed");}
|
||||
abstract class F {abstract void f() throws Throwable;}
|
||||
void THROWS(Class<? extends Throwable> k, F... fs) {
|
||||
for (F f : fs)
|
||||
try {f.f(); fail("Expected " + k.getName() + " not thrown");}
|
||||
catch (Throwable t) {
|
||||
if (k.isAssignableFrom(t.getClass())) pass();
|
||||
else unexpected(t);}}
|
||||
}
|
||||
43
test/jdk/java/util/ArrayList/Bug8146568.java
Normal file
43
test/jdk/java/util/ArrayList/Bug8146568.java
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright 2016 Google, Inc. 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 8146568
|
||||
* @summary repro for: NegativeArraySizeException in ArrayList.grow(int)
|
||||
* @run main/manual/othervm -Xmx17g Bug8146568
|
||||
* @requires os.maxMemory>17G
|
||||
*/
|
||||
|
||||
public class Bug8146568 {
|
||||
public static void main(String[] args) {
|
||||
int size = Integer.MAX_VALUE - 2;
|
||||
java.util.ArrayList<Object> huge = new java.util.ArrayList<>(size);
|
||||
for (int i = 0; i < size; i++)
|
||||
huge.add(null);
|
||||
try {
|
||||
huge.addAll(huge);
|
||||
throw new Error("expected OutOfMemoryError not thrown");
|
||||
} catch (OutOfMemoryError success) {}
|
||||
}
|
||||
}
|
||||
64
test/jdk/java/util/ArrayList/EnsureCapacity.java
Normal file
64
test/jdk/java/util/ArrayList/EnsureCapacity.java
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright (c) 2010, 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
|
||||
* 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 6992121
|
||||
* @summary Test the ArrayList.ensureCapacity() and Vector.ensureCapacity
|
||||
* method with negative minimumCapacity input argument.
|
||||
*/
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Vector;
|
||||
|
||||
public class EnsureCapacity {
|
||||
public static void main(String[] args) {
|
||||
testArrayList();
|
||||
testVector();
|
||||
}
|
||||
|
||||
private static void checkCapacity(int before, int after) {
|
||||
if (before != after) {
|
||||
throw new RuntimeException("capacity is expected to be unchanged: " +
|
||||
"before=" + before + " after=" + after);
|
||||
}
|
||||
}
|
||||
|
||||
private static void testArrayList() {
|
||||
ArrayList<String> al = new ArrayList<String>();
|
||||
al.add("abc");
|
||||
al.ensureCapacity(Integer.MIN_VALUE);
|
||||
|
||||
// there is no method to query the capacity of ArrayList
|
||||
// so before and after capacity are not checked
|
||||
}
|
||||
|
||||
private static void testVector() {
|
||||
Vector<String> vector = new Vector<String>();
|
||||
vector.add("abc");
|
||||
|
||||
int cap = vector.capacity();
|
||||
vector.ensureCapacity(Integer.MIN_VALUE);
|
||||
checkCapacity(cap, vector.capacity());
|
||||
}
|
||||
}
|
||||
710
test/jdk/java/util/ArrayList/IteratorMicroBenchmark.java
Normal file
710
test/jdk/java/util/ArrayList/IteratorMicroBenchmark.java
Normal file
|
|
@ -0,0 +1,710 @@
|
|||
/*
|
||||
* Copyright (c) 2007, 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
|
||||
* 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
|
||||
* @summary micro-benchmark correctness mode
|
||||
* @run main IteratorMicroBenchmark iterations=1 size=8 warmup=0
|
||||
*/
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
import java.util.Spliterator;
|
||||
import java.util.Vector;
|
||||
import java.util.concurrent.ConcurrentSkipListMap;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Usage: [iterations=N] [size=N] [filter=REGEXP] [warmup=SECONDS]
|
||||
*
|
||||
* To run this in micro-benchmark mode, simply run as a normal java program.
|
||||
* Be patient; this program runs for a very long time.
|
||||
* For faster runs, restrict execution using command line args.
|
||||
*
|
||||
* @author Martin Buchholz
|
||||
*/
|
||||
public class IteratorMicroBenchmark {
|
||||
abstract static class Job {
|
||||
private final String name;
|
||||
public Job(String name) { this.name = name; }
|
||||
public String name() { return name; }
|
||||
public abstract void work() throws Throwable;
|
||||
}
|
||||
|
||||
static double warmupSeconds;
|
||||
static long warmupNanos;
|
||||
|
||||
// --------------- GC finalization infrastructure ---------------
|
||||
|
||||
/** No guarantees, but effective in practice. */
|
||||
static void forceFullGc() {
|
||||
long timeoutMillis = 1000L;
|
||||
CountDownLatch finalized = new CountDownLatch(1);
|
||||
ReferenceQueue<Object> queue = new ReferenceQueue<>();
|
||||
WeakReference<Object> ref = new WeakReference<>(
|
||||
new Object() { protected void finalize() { finalized.countDown(); }},
|
||||
queue);
|
||||
try {
|
||||
for (int tries = 3; tries--> 0; ) {
|
||||
System.gc();
|
||||
if (finalized.await(timeoutMillis, MILLISECONDS)
|
||||
&& queue.remove(timeoutMillis) != null
|
||||
&& ref.get() == null) {
|
||||
System.runFinalization(); // try to pick up stragglers
|
||||
return;
|
||||
}
|
||||
timeoutMillis *= 4;
|
||||
}
|
||||
} catch (InterruptedException unexpected) {
|
||||
throw new AssertionError("unexpected InterruptedException");
|
||||
}
|
||||
throw new AssertionError("failed to do a \"full\" gc");
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs each job for long enough that all the runtime compilers
|
||||
* have had plenty of time to warm up, i.e. get around to
|
||||
* compiling everything worth compiling.
|
||||
* Returns array of average times per job per run.
|
||||
*/
|
||||
private static long[] time0(Job ... jobs) throws Throwable {
|
||||
long[] nanoss = new long[jobs.length];
|
||||
for (int i = 0; i < jobs.length; i++) {
|
||||
if (warmupNanos > 0) forceFullGc();
|
||||
Job job = jobs[i];
|
||||
long totalTime;
|
||||
int runs = 0;
|
||||
long startTime = System.nanoTime();
|
||||
do { job.work(); runs++; }
|
||||
while ((totalTime = System.nanoTime() - startTime) < warmupNanos);
|
||||
nanoss[i] = totalTime/runs;
|
||||
}
|
||||
return nanoss;
|
||||
}
|
||||
|
||||
private static void time(Job ... jobs) throws Throwable {
|
||||
if (warmupSeconds > 0.0) time0(jobs); // Warm up run
|
||||
long[] nanoss = time0(jobs); // Real timing run
|
||||
long[] milliss = new long[jobs.length];
|
||||
double[] ratios = new double[jobs.length];
|
||||
|
||||
final String nameHeader = "Method";
|
||||
final String millisHeader = "Millis";
|
||||
final String ratioHeader = "Ratio";
|
||||
|
||||
int nameWidth = nameHeader.length();
|
||||
int millisWidth = millisHeader.length();
|
||||
int ratioWidth = ratioHeader.length();
|
||||
|
||||
for (int i = 0; i < jobs.length; i++) {
|
||||
nameWidth = Math.max(nameWidth, jobs[i].name().length());
|
||||
|
||||
milliss[i] = nanoss[i]/(1000L * 1000L);
|
||||
millisWidth = Math.max(millisWidth,
|
||||
String.format("%d", milliss[i]).length());
|
||||
|
||||
ratios[i] = (double) nanoss[i] / (double) nanoss[0];
|
||||
ratioWidth = Math.max(ratioWidth,
|
||||
String.format("%.3f", ratios[i]).length());
|
||||
}
|
||||
|
||||
String format = String.format("%%-%ds %%%dd %%%d.3f%%n",
|
||||
nameWidth, millisWidth, ratioWidth);
|
||||
String headerFormat = String.format("%%-%ds %%%ds %%%ds%%n",
|
||||
nameWidth, millisWidth, ratioWidth);
|
||||
System.out.printf(headerFormat, "Method", "Millis", "Ratio");
|
||||
|
||||
// Print out absolute and relative times, calibrated against first job
|
||||
for (int i = 0; i < jobs.length; i++)
|
||||
System.out.printf(format, jobs[i].name(), milliss[i], ratios[i]);
|
||||
}
|
||||
|
||||
private static String keywordValue(String[] args, String keyword) {
|
||||
for (String arg : args)
|
||||
if (arg.startsWith(keyword))
|
||||
return arg.substring(keyword.length() + 1);
|
||||
return null;
|
||||
}
|
||||
|
||||
private static int intArg(String[] args, String keyword, int defaultValue) {
|
||||
String val = keywordValue(args, keyword);
|
||||
return (val == null) ? defaultValue : Integer.parseInt(val);
|
||||
}
|
||||
|
||||
private static double doubleArg(String[] args, String keyword, double defaultValue) {
|
||||
String val = keywordValue(args, keyword);
|
||||
return (val == null) ? defaultValue : Double.parseDouble(val);
|
||||
}
|
||||
|
||||
private static Pattern patternArg(String[] args, String keyword) {
|
||||
String val = keywordValue(args, keyword);
|
||||
return (val == null) ? null : Pattern.compile(val);
|
||||
}
|
||||
|
||||
private static Job[] filter(Pattern filter, Job[] jobs) {
|
||||
return (filter == null) ? jobs
|
||||
: Arrays.stream(jobs)
|
||||
.filter(job -> filter.matcher(job.name()).find())
|
||||
.collect(toList())
|
||||
.toArray(new Job[0]);
|
||||
}
|
||||
|
||||
private static void deoptimize(int sum) {
|
||||
if (sum == 42)
|
||||
System.out.println("the answer");
|
||||
}
|
||||
|
||||
private static <T> List<T> asSubList(List<T> list) {
|
||||
return list.subList(0, list.size());
|
||||
}
|
||||
|
||||
private static <T> Iterable<T> backwards(final List<T> list) {
|
||||
return new Iterable<T>() {
|
||||
public Iterator<T> iterator() {
|
||||
return new Iterator<T>() {
|
||||
final ListIterator<T> it = list.listIterator(list.size());
|
||||
public boolean hasNext() { return it.hasPrevious(); }
|
||||
public T next() { return it.previous(); }
|
||||
public void remove() { it.remove(); }};}};
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
final int iterations = intArg(args, "iterations", 100_000);
|
||||
final int size = intArg(args, "size", 1000);
|
||||
warmupSeconds = doubleArg(args, "warmup", 7.0);
|
||||
final Pattern filter = patternArg(args, "filter");
|
||||
|
||||
warmupNanos = (long) (warmupSeconds * (1000L * 1000L * 1000L));
|
||||
|
||||
// System.out.printf(
|
||||
// "iterations=%d size=%d, warmup=%1g, filter=\"%s\"%n",
|
||||
// iterations, size, warmupSeconds, filter);
|
||||
|
||||
final ConcurrentSkipListMap<Integer,Integer> m
|
||||
= new ConcurrentSkipListMap<>();
|
||||
final ArrayList<Integer> al = new ArrayList<>(size);
|
||||
|
||||
// Populate collections with random data
|
||||
final ThreadLocalRandom rnd = ThreadLocalRandom.current();
|
||||
for (int i = 0; i < size; i++) {
|
||||
m.put(rnd.nextInt(size), rnd.nextInt(size));
|
||||
al.add(rnd.nextInt(size));
|
||||
}
|
||||
final Vector<Integer> v = new Vector<>(al);
|
||||
final ArrayDeque<Integer> ad = new ArrayDeque<>(al);
|
||||
// shuffle ArrayDeque elements so they wrap
|
||||
for (int i = 0, n = rnd.nextInt(size); i < n; i++)
|
||||
ad.addLast(ad.removeFirst());
|
||||
|
||||
// Also test "short" collections
|
||||
final int shortSize = 5;
|
||||
final Vector<Integer> sv = new Vector<>(v.subList(0, shortSize));
|
||||
final ArrayList<Integer> sal = new ArrayList<>(sv);
|
||||
|
||||
// Checks for correctness *and* prevents loop optimizations
|
||||
class Check {
|
||||
private int sum;
|
||||
public void sum(int sum) {
|
||||
if (this.sum == 0)
|
||||
this.sum = sum;
|
||||
if (this.sum != sum)
|
||||
throw new AssertionError("Sum mismatch");
|
||||
}
|
||||
}
|
||||
final Check check = new Check();
|
||||
final Check shortCheck = new Check();
|
||||
|
||||
Job[] jobs = {
|
||||
// new Job("Vector iterate desugared") {
|
||||
// public void work() throws Throwable {
|
||||
// for (int i = 0; i < iterations; i++) {
|
||||
// int sum = 0;
|
||||
// for (Iterator<Integer> it = v.iterator(); it.hasNext();)
|
||||
// sum += it.next();
|
||||
// check.sum(sum);}}},
|
||||
new Job("array loop") {
|
||||
public void work() throws Throwable {
|
||||
Integer[] a = al.toArray(new Integer[0]);
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
int sum = 0;
|
||||
int size = a.length;
|
||||
for (int j = 0; j < size; ++j)
|
||||
sum += a[j];
|
||||
check.sum(sum);}}},
|
||||
new Job("descending array loop") {
|
||||
public void work() throws Throwable {
|
||||
Integer[] a = al.toArray(new Integer[0]);
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
int sum = 0;
|
||||
int size = a.length;
|
||||
for (int j = size - 1; j >= 0; j--)
|
||||
sum += a[j];
|
||||
check.sum(sum);}}},
|
||||
new Job("Vector get loop") {
|
||||
public void work() throws Throwable {
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
int sum = 0;
|
||||
int size = v.size();
|
||||
for (int j = 0; j < size; ++j)
|
||||
sum += v.get(j);
|
||||
check.sum(sum);}}},
|
||||
new Job("Vector iterate for loop") {
|
||||
public void work() throws Throwable {
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
int sum = 0;
|
||||
for (Integer n : v)
|
||||
sum += n;
|
||||
check.sum(sum);}}},
|
||||
new Job("Vector descending listIterator loop") {
|
||||
public void work() throws Throwable {
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
int sum = 0;
|
||||
ListIterator<Integer> it = v.listIterator(al.size());
|
||||
while (it.hasPrevious())
|
||||
sum += it.previous();
|
||||
check.sum(sum);}}},
|
||||
new Job("Vector Enumeration loop") {
|
||||
public void work() throws Throwable {
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
int sum = 0;
|
||||
Enumeration<Integer> it = v.elements();
|
||||
while (it.hasMoreElements())
|
||||
sum += it.nextElement();
|
||||
check.sum(sum);}}},
|
||||
new Job("Vector subList iterate for loop") {
|
||||
public void work() throws Throwable {
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
int sum = 0;
|
||||
for (Integer n : asSubList(v))
|
||||
sum += n;
|
||||
check.sum(sum);}}},
|
||||
new Job("Vector subList subList subList iterate for loop") {
|
||||
public void work() throws Throwable {
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
int sum = 0;
|
||||
for (Integer n : asSubList(asSubList(asSubList(v))))
|
||||
sum += n;
|
||||
check.sum(sum);}}},
|
||||
new Job("Vector backwards wrapper ListIterator for loop") {
|
||||
public void work() throws Throwable {
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
int sum = 0;
|
||||
for (Integer n : backwards(v))
|
||||
sum += n;
|
||||
check.sum(sum);}}},
|
||||
new Job("Vector backwards wrapper subList ListIterator for loop") {
|
||||
public void work() throws Throwable {
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
int sum = 0;
|
||||
for (Integer n : backwards(asSubList(v)))
|
||||
sum += n;
|
||||
check.sum(sum);}}},
|
||||
// new Job("Vector iterate for loop invokeinterface") {
|
||||
// public void work() throws Throwable {
|
||||
// final List<Integer> l = v;
|
||||
// for (int i = 0; i < iterations; i++) {
|
||||
// int sum = 0;
|
||||
// for (Integer n : l)
|
||||
// sum += n;
|
||||
// check.sum(sum);}}},
|
||||
// new Job("Vector subList iterate for loop invokeinterface") {
|
||||
// public void work() throws Throwable {
|
||||
// final List<Integer> l = v;
|
||||
// for (int i = 0; i < iterations; i++) {
|
||||
// int sum = 0;
|
||||
// for (Integer n : asSubList(l))
|
||||
// sum += n;
|
||||
// check.sum(sum);}}},
|
||||
new Job("Short Vector get loop") {
|
||||
public void work() throws Throwable {
|
||||
for (int i = 0; i < (iterations * size / shortSize); i++) {
|
||||
int sum = 0;
|
||||
int size = sv.size();
|
||||
for (int j = 0; j < size; ++j)
|
||||
sum += sv.get(j);
|
||||
shortCheck.sum(sum);}}},
|
||||
new Job("Short Vector iterate for loop") {
|
||||
public void work() throws Throwable {
|
||||
for (int i = 0; i < (iterations * size / shortSize); i++) {
|
||||
int sum = 0;
|
||||
for (Integer n : sv)
|
||||
sum += n;
|
||||
shortCheck.sum(sum);}}},
|
||||
new Job("Short Vector sublist iterate for loop") {
|
||||
public void work() throws Throwable {
|
||||
for (int i = 0; i < (iterations * size / shortSize); i++) {
|
||||
int sum = 0;
|
||||
for (Integer n : asSubList(sv))
|
||||
sum += n;
|
||||
shortCheck.sum(sum);}}},
|
||||
new Job("ArrayList get loop") {
|
||||
public void work() throws Throwable {
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
int sum = 0;
|
||||
int size = al.size();
|
||||
for (int j = 0; j < size; ++j)
|
||||
sum += al.get(j);
|
||||
check.sum(sum);}}},
|
||||
new Job("ArrayList iterate for loop") {
|
||||
public void work() throws Throwable {
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
int sum = 0;
|
||||
for (Integer n : al)
|
||||
sum += n;
|
||||
check.sum(sum);}}},
|
||||
new Job("ArrayDeque iterate for loop") {
|
||||
public void work() throws Throwable {
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
int sum = 0;
|
||||
for (Integer n : ad)
|
||||
sum += n;
|
||||
check.sum(sum);}}},
|
||||
new Job("ArrayList descending listIterator loop") {
|
||||
public void work() throws Throwable {
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
int sum = 0;
|
||||
ListIterator<Integer> it = al.listIterator(al.size());
|
||||
while (it.hasPrevious())
|
||||
sum += it.previous();
|
||||
check.sum(sum);}}},
|
||||
new Job("ArrayList listIterator loop") {
|
||||
public void work() throws Throwable {
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
int sum = 0;
|
||||
ListIterator<Integer> it = al.listIterator();
|
||||
while (it.hasNext())
|
||||
sum += it.next();
|
||||
check.sum(sum);}}},
|
||||
new Job("ArrayDeque.descendingIterator() loop") {
|
||||
public void work() throws Throwable {
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
int sum = 0;
|
||||
Iterator<Integer> it = ad.descendingIterator();
|
||||
while (it.hasNext())
|
||||
sum += it.next();
|
||||
check.sum(sum);}}},
|
||||
new Job("ArrayList.forEach") {
|
||||
public void work() throws Throwable {
|
||||
int[] sum = new int[1];
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
sum[0] = 0;
|
||||
al.forEach(n -> sum[0] += n);
|
||||
check.sum(sum[0]);}}},
|
||||
new Job("ArrayDeque.forEach") {
|
||||
public void work() throws Throwable {
|
||||
int[] sum = new int[1];
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
sum[0] = 0;
|
||||
ad.forEach(n -> sum[0] += n);
|
||||
check.sum(sum[0]);}}},
|
||||
new Job("Vector.forEach") {
|
||||
public void work() throws Throwable {
|
||||
int[] sum = new int[1];
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
sum[0] = 0;
|
||||
v.forEach(n -> sum[0] += n);
|
||||
check.sum(sum[0]);}}},
|
||||
new Job("ArrayList.iterator().forEachRemaining()") {
|
||||
public void work() throws Throwable {
|
||||
int[] sum = new int[1];
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
sum[0] = 0;
|
||||
al.iterator().forEachRemaining(n -> sum[0] += n);
|
||||
check.sum(sum[0]);}}},
|
||||
new Job("ArrayDeque.descendingIterator().forEachRemaining()") {
|
||||
public void work() throws Throwable {
|
||||
int[] sum = new int[1];
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
sum[0] = 0;
|
||||
ad.descendingIterator().forEachRemaining(n -> sum[0] += n);
|
||||
check.sum(sum[0]);}}},
|
||||
new Job("ArrayDeque.iterator().forEachRemaining()") {
|
||||
public void work() throws Throwable {
|
||||
int[] sum = new int[1];
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
sum[0] = 0;
|
||||
ad.iterator().forEachRemaining(n -> sum[0] += n);
|
||||
check.sum(sum[0]);}}},
|
||||
new Job("Vector.iterator().forEachRemaining()") {
|
||||
public void work() throws Throwable {
|
||||
int[] sum = new int[1];
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
sum[0] = 0;
|
||||
v.iterator().forEachRemaining(n -> sum[0] += n);
|
||||
check.sum(sum[0]);}}},
|
||||
new Job("ArrayList.spliterator().forEachRemaining()") {
|
||||
public void work() throws Throwable {
|
||||
int[] sum = new int[1];
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
sum[0] = 0;
|
||||
al.spliterator().forEachRemaining(n -> sum[0] += n);
|
||||
check.sum(sum[0]);}}},
|
||||
new Job("ArrayDeque.spliterator().forEachRemaining()") {
|
||||
public void work() throws Throwable {
|
||||
int[] sum = new int[1];
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
sum[0] = 0;
|
||||
ad.spliterator().forEachRemaining(n -> sum[0] += n);
|
||||
check.sum(sum[0]);}}},
|
||||
new Job("Vector.spliterator().forEachRemaining()") {
|
||||
public void work() throws Throwable {
|
||||
int[] sum = new int[1];
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
sum[0] = 0;
|
||||
v.spliterator().forEachRemaining(n -> sum[0] += n);
|
||||
check.sum(sum[0]);}}},
|
||||
new Job("ArrayList.spliterator().tryAdvance()") {
|
||||
public void work() throws Throwable {
|
||||
int[] sum = new int[1];
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
sum[0] = 0;
|
||||
Spliterator<Integer> spliterator = al.spliterator();
|
||||
do {} while (spliterator.tryAdvance(n -> sum[0] += n));
|
||||
check.sum(sum[0]);}}},
|
||||
new Job("ArrayDeque.spliterator().tryAdvance()") {
|
||||
public void work() throws Throwable {
|
||||
int[] sum = new int[1];
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
sum[0] = 0;
|
||||
Spliterator<Integer> spliterator = ad.spliterator();
|
||||
do {} while (spliterator.tryAdvance(n -> sum[0] += n));
|
||||
check.sum(sum[0]);}}},
|
||||
new Job("Vector.spliterator().tryAdvance()") {
|
||||
public void work() throws Throwable {
|
||||
int[] sum = new int[1];
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
sum[0] = 0;
|
||||
Spliterator<Integer> spliterator = v.spliterator();
|
||||
do {} while (spliterator.tryAdvance(n -> sum[0] += n));
|
||||
check.sum(sum[0]);}}},
|
||||
new Job("ArrayList.removeIf") {
|
||||
public void work() throws Throwable {
|
||||
int[] sum = new int[1];
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
sum[0] = 0;
|
||||
al.removeIf(n -> { sum[0] += n; return false; });
|
||||
check.sum(sum[0]);}}},
|
||||
new Job("ArrayDeque.removeIf") {
|
||||
public void work() throws Throwable {
|
||||
int[] sum = new int[1];
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
sum[0] = 0;
|
||||
ad.removeIf(n -> { sum[0] += n; return false; });
|
||||
check.sum(sum[0]);}}},
|
||||
new Job("Vector.removeIf") {
|
||||
public void work() throws Throwable {
|
||||
int[] sum = new int[1];
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
sum[0] = 0;
|
||||
v.removeIf(n -> { sum[0] += n; return false; });
|
||||
check.sum(sum[0]);}}},
|
||||
new Job("ArrayList subList .removeIf") {
|
||||
public void work() throws Throwable {
|
||||
int[] sum = new int[1];
|
||||
List<Integer> sl = asSubList(al);
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
sum[0] = 0;
|
||||
sl.removeIf(n -> { sum[0] += n; return false; });
|
||||
check.sum(sum[0]);}}},
|
||||
new Job("ArrayList subList get loop") {
|
||||
public void work() throws Throwable {
|
||||
List<Integer> sl = asSubList(al);
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
int sum = 0;
|
||||
int size = sl.size();
|
||||
for (int j = 0; j < size; ++j)
|
||||
sum += sl.get(j);
|
||||
check.sum(sum);}}},
|
||||
new Job("ArrayList subList iterate for loop") {
|
||||
public void work() throws Throwable {
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
int sum = 0;
|
||||
for (Integer n : asSubList(al))
|
||||
sum += n;
|
||||
check.sum(sum);}}},
|
||||
new Job("ArrayList subList subList subList iterate for loop") {
|
||||
public void work() throws Throwable {
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
int sum = 0;
|
||||
for (Integer n : asSubList(asSubList(asSubList(al))))
|
||||
sum += n;
|
||||
check.sum(sum);}}},
|
||||
new Job("ArrayList backwards wrapper ListIterator for loop") {
|
||||
public void work() throws Throwable {
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
int sum = 0;
|
||||
for (Integer n : backwards(al))
|
||||
sum += n;
|
||||
check.sum(sum);}}},
|
||||
new Job("ArrayList backwards wrapper subList ListIterator for loop") {
|
||||
public void work() throws Throwable {
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
int sum = 0;
|
||||
for (Integer n : backwards(asSubList(al)))
|
||||
sum += n;
|
||||
check.sum(sum);}}},
|
||||
// new Job("ArrayList iterate desugared") {
|
||||
// public void work() throws Throwable {
|
||||
// for (int i = 0; i < iterations; i++) {
|
||||
// int sum = 0;
|
||||
// for (Iterator<Integer> it = al.iterator(); it.hasNext();)
|
||||
// sum += it.next();
|
||||
// check.sum(sum);}}},
|
||||
new Job("Short ArrayList get loop") {
|
||||
public void work() throws Throwable {
|
||||
for (int i = 0; i < (iterations * size / shortSize); i++) {
|
||||
int sum = 0;
|
||||
int size = sal.size();
|
||||
for (int j = 0; j < size; ++j)
|
||||
sum += sal.get(j);
|
||||
shortCheck.sum(sum);}}},
|
||||
new Job("Short ArrayList iterate for loop") {
|
||||
public void work() throws Throwable {
|
||||
for (int i = 0; i < (iterations * size / shortSize); i++) {
|
||||
int sum = 0;
|
||||
for (Integer n : sal)
|
||||
sum += n;
|
||||
shortCheck.sum(sum);}}},
|
||||
new Job("Short ArrayList sublist iterate for loop") {
|
||||
public void work() throws Throwable {
|
||||
for (int i = 0; i < (iterations * size / shortSize); i++) {
|
||||
int sum = 0;
|
||||
for (Integer n : asSubList(sal))
|
||||
sum += n;
|
||||
shortCheck.sum(sum);}}},
|
||||
new Job("Vector ArrayList alternating iteration") {
|
||||
public void work() throws Throwable {
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
int sum = 0;
|
||||
Iterator<Integer> it1 = v.iterator();
|
||||
Iterator<Integer> it2 = al.iterator();
|
||||
while (it1.hasNext())
|
||||
sum += it1.next() + it2.next();
|
||||
check.sum(sum/2);}}},
|
||||
new Job("Vector ArrayList alternating invokeVirtual iteration") {
|
||||
public void work() throws Throwable {
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
int sum = 0;
|
||||
List<Iterator<Integer>> its = new ArrayList<>(2);
|
||||
its.add(v.iterator());
|
||||
its.add(al.iterator());
|
||||
for (int k = 0; its.get(k).hasNext(); k = (k == 0) ? 1 : 0)
|
||||
sum += its.get(k).next();
|
||||
check.sum(sum/2);}}},
|
||||
new Job("ConcurrentSkipListMap entrySet iterate") {
|
||||
public void work() throws Throwable {
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
int sum = 0;
|
||||
for (Map.Entry<Integer,Integer> e : m.entrySet())
|
||||
sum += e.getKey();
|
||||
deoptimize(sum);}}},
|
||||
new Job("ArrayList.toArray()") {
|
||||
public void work() throws Throwable {
|
||||
int[] sum = new int[1];
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
sum[0] = 0;
|
||||
for (Object o : al.toArray())
|
||||
sum[0] += (Integer) o;
|
||||
check.sum(sum[0]);}}},
|
||||
new Job("ArrayList.toArray(a)") {
|
||||
public void work() throws Throwable {
|
||||
Integer[] a = new Integer[size];
|
||||
int[] sum = new int[1];
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
sum[0] = 0;
|
||||
al.toArray(a);
|
||||
for (Object o : a)
|
||||
sum[0] += (Integer) o;
|
||||
check.sum(sum[0]);}}},
|
||||
new Job("ArrayList subList .toArray()") {
|
||||
public void work() throws Throwable {
|
||||
int[] sum = new int[1];
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
sum[0] = 0;
|
||||
for (Object o : asSubList(al).toArray())
|
||||
sum[0] += (Integer) o;
|
||||
check.sum(sum[0]);}}},
|
||||
new Job("ArrayList subList .toArray(a)") {
|
||||
public void work() throws Throwable {
|
||||
Integer[] a = new Integer[size];
|
||||
int[] sum = new int[1];
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
sum[0] = 0;
|
||||
asSubList(al).toArray(a);
|
||||
for (Object o : a)
|
||||
sum[0] += (Integer) o;
|
||||
check.sum(sum[0]);}}},
|
||||
new Job("ArrayDeque.toArray()") {
|
||||
public void work() throws Throwable {
|
||||
int[] sum = new int[1];
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
sum[0] = 0;
|
||||
for (Object o : ad.toArray())
|
||||
sum[0] += (Integer) o;
|
||||
check.sum(sum[0]);}}},
|
||||
new Job("ArrayDeque.toArray(a)") {
|
||||
public void work() throws Throwable {
|
||||
Integer[] a = new Integer[size];
|
||||
int[] sum = new int[1];
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
sum[0] = 0;
|
||||
ad.toArray(a);
|
||||
for (Object o : a)
|
||||
sum[0] += (Integer) o;
|
||||
check.sum(sum[0]);}}},
|
||||
new Job("Vector.toArray()") {
|
||||
public void work() throws Throwable {
|
||||
int[] sum = new int[1];
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
sum[0] = 0;
|
||||
for (Object o : v.toArray())
|
||||
sum[0] += (Integer) o;
|
||||
check.sum(sum[0]);}}},
|
||||
new Job("Vector.toArray(a)") {
|
||||
public void work() throws Throwable {
|
||||
Integer[] a = new Integer[size];
|
||||
int[] sum = new int[1];
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
sum[0] = 0;
|
||||
v.toArray(a);
|
||||
for (Object o : a)
|
||||
sum[0] += (Integer) o;
|
||||
check.sum(sum[0]);}}},
|
||||
};
|
||||
|
||||
time(filter(filter, jobs));
|
||||
}
|
||||
}
|
||||
234
test/jdk/java/util/ArrayList/RangeCheckMicroBenchmark.java
Normal file
234
test/jdk/java/util/ArrayList/RangeCheckMicroBenchmark.java
Normal file
|
|
@ -0,0 +1,234 @@
|
|||
/*
|
||||
* Copyright (c) 2007, 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
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is not a regression test, but a micro-benchmark.
|
||||
*
|
||||
* I have run this as follows:
|
||||
*
|
||||
* repeat 5 for f in -client -server; do mergeBench dolphin . jr -dsa -da $f RangeCheckMicroBenchmark.java; done
|
||||
*
|
||||
*
|
||||
* @author Martin Buchholz
|
||||
*/
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
public class RangeCheckMicroBenchmark {
|
||||
abstract static class Job {
|
||||
private final String name;
|
||||
Job(String name) { this.name = name; }
|
||||
String name() { return name; }
|
||||
abstract void work() throws Throwable;
|
||||
}
|
||||
|
||||
private static void collectAllGarbage() {
|
||||
final CountDownLatch drained = new CountDownLatch(1);
|
||||
try {
|
||||
System.gc(); // enqueue finalizable objects
|
||||
new Object() { protected void finalize() {
|
||||
drained.countDown(); }};
|
||||
System.gc(); // enqueue detector
|
||||
drained.await(); // wait for finalizer queue to drain
|
||||
System.gc(); // cleanup finalized objects
|
||||
} catch (InterruptedException e) { throw new Error(e); }
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs each job for long enough that all the runtime compilers
|
||||
* have had plenty of time to warm up, i.e. get around to
|
||||
* compiling everything worth compiling.
|
||||
* Returns array of average times per job per run.
|
||||
*/
|
||||
private static long[] time0(Job ... jobs) throws Throwable {
|
||||
final long warmupNanos = 10L * 1000L * 1000L * 1000L;
|
||||
long[] nanoss = new long[jobs.length];
|
||||
for (int i = 0; i < jobs.length; i++) {
|
||||
collectAllGarbage();
|
||||
long t0 = System.nanoTime();
|
||||
long t;
|
||||
int j = 0;
|
||||
do { jobs[i].work(); j++; }
|
||||
while ((t = System.nanoTime() - t0) < warmupNanos);
|
||||
nanoss[i] = t/j;
|
||||
}
|
||||
return nanoss;
|
||||
}
|
||||
|
||||
private static void time(Job ... jobs) throws Throwable {
|
||||
|
||||
long[] warmup = time0(jobs); // Warm up run
|
||||
long[] nanoss = time0(jobs); // Real timing run
|
||||
long[] milliss = new long[jobs.length];
|
||||
double[] ratios = new double[jobs.length];
|
||||
|
||||
final String nameHeader = "Method";
|
||||
final String millisHeader = "Millis";
|
||||
final String ratioHeader = "Ratio";
|
||||
|
||||
int nameWidth = nameHeader.length();
|
||||
int millisWidth = millisHeader.length();
|
||||
int ratioWidth = ratioHeader.length();
|
||||
|
||||
for (int i = 0; i < jobs.length; i++) {
|
||||
nameWidth = Math.max(nameWidth, jobs[i].name().length());
|
||||
|
||||
milliss[i] = nanoss[i]/(1000L * 1000L);
|
||||
millisWidth = Math.max(millisWidth,
|
||||
String.format("%d", milliss[i]).length());
|
||||
|
||||
ratios[i] = (double) nanoss[i] / (double) nanoss[0];
|
||||
ratioWidth = Math.max(ratioWidth,
|
||||
String.format("%.3f", ratios[i]).length());
|
||||
}
|
||||
|
||||
String format = String.format("%%-%ds %%%dd %%%d.3f%%n",
|
||||
nameWidth, millisWidth, ratioWidth);
|
||||
String headerFormat = String.format("%%-%ds %%%ds %%%ds%%n",
|
||||
nameWidth, millisWidth, ratioWidth);
|
||||
System.out.printf(headerFormat, "Method", "Millis", "Ratio");
|
||||
|
||||
// Print out absolute and relative times, calibrated against first job
|
||||
for (int i = 0; i < jobs.length; i++)
|
||||
System.out.printf(format, jobs[i].name(), milliss[i], ratios[i]);
|
||||
}
|
||||
|
||||
private static String keywordValue(String[] args, String keyword) {
|
||||
for (String arg : args)
|
||||
if (arg.startsWith(keyword))
|
||||
return arg.substring(keyword.length() + 1);
|
||||
return null;
|
||||
}
|
||||
|
||||
private static int intArg(String[] args, String keyword, int defaultValue) {
|
||||
String val = keywordValue(args, keyword);
|
||||
return val == null ? defaultValue : Integer.parseInt(val);
|
||||
}
|
||||
|
||||
private static Pattern patternArg(String[] args, String keyword) {
|
||||
String val = keywordValue(args, keyword);
|
||||
return val == null ? null : Pattern.compile(val);
|
||||
}
|
||||
|
||||
private static Job[] filter(Pattern filter, Job[] jobs) {
|
||||
return (filter == null) ? jobs
|
||||
: Arrays.stream(jobs)
|
||||
.filter(job -> filter.matcher(job.name()).find())
|
||||
.collect(toList())
|
||||
.toArray(new Job[0]);
|
||||
}
|
||||
|
||||
private static void deoptimize(ArrayList<Integer> list) {
|
||||
for (Integer x : list)
|
||||
if (x == null)
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
/**
|
||||
* Usage: [iterations=N] [size=N] [filter=REGEXP]
|
||||
*/
|
||||
public static void main(String[] args) throws Throwable {
|
||||
final int iterations = intArg(args, "iterations", 30000);
|
||||
final int size = intArg(args, "size", 1000);
|
||||
final Pattern filter = patternArg(args, "filter");
|
||||
|
||||
final ArrayList<Integer> list = new ArrayList<>();
|
||||
final Random rnd = new Random();
|
||||
for (int i = 0; i < size; i++)
|
||||
list.add(rnd.nextInt());
|
||||
|
||||
final Job[] jobs = {
|
||||
new Job("get") { void work() {
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
for (int k = 0; k < size; k++)
|
||||
if (list.get(k) == 42)
|
||||
throw new Error();
|
||||
}
|
||||
deoptimize(list);}},
|
||||
new Job("set") { void work() {
|
||||
Integer[] xs = list.toArray(new Integer[size]);
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
for (int k = 0; k < size; k++)
|
||||
list.set(k, xs[k]);
|
||||
}
|
||||
deoptimize(list);}},
|
||||
new Job("get/set") { void work() {
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
for (int k = 0; k < size; k++)
|
||||
list.set(k, list.get(size - k - 1));
|
||||
}
|
||||
deoptimize(list);}},
|
||||
new Job("add/remove at end") { void work() {
|
||||
Integer x = rnd.nextInt();
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
for (int k = 0; k < size - 1; k++) {
|
||||
list.add(size, x);
|
||||
list.remove(size);
|
||||
}
|
||||
}
|
||||
deoptimize(list);}},
|
||||
new Job("subList get") { void work() {
|
||||
List<Integer> sublist = list.subList(0, list.size());
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
for (int k = 0; k < size; k++)
|
||||
if (sublist.get(k) == 42)
|
||||
throw new Error();
|
||||
}
|
||||
deoptimize(list);}},
|
||||
new Job("subList set") { void work() {
|
||||
List<Integer> sublist = list.subList(0, list.size());
|
||||
Integer[] xs = sublist.toArray(new Integer[size]);
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
for (int k = 0; k < size; k++)
|
||||
sublist.set(k, xs[k]);
|
||||
}
|
||||
deoptimize(list);}},
|
||||
new Job("subList get/set") { void work() {
|
||||
List<Integer> sublist = list.subList(0, list.size());
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
for (int k = 0; k < size; k++)
|
||||
sublist.set(k, sublist.get(size - k - 1));
|
||||
}
|
||||
deoptimize(list);}},
|
||||
new Job("subList add/remove at end") { void work() {
|
||||
List<Integer> sublist = list.subList(0, list.size());
|
||||
Integer x = rnd.nextInt();
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
for (int k = 0; k < size - 1; k++) {
|
||||
sublist.add(size, x);
|
||||
sublist.remove(size);
|
||||
}
|
||||
}
|
||||
deoptimize(list);}}
|
||||
};
|
||||
|
||||
time(filter(filter, jobs));
|
||||
}
|
||||
}
|
||||
59
test/jdk/java/util/ArrayList/SortingModCount.java
Normal file
59
test/jdk/java/util/ArrayList/SortingModCount.java
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (c) 2024, 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
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8340572
|
||||
* @summary ConcurrentModificationException when sorting ArrayList sublists
|
||||
*/
|
||||
|
||||
public class SortingModCount {
|
||||
public static void main(String[] args) {
|
||||
testSortingSubListsDoesNotIncrementModCount();
|
||||
testSortingListDoesIncrementModCount();
|
||||
}
|
||||
|
||||
private static void testSortingSubListsDoesNotIncrementModCount() {
|
||||
List<Integer> l = new ArrayList<>(List.of(1, 2, 3, 4));
|
||||
var a = l.subList(0, 2);
|
||||
var b = l.subList(2, 4);
|
||||
Collections.sort(a);
|
||||
Collections.sort(b);
|
||||
}
|
||||
|
||||
private static void testSortingListDoesIncrementModCount() {
|
||||
List<Integer> l = new ArrayList<>(List.of(1, 2, 3, 4));
|
||||
var b = l.subList(2, 4);
|
||||
Collections.sort(l);
|
||||
try {
|
||||
Collections.sort(b);
|
||||
throw new Error("expected ConcurrentModificationException not thrown");
|
||||
} catch (ConcurrentModificationException expected) {
|
||||
}
|
||||
}
|
||||
}
|
||||
68
test/jdk/java/util/ArrayList/SubListModCount.java
Normal file
68
test/jdk/java/util/ArrayList/SubListModCount.java
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright (c) 2019, 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
|
||||
* 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 8234423
|
||||
* @summary Modifying ArrayList.subList().subList() resets modCount of subList
|
||||
*/
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.ConcurrentModificationException;
|
||||
|
||||
public class SubListModCount {
|
||||
public static void main(String[] args) {
|
||||
int failures = 0;
|
||||
var root = new ArrayList<Integer>();
|
||||
var subList = root.subList(0, 0);
|
||||
root.add(42);
|
||||
try {
|
||||
subList.size();
|
||||
failures++;
|
||||
System.out.println("Accessing subList");
|
||||
} catch (ConcurrentModificationException expected) {
|
||||
}
|
||||
var subSubList = subList.subList(0, 0);
|
||||
try {
|
||||
subSubList.size();
|
||||
failures++;
|
||||
System.out.println("Accessing subList.subList");
|
||||
} catch (ConcurrentModificationException expected) {
|
||||
}
|
||||
try {
|
||||
subSubList.add(42);
|
||||
failures++;
|
||||
System.out.println("Modifying subList.subList");
|
||||
} catch (ConcurrentModificationException expected) {
|
||||
}
|
||||
try {
|
||||
subList.size();
|
||||
failures++;
|
||||
System.out.println("Accessing subList again");
|
||||
} catch (ConcurrentModificationException expected) {
|
||||
}
|
||||
if (failures > 0) {
|
||||
throw new AssertionError(failures + " tests failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue