mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 06:45:07 +02:00
8156071: List.of: reduce array copying during creation
Reviewed-by: psandoz, redestad
This commit is contained in:
parent
ea27a54bf0
commit
88d75c9ad5
6 changed files with 203 additions and 18 deletions
|
@ -36,6 +36,7 @@ import java.util.function.BiFunction;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.function.UnaryOperator;
|
import java.util.function.UnaryOperator;
|
||||||
|
import jdk.internal.access.JavaUtilCollectionAccess;
|
||||||
import jdk.internal.access.SharedSecrets;
|
import jdk.internal.access.SharedSecrets;
|
||||||
import jdk.internal.misc.CDS;
|
import jdk.internal.misc.CDS;
|
||||||
import jdk.internal.vm.annotation.Stable;
|
import jdk.internal.vm.annotation.Stable;
|
||||||
|
@ -103,7 +104,7 @@ class ImmutableCollections {
|
||||||
CDS.initializeFromArchive(ImmutableCollections.class);
|
CDS.initializeFromArchive(ImmutableCollections.class);
|
||||||
if (archivedObjects == null) {
|
if (archivedObjects == null) {
|
||||||
EMPTY = new Object();
|
EMPTY = new Object();
|
||||||
EMPTY_LIST = new ListN<>();
|
EMPTY_LIST = new ListN<>(new Object[0]);
|
||||||
EMPTY_SET = new SetN<>();
|
EMPTY_SET = new SetN<>();
|
||||||
EMPTY_MAP = new MapN<>();
|
EMPTY_MAP = new MapN<>();
|
||||||
archivedObjects = new Object[] { EMPTY, EMPTY_LIST, EMPTY_SET, EMPTY_MAP };
|
archivedObjects = new Object[] { EMPTY, EMPTY_LIST, EMPTY_SET, EMPTY_MAP };
|
||||||
|
@ -115,6 +116,16 @@ class ImmutableCollections {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class Access {
|
||||||
|
static {
|
||||||
|
SharedSecrets.setJavaUtilCollectionAccess(new JavaUtilCollectionAccess() {
|
||||||
|
public <E> List<E> listFromTrustedArray(Object[] array) {
|
||||||
|
return ImmutableCollections.ListN.fromTrustedArray(array);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** No instances. */
|
/** No instances. */
|
||||||
private ImmutableCollections() { }
|
private ImmutableCollections() { }
|
||||||
|
|
||||||
|
@ -521,15 +532,31 @@ class ImmutableCollections {
|
||||||
@Stable
|
@Stable
|
||||||
private final E[] elements;
|
private final E[] elements;
|
||||||
|
|
||||||
|
private ListN(E[] array) {
|
||||||
|
elements = array;
|
||||||
|
}
|
||||||
|
|
||||||
|
// creates a new internal array, and checks and rejects null elements
|
||||||
@SafeVarargs
|
@SafeVarargs
|
||||||
ListN(E... input) {
|
static <E> List<E> fromArray(E... input) {
|
||||||
// copy and check manually to avoid TOCTOU
|
// copy and check manually to avoid TOCTOU
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
E[] tmp = (E[])new Object[input.length]; // implicit nullcheck of input
|
E[] tmp = (E[])new Object[input.length]; // implicit nullcheck of input
|
||||||
for (int i = 0; i < input.length; i++) {
|
for (int i = 0; i < input.length; i++) {
|
||||||
tmp[i] = Objects.requireNonNull(input[i]);
|
tmp[i] = Objects.requireNonNull(input[i]);
|
||||||
}
|
}
|
||||||
elements = tmp;
|
return new ListN<>(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Avoids creating a new array, but checks and rejects null elements.
|
||||||
|
// Declared with Object... arg so that varargs calls don't accidentally
|
||||||
|
// create an array of a subtype.
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
static <E> List<E> fromTrustedArray(Object... input) {
|
||||||
|
for (Object o : input) {
|
||||||
|
Objects.requireNonNull(o);
|
||||||
|
}
|
||||||
|
return new ListN<>((E[])input);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -842,7 +842,7 @@ public interface List<E> extends Collection<E> {
|
||||||
* @since 9
|
* @since 9
|
||||||
*/
|
*/
|
||||||
static <E> List<E> of(E e1, E e2, E e3) {
|
static <E> List<E> of(E e1, E e2, E e3) {
|
||||||
return new ImmutableCollections.ListN<>(e1, e2, e3);
|
return ImmutableCollections.ListN.fromTrustedArray(e1, e2, e3);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -861,7 +861,7 @@ public interface List<E> extends Collection<E> {
|
||||||
* @since 9
|
* @since 9
|
||||||
*/
|
*/
|
||||||
static <E> List<E> of(E e1, E e2, E e3, E e4) {
|
static <E> List<E> of(E e1, E e2, E e3, E e4) {
|
||||||
return new ImmutableCollections.ListN<>(e1, e2, e3, e4);
|
return ImmutableCollections.ListN.fromTrustedArray(e1, e2, e3, e4);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -881,7 +881,7 @@ public interface List<E> extends Collection<E> {
|
||||||
* @since 9
|
* @since 9
|
||||||
*/
|
*/
|
||||||
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5) {
|
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5) {
|
||||||
return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5);
|
return ImmutableCollections.ListN.fromTrustedArray(e1, e2, e3, e4, e5);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -902,8 +902,8 @@ public interface List<E> extends Collection<E> {
|
||||||
* @since 9
|
* @since 9
|
||||||
*/
|
*/
|
||||||
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6) {
|
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6) {
|
||||||
return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5,
|
return ImmutableCollections.ListN.fromTrustedArray(e1, e2, e3, e4, e5,
|
||||||
e6);
|
e6);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -925,8 +925,8 @@ public interface List<E> extends Collection<E> {
|
||||||
* @since 9
|
* @since 9
|
||||||
*/
|
*/
|
||||||
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7) {
|
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7) {
|
||||||
return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5,
|
return ImmutableCollections.ListN.fromTrustedArray(e1, e2, e3, e4, e5,
|
||||||
e6, e7);
|
e6, e7);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -949,8 +949,8 @@ public interface List<E> extends Collection<E> {
|
||||||
* @since 9
|
* @since 9
|
||||||
*/
|
*/
|
||||||
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8) {
|
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8) {
|
||||||
return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5,
|
return ImmutableCollections.ListN.fromTrustedArray(e1, e2, e3, e4, e5,
|
||||||
e6, e7, e8);
|
e6, e7, e8);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -974,8 +974,8 @@ public interface List<E> extends Collection<E> {
|
||||||
* @since 9
|
* @since 9
|
||||||
*/
|
*/
|
||||||
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9) {
|
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9) {
|
||||||
return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5,
|
return ImmutableCollections.ListN.fromTrustedArray(e1, e2, e3, e4, e5,
|
||||||
e6, e7, e8, e9);
|
e6, e7, e8, e9);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1000,8 +1000,8 @@ public interface List<E> extends Collection<E> {
|
||||||
* @since 9
|
* @since 9
|
||||||
*/
|
*/
|
||||||
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10) {
|
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10) {
|
||||||
return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5,
|
return ImmutableCollections.ListN.fromTrustedArray(e1, e2, e3, e4, e5,
|
||||||
e6, e7, e8, e9, e10);
|
e6, e7, e8, e9, e10);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1042,7 +1042,7 @@ public interface List<E> extends Collection<E> {
|
||||||
case 2:
|
case 2:
|
||||||
return new ImmutableCollections.List12<>(elements[0], elements[1]);
|
return new ImmutableCollections.List12<>(elements[0], elements[1]);
|
||||||
default:
|
default:
|
||||||
return new ImmutableCollections.ListN<>(elements);
|
return ImmutableCollections.ListN.fromArray(elements);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,8 @@ import java.util.function.ToDoubleFunction;
|
||||||
import java.util.function.ToIntFunction;
|
import java.util.function.ToIntFunction;
|
||||||
import java.util.function.ToLongFunction;
|
import java.util.function.ToLongFunction;
|
||||||
|
|
||||||
|
import jdk.internal.access.SharedSecrets;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementations of {@link Collector} that implement various useful reduction
|
* Implementations of {@link Collector} that implement various useful reduction
|
||||||
* operations, such as accumulating elements into collections, summarizing
|
* operations, such as accumulating elements into collections, summarizing
|
||||||
|
@ -296,7 +298,8 @@ public final class Collectors {
|
||||||
Collector<T, ?, List<T>> toUnmodifiableList() {
|
Collector<T, ?, List<T>> toUnmodifiableList() {
|
||||||
return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,
|
return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,
|
||||||
(left, right) -> { left.addAll(right); return left; },
|
(left, right) -> { left.addAll(right); return left; },
|
||||||
list -> (List<T>)List.of(list.toArray()),
|
list -> (List<T>)SharedSecrets.getJavaUtilCollectionAccess()
|
||||||
|
.listFromTrustedArray(list.toArray()),
|
||||||
CH_NOID);
|
CH_NOID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020, 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. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package jdk.internal.access;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface JavaUtilCollectionAccess {
|
||||||
|
<E> List<E> listFromTrustedArray(Object[] array);
|
||||||
|
}
|
|
@ -70,6 +70,7 @@ public class SharedSecrets {
|
||||||
private static JavaNetUriAccess javaNetUriAccess;
|
private static JavaNetUriAccess javaNetUriAccess;
|
||||||
private static JavaNetURLAccess javaNetURLAccess;
|
private static JavaNetURLAccess javaNetURLAccess;
|
||||||
private static JavaNioAccess javaNioAccess;
|
private static JavaNioAccess javaNioAccess;
|
||||||
|
private static JavaUtilCollectionAccess javaUtilCollectionAccess;
|
||||||
private static JavaUtilJarAccess javaUtilJarAccess;
|
private static JavaUtilJarAccess javaUtilJarAccess;
|
||||||
private static JavaUtilZipFileAccess javaUtilZipFileAccess;
|
private static JavaUtilZipFileAccess javaUtilZipFileAccess;
|
||||||
private static JavaUtilResourceBundleAccess javaUtilResourceBundleAccess;
|
private static JavaUtilResourceBundleAccess javaUtilResourceBundleAccess;
|
||||||
|
@ -77,6 +78,19 @@ public class SharedSecrets {
|
||||||
private static JavaSecuritySignatureAccess javaSecuritySignatureAccess;
|
private static JavaSecuritySignatureAccess javaSecuritySignatureAccess;
|
||||||
private static JavaxCryptoSealedObjectAccess javaxCryptoSealedObjectAccess;
|
private static JavaxCryptoSealedObjectAccess javaxCryptoSealedObjectAccess;
|
||||||
|
|
||||||
|
public static void setJavaUtilCollectionAccess(JavaUtilCollectionAccess juca) {
|
||||||
|
javaUtilCollectionAccess = juca;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JavaUtilCollectionAccess getJavaUtilCollectionAccess() {
|
||||||
|
if (javaUtilCollectionAccess == null) {
|
||||||
|
try {
|
||||||
|
Class.forName("java.util.ImmutableCollections$Access", true, null);
|
||||||
|
} catch (ClassNotFoundException e) {};
|
||||||
|
}
|
||||||
|
return javaUtilCollectionAccess;
|
||||||
|
}
|
||||||
|
|
||||||
public static JavaUtilJarAccess javaUtilJarAccess() {
|
public static JavaUtilJarAccess javaUtilJarAccess() {
|
||||||
if (javaUtilJarAccess == null) {
|
if (javaUtilJarAccess == null) {
|
||||||
// Ensure JarFile is initialized; we know that this class
|
// Ensure JarFile is initialized; we know that this class
|
||||||
|
|
109
test/micro/org/openjdk/bench/java/util/ListArgs.java
Normal file
109
test/micro/org/openjdk/bench/java/util/ListArgs.java
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019, 2020, 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.
|
||||||
|
*/
|
||||||
|
package org.openjdk.bench.java.util;
|
||||||
|
|
||||||
|
import org.openjdk.jmh.annotations.*;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Microbenchmarks for List.of fixed vs varargs implementations.
|
||||||
|
* Run with -Xint to avoid JIT compilation, in order to test
|
||||||
|
* common use cases of these methods being called from static
|
||||||
|
* initializers. Use parallel GC and set initial heap size to avoid
|
||||||
|
* GC during runs.
|
||||||
|
*/
|
||||||
|
@State(Scope.Benchmark)
|
||||||
|
@OutputTimeUnit(TimeUnit.MILLISECONDS)
|
||||||
|
@Fork(value = 3, jvmArgsAppend = { "-verbose:gc", "-XX:+UseParallelGC", "-Xms4g", "-Xmx4g", "-Xint" })
|
||||||
|
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
|
||||||
|
@Measurement(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS)
|
||||||
|
public class ListArgs {
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public Object list00() {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public Object list01() {
|
||||||
|
return List.of("a");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public Object list02() {
|
||||||
|
return List.of("a", "b");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public Object list03() {
|
||||||
|
return List.of("a", "b", "c");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public Object list04() {
|
||||||
|
return List.of("a", "b", "c", "d");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public Object list05() {
|
||||||
|
return List.of("a", "b", "c", "d", "e");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public Object list06() {
|
||||||
|
return List.of("a", "b", "c", "d", "e",
|
||||||
|
"f");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public Object list07() {
|
||||||
|
return List.of("a", "b", "c", "d", "e",
|
||||||
|
"f", "g");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public Object list08() {
|
||||||
|
return List.of("a", "b", "c", "d", "e",
|
||||||
|
"f", "g", "h");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public Object list09() {
|
||||||
|
return List.of("a", "b", "c", "d", "e",
|
||||||
|
"f", "g", "h", "i");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public Object list10() {
|
||||||
|
return List.of("a", "b", "c", "d", "e",
|
||||||
|
"f", "g", "h", "i", "j");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public Object list11() {
|
||||||
|
return List.of("a", "b", "c", "d", "e",
|
||||||
|
"f", "g", "h", "i", "j", "k");
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue