From 1f9c110c1f9ea6f5c3621a25692ce9d7abf245d4 Mon Sep 17 00:00:00 2001 From: Claes Redestad Date: Mon, 13 Feb 2023 11:17:38 +0000 Subject: [PATCH] 8301958: Reduce Arrays.copyOf/-Range overheads Reviewed-by: alanb, smarks --- .../share/classes/java/util/Arrays.java | 184 ++++++++++++++++-- .../bench/java/lang/StringConstructor.java | 34 ++-- 2 files changed, 188 insertions(+), 30 deletions(-) diff --git a/src/java.base/share/classes/java/util/Arrays.java b/src/java.base/share/classes/java/util/Arrays.java index f92cfd4fb68..7510addfe27 100644 --- a/src/java.base/share/classes/java/util/Arrays.java +++ b/src/java.base/share/classes/java/util/Arrays.java @@ -26,6 +26,7 @@ package java.util; import jdk.internal.util.ArraysSupport; +import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.annotation.IntrinsicCandidate; import java.io.Serializable; @@ -3534,12 +3535,22 @@ public class Arrays { * @since 1.6 */ public static byte[] copyOf(byte[] original, int newLength) { + if (newLength == original.length) { + return copyOf(original); + } byte[] copy = new byte[newLength]; System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; } + @ForceInline + private static byte[] copyOf(byte[] original) { + byte[] copy = new byte[original.length]; + System.arraycopy(original, 0, copy, 0, original.length); + return copy; + } + /** * Copies the specified array, truncating or padding with zeros (if necessary) * so the copy has the specified length. For all indices that are @@ -3558,12 +3569,22 @@ public class Arrays { * @since 1.6 */ public static short[] copyOf(short[] original, int newLength) { + if (newLength == original.length) { + return copyOf(original); + } short[] copy = new short[newLength]; System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; } + @ForceInline + private static short[] copyOf(short[] original) { + short[] copy = new short[original.length]; + System.arraycopy(original, 0, copy, 0, original.length); + return copy; + } + /** * Copies the specified array, truncating or padding with zeros (if necessary) * so the copy has the specified length. For all indices that are @@ -3582,12 +3603,22 @@ public class Arrays { * @since 1.6 */ public static int[] copyOf(int[] original, int newLength) { + if (newLength == original.length) { + return copyOf(original); + } int[] copy = new int[newLength]; System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; } + @ForceInline + private static int[] copyOf(int[] original) { + int[] copy = new int[original.length]; + System.arraycopy(original, 0, copy, 0, original.length); + return copy; + } + /** * Copies the specified array, truncating or padding with zeros (if necessary) * so the copy has the specified length. For all indices that are @@ -3606,12 +3637,22 @@ public class Arrays { * @since 1.6 */ public static long[] copyOf(long[] original, int newLength) { + if (newLength == original.length) { + return copyOf(original); + } long[] copy = new long[newLength]; System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; } + @ForceInline + private static long[] copyOf(long[] original) { + long[] copy = new long[original.length]; + System.arraycopy(original, 0, copy, 0, original.length); + return copy; + } + /** * Copies the specified array, truncating or padding with null characters (if necessary) * so the copy has the specified length. For all indices that are valid @@ -3630,12 +3671,22 @@ public class Arrays { * @since 1.6 */ public static char[] copyOf(char[] original, int newLength) { + if (newLength == original.length) { + return copyOf(original); + } char[] copy = new char[newLength]; System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; } + @ForceInline + private static char[] copyOf(char[] original) { + char[] copy = new char[original.length]; + System.arraycopy(original, 0, copy, 0, original.length); + return copy; + } + /** * Copies the specified array, truncating or padding with zeros (if necessary) * so the copy has the specified length. For all indices that are @@ -3654,12 +3705,22 @@ public class Arrays { * @since 1.6 */ public static float[] copyOf(float[] original, int newLength) { + if (newLength == original.length) { + return copyOf(original); + } float[] copy = new float[newLength]; System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; } + @ForceInline + private static float[] copyOf(float[] original) { + float[] copy = new float[original.length]; + System.arraycopy(original, 0, copy, 0, original.length); + return copy; + } + /** * Copies the specified array, truncating or padding with zeros (if necessary) * so the copy has the specified length. For all indices that are @@ -3678,12 +3739,22 @@ public class Arrays { * @since 1.6 */ public static double[] copyOf(double[] original, int newLength) { + if (newLength == original.length) { + return copyOf(original); + } double[] copy = new double[newLength]; System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; } + @ForceInline + private static double[] copyOf(double[] original) { + double[] copy = new double[original.length]; + System.arraycopy(original, 0, copy, 0, original.length); + return copy; + } + /** * Copies the specified array, truncating or padding with {@code false} (if necessary) * so the copy has the specified length. For all indices that are @@ -3702,12 +3773,22 @@ public class Arrays { * @since 1.6 */ public static boolean[] copyOf(boolean[] original, int newLength) { + if (newLength == original.length) { + return copyOf(original); + } boolean[] copy = new boolean[newLength]; System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; } + @ForceInline + private static boolean[] copyOf(boolean[] original) { + boolean[] copy = new boolean[original.length]; + System.arraycopy(original, 0, copy, 0, original.length); + return copy; + } + /** * Copies the specified range of the specified array into a new array. * The initial index of the range ({@code from}) must lie between zero @@ -3789,6 +3870,13 @@ public class Arrays { return copy; } + @ForceInline + private static void checkLength(int from, int to) { + if (to < from) { + throw new IllegalArgumentException(from + " > " + to); + } + } + /** * Copies the specified range of the specified array into a new array. * The initial index of the range ({@code from}) must lie between zero @@ -3816,9 +3904,17 @@ public class Arrays { * @since 1.6 */ public static byte[] copyOfRange(byte[] original, int from, int to) { + // Tickle the JIT to fold special cases optimally + if (from != 0 || to != original.length) + return copyOfRangeByte(original, from, to); + else // from == 0 && to == original.length + return copyOf(original); + } + + @ForceInline + private static byte[] copyOfRangeByte(byte[] original, int from, int to) { + checkLength(from, to); int newLength = to - from; - if (newLength < 0) - throw new IllegalArgumentException(from + " > " + to); byte[] copy = new byte[newLength]; System.arraycopy(original, from, copy, 0, Math.min(original.length - from, newLength)); @@ -3852,9 +3948,17 @@ public class Arrays { * @since 1.6 */ public static short[] copyOfRange(short[] original, int from, int to) { + // Tickle the JIT to fold special cases optimally + if (from != 0 || to != original.length) + return copyOfRangeShort(original, from, to); + else // from == 0 && to == original.length + return copyOf(original); + } + + @ForceInline + private static short[] copyOfRangeShort(short[] original, int from, int to) { + checkLength(from, to); int newLength = to - from; - if (newLength < 0) - throw new IllegalArgumentException(from + " > " + to); short[] copy = new short[newLength]; System.arraycopy(original, from, copy, 0, Math.min(original.length - from, newLength)); @@ -3888,9 +3992,17 @@ public class Arrays { * @since 1.6 */ public static int[] copyOfRange(int[] original, int from, int to) { + // Tickle the JIT to fold special cases optimally + if (from != 0 || to != original.length) + return copyOfRangeInt(original, from, to); + else // from == 0 && to == original.length + return copyOf(original); + } + + @ForceInline + private static int[] copyOfRangeInt(int[] original, int from, int to) { + checkLength(from, to); int newLength = to - from; - if (newLength < 0) - throw new IllegalArgumentException(from + " > " + to); int[] copy = new int[newLength]; System.arraycopy(original, from, copy, 0, Math.min(original.length - from, newLength)); @@ -3924,9 +4036,17 @@ public class Arrays { * @since 1.6 */ public static long[] copyOfRange(long[] original, int from, int to) { + // Tickle the JIT to fold special cases optimally + if (from != 0 || to != original.length) + return copyOfRangeLong(original, from, to); + else // from == 0 && to == original.length + return copyOf(original); + } + + @ForceInline + private static long[] copyOfRangeLong(long[] original, int from, int to) { + checkLength(from, to); int newLength = to - from; - if (newLength < 0) - throw new IllegalArgumentException(from + " > " + to); long[] copy = new long[newLength]; System.arraycopy(original, from, copy, 0, Math.min(original.length - from, newLength)); @@ -3960,9 +4080,17 @@ public class Arrays { * @since 1.6 */ public static char[] copyOfRange(char[] original, int from, int to) { + // Tickle the JIT to fold special cases optimally + if (from != 0 || to != original.length) + return copyOfRangeChar(original, from, to); + else // from == 0 && to == original.length + return copyOf(original); + } + + @ForceInline + private static char[] copyOfRangeChar(char[] original, int from, int to) { + checkLength(from, to); int newLength = to - from; - if (newLength < 0) - throw new IllegalArgumentException(from + " > " + to); char[] copy = new char[newLength]; System.arraycopy(original, from, copy, 0, Math.min(original.length - from, newLength)); @@ -3996,9 +4124,17 @@ public class Arrays { * @since 1.6 */ public static float[] copyOfRange(float[] original, int from, int to) { + // Tickle the JIT to fold special cases optimally + if (from != 0 || to != original.length) + return copyOfRangeFloat(original, from, to); + else // from == 0 && to == original.length + return copyOf(original); + } + + @ForceInline + private static float[] copyOfRangeFloat(float[] original, int from, int to) { + checkLength(from, to); int newLength = to - from; - if (newLength < 0) - throw new IllegalArgumentException(from + " > " + to); float[] copy = new float[newLength]; System.arraycopy(original, from, copy, 0, Math.min(original.length - from, newLength)); @@ -4032,9 +4168,17 @@ public class Arrays { * @since 1.6 */ public static double[] copyOfRange(double[] original, int from, int to) { + // Tickle the JIT to fold special cases optimally + if (from != 0 || to != original.length) + return copyOfRangeDouble(original, from, to); + else // from == 0 && to == original.length + return copyOf(original); + } + + @ForceInline + private static double[] copyOfRangeDouble(double[] original, int from, int to) { + checkLength(from, to); int newLength = to - from; - if (newLength < 0) - throw new IllegalArgumentException(from + " > " + to); double[] copy = new double[newLength]; System.arraycopy(original, from, copy, 0, Math.min(original.length - from, newLength)); @@ -4068,9 +4212,17 @@ public class Arrays { * @since 1.6 */ public static boolean[] copyOfRange(boolean[] original, int from, int to) { + // Tickle the JIT to fold special cases optimally + if (from != 0 || to != original.length) + return copyOfRangeBoolean(original, from, to); + else // from == 0 && to == original.length + return copyOf(original); + } + + @ForceInline + private static boolean[] copyOfRangeBoolean(boolean[] original, int from, int to) { + checkLength(from, to); int newLength = to - from; - if (newLength < 0) - throw new IllegalArgumentException(from + " > " + to); boolean[] copy = new boolean[newLength]; System.arraycopy(original, from, copy, 0, Math.min(original.length - from, newLength)); diff --git a/test/micro/org/openjdk/bench/java/lang/StringConstructor.java b/test/micro/org/openjdk/bench/java/lang/StringConstructor.java index bd6ba5200ec..1509d6b798f 100644 --- a/test/micro/org/openjdk/bench/java/lang/StringConstructor.java +++ b/test/micro/org/openjdk/bench/java/lang/StringConstructor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2023, 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 @@ -28,47 +28,53 @@ import org.openjdk.jmh.annotations.*; import java.nio.charset.StandardCharsets; import java.util.concurrent.TimeUnit; -@Fork(5) @State(Scope.Thread) @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Warmup(iterations = 5, time = 5) -@Measurement(iterations = 10, time = 5) +@Warmup(iterations = 5, time = 3) +@Measurement(iterations = 5, time = 3) +@Fork(3) public class StringConstructor { + + @Param({"7", "64"}) + public int size; + + // Offset to use for ranged newStrings + @Param("1") + public int offset; private byte[] array; @Setup public void setup() { - array = "".getBytes(StandardCharsets.UTF_8); + if (offset > size) { + offset = size; + } + array = "a".repeat(size).getBytes(StandardCharsets.UTF_8); } @Benchmark public String newStringFromArray() { - return new String(array); + return new String(array); } @Benchmark public String newStringFromArrayWithCharset() { - return new String(array, StandardCharsets.UTF_8); + return new String(array, StandardCharsets.UTF_8); } @Benchmark public String newStringFromArrayWithCharsetName() throws Exception { - return new String(array, StandardCharsets.UTF_8.name()); + return new String(array, StandardCharsets.UTF_8.name()); } @Benchmark public String newStringFromRangedArray() { - return new String(array, 0, 0); + return new String(array, offset, array.length - offset); } @Benchmark public String newStringFromRangedArrayWithCharset() { - return new String(array, 0, 0, StandardCharsets.UTF_8); + return new String(array, offset, array.length - offset, StandardCharsets.UTF_8); } - @Benchmark - public String newStringFromRangedArrayWithCharsetName() throws Exception { - return new String(array, 0, 0, StandardCharsets.UTF_8.name()); - } }