From 4a17e1a6ee172d34414aca8266d383e958d72626 Mon Sep 17 00:00:00 2001 From: redestad Date: Fri, 19 Apr 2024 16:59:41 +0200 Subject: [PATCH 01/13] Prefer ClassDesc.ofDescriptor over ClassDesc.of: the former avoids some string processing --- .../java/lang/constant/ConstantDescs.java | 66 +++++++++---------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/src/java.base/share/classes/java/lang/constant/ConstantDescs.java b/src/java.base/share/classes/java/lang/constant/ConstantDescs.java index 82f56b7cbd487..743923b3a9442 100644 --- a/src/java.base/share/classes/java/lang/constant/ConstantDescs.java +++ b/src/java.base/share/classes/java/lang/constant/ConstantDescs.java @@ -64,100 +64,100 @@ private ConstantDescs() { } // Don't change the order of these declarations! /** {@link ClassDesc} representing {@link Object} */ - public static final ClassDesc CD_Object = ClassDesc.of("java.lang.Object"); + public static final ClassDesc CD_Object = ClassDesc.ofDescriptor("Ljava/lang/Object;"); /** {@link ClassDesc} representing {@link String} */ - public static final ClassDesc CD_String = ClassDesc.of("java.lang.String"); + public static final ClassDesc CD_String = ClassDesc.ofDescriptor("Ljava/lang/String;"); /** {@link ClassDesc} representing {@link Class} */ - public static final ClassDesc CD_Class = ClassDesc.of("java.lang.Class"); + public static final ClassDesc CD_Class = ClassDesc.ofDescriptor("Ljava/lang/Class;"); /** {@link ClassDesc} representing {@link Number} */ - public static final ClassDesc CD_Number = ClassDesc.of("java.lang.Number"); + public static final ClassDesc CD_Number = ClassDesc.ofDescriptor("Ljava/lang/Number;"); /** {@link ClassDesc} representing {@link Integer} */ - public static final ClassDesc CD_Integer = ClassDesc.of("java.lang.Integer"); + public static final ClassDesc CD_Integer = ClassDesc.ofDescriptor("Ljava/lang/Integer;"); /** {@link ClassDesc} representing {@link Long} */ - public static final ClassDesc CD_Long = ClassDesc.of("java.lang.Long"); + public static final ClassDesc CD_Long = ClassDesc.ofDescriptor("Ljava/lang/Long;"); /** {@link ClassDesc} representing {@link Float} */ - public static final ClassDesc CD_Float = ClassDesc.of("java.lang.Float"); + public static final ClassDesc CD_Float = ClassDesc.ofDescriptor("Ljava/lang/Float;"); /** {@link ClassDesc} representing {@link Double} */ - public static final ClassDesc CD_Double = ClassDesc.of("java.lang.Double"); + public static final ClassDesc CD_Double = ClassDesc.ofDescriptor("Ljava/lang/Double;"); /** {@link ClassDesc} representing {@link Short} */ - public static final ClassDesc CD_Short = ClassDesc.of("java.lang.Short"); + public static final ClassDesc CD_Short = ClassDesc.ofDescriptor("Ljava/lang/Short;"); /** {@link ClassDesc} representing {@link Byte} */ - public static final ClassDesc CD_Byte = ClassDesc.of("java.lang.Byte"); + public static final ClassDesc CD_Byte = ClassDesc.ofDescriptor("Ljava/lang/Byte;"); /** {@link ClassDesc} representing {@link Character} */ - public static final ClassDesc CD_Character = ClassDesc.of("java.lang.Character"); + public static final ClassDesc CD_Character = ClassDesc.ofDescriptor("Ljava/lang/Character;"); /** {@link ClassDesc} representing {@link Boolean} */ - public static final ClassDesc CD_Boolean = ClassDesc.of("java.lang.Boolean"); + public static final ClassDesc CD_Boolean = ClassDesc.ofDescriptor("Ljava/lang/Boolean;"); /** {@link ClassDesc} representing {@link Void} */ - public static final ClassDesc CD_Void = ClassDesc.of("java.lang.Void"); + public static final ClassDesc CD_Void = ClassDesc.ofDescriptor("Ljava/lang/Void;"); /** {@link ClassDesc} representing {@link Throwable} */ - public static final ClassDesc CD_Throwable = ClassDesc.of("java.lang.Throwable"); + public static final ClassDesc CD_Throwable = ClassDesc.ofDescriptor("Ljava/lang/Throwable;"); /** {@link ClassDesc} representing {@link Exception} */ - public static final ClassDesc CD_Exception = ClassDesc.of("java.lang.Exception"); + public static final ClassDesc CD_Exception = ClassDesc.ofDescriptor("Ljava/lang/Exception;"); /** {@link ClassDesc} representing {@link Enum} */ - public static final ClassDesc CD_Enum = ClassDesc.of("java.lang.Enum"); + public static final ClassDesc CD_Enum = ClassDesc.ofDescriptor("Ljava/lang/Enum;"); /** {@link ClassDesc} representing {@link VarHandle} */ - public static final ClassDesc CD_VarHandle = ClassDesc.of("java.lang.invoke.VarHandle"); + public static final ClassDesc CD_VarHandle = ClassDesc.ofDescriptor("Ljava/lang/invoke/VarHandle;"); /** {@link ClassDesc} representing {@link MethodHandles} */ - public static final ClassDesc CD_MethodHandles = ClassDesc.of("java.lang.invoke.MethodHandles"); + public static final ClassDesc CD_MethodHandles = ClassDesc.ofDescriptor("Ljava/lang/invoke/MethodHandles;"); /** {@link ClassDesc} representing {@link MethodHandles.Lookup} */ public static final ClassDesc CD_MethodHandles_Lookup = CD_MethodHandles.nested("Lookup"); /** {@link ClassDesc} representing {@link MethodHandle} */ - public static final ClassDesc CD_MethodHandle = ClassDesc.of("java.lang.invoke.MethodHandle"); + public static final ClassDesc CD_MethodHandle = ClassDesc.ofDescriptor("Ljava/lang/invoke/MethodHandle;"); /** {@link ClassDesc} representing {@link MethodType} */ - public static final ClassDesc CD_MethodType = ClassDesc.of("java.lang.invoke.MethodType"); + public static final ClassDesc CD_MethodType = ClassDesc.ofDescriptor("Ljava/lang/invoke/MethodType;"); /** {@link ClassDesc} representing {@link CallSite} */ - public static final ClassDesc CD_CallSite = ClassDesc.of("java.lang.invoke.CallSite"); + public static final ClassDesc CD_CallSite = ClassDesc.ofDescriptor("Ljava/lang/invoke/CallSite;"); /** {@link ClassDesc} representing {@link Collection} */ - public static final ClassDesc CD_Collection = ClassDesc.of("java.util.Collection"); + public static final ClassDesc CD_Collection = ClassDesc.ofDescriptor("Ljava/util/Collection;"); /** {@link ClassDesc} representing {@link List} */ - public static final ClassDesc CD_List = ClassDesc.of("java.util.List"); + public static final ClassDesc CD_List = ClassDesc.ofDescriptor("Ljava/util/List;"); /** {@link ClassDesc} representing {@link Set} */ - public static final ClassDesc CD_Set = ClassDesc.of("java.util.Set"); + public static final ClassDesc CD_Set = ClassDesc.ofDescriptor("Ljava/util/Set;"); /** {@link ClassDesc} representing {@link Map} */ - public static final ClassDesc CD_Map = ClassDesc.of("java.util.Map"); + public static final ClassDesc CD_Map = ClassDesc.ofDescriptor("Ljava/util/Map;"); /** {@link ClassDesc} representing {@link ConstantDesc} */ - public static final ClassDesc CD_ConstantDesc = ClassDesc.of("java.lang.constant.ConstantDesc"); + public static final ClassDesc CD_ConstantDesc = ClassDesc.ofDescriptor("Ljava/lang/constant/ConstantDesc;"); /** {@link ClassDesc} representing {@link ClassDesc} */ - public static final ClassDesc CD_ClassDesc = ClassDesc.of("java.lang.constant.ClassDesc"); + public static final ClassDesc CD_ClassDesc = ClassDesc.ofDescriptor("Ljava/lang/constant/ClassDesc;"); /** {@link ClassDesc} representing {@link EnumDesc} */ public static final ClassDesc CD_EnumDesc = CD_Enum.nested("EnumDesc"); /** {@link ClassDesc} representing {@link MethodTypeDesc} */ - public static final ClassDesc CD_MethodTypeDesc = ClassDesc.of("java.lang.constant.MethodTypeDesc"); + public static final ClassDesc CD_MethodTypeDesc = ClassDesc.ofDescriptor("Ljava/lang/constant/MethodTypeDesc;"); /** {@link ClassDesc} representing {@link MethodHandleDesc} */ - public static final ClassDesc CD_MethodHandleDesc = ClassDesc.of("java.lang.constant.MethodHandleDesc"); + public static final ClassDesc CD_MethodHandleDesc = ClassDesc.ofDescriptor("Ljava/lang/constant/MethodHandleDesc;"); /** {@link ClassDesc} representing {@link DirectMethodHandleDesc} */ - public static final ClassDesc CD_DirectMethodHandleDesc = ClassDesc.of("java.lang.constant.DirectMethodHandleDesc"); + public static final ClassDesc CD_DirectMethodHandleDesc = ClassDesc.ofDescriptor("Ljava/lang/constant/DirectMethodHandleDesc;"); /** {@link ClassDesc} representing {@link VarHandleDesc} */ public static final ClassDesc CD_VarHandleDesc = CD_VarHandle.nested("VarHandleDesc"); @@ -166,13 +166,13 @@ private ConstantDescs() { } public static final ClassDesc CD_MethodHandleDesc_Kind = CD_DirectMethodHandleDesc.nested("Kind"); /** {@link ClassDesc} representing {@link DynamicConstantDesc} */ - public static final ClassDesc CD_DynamicConstantDesc = ClassDesc.of("java.lang.constant.DynamicConstantDesc"); + public static final ClassDesc CD_DynamicConstantDesc = ClassDesc.ofDescriptor("Ljava/lang/constant/DynamicConstantDesc;"); /** {@link ClassDesc} representing {@link DynamicCallSiteDesc} */ - public static final ClassDesc CD_DynamicCallSiteDesc = ClassDesc.of("java.lang.constant.DynamicCallSiteDesc"); + public static final ClassDesc CD_DynamicCallSiteDesc = ClassDesc.ofDescriptor("Ljava/lang/constant/DynamicCallSiteDesc;"); /** {@link ClassDesc} representing {@link ConstantBootstraps} */ - public static final ClassDesc CD_ConstantBootstraps = ClassDesc.of("java.lang.invoke.ConstantBootstraps"); + public static final ClassDesc CD_ConstantBootstraps = ClassDesc.ofDescriptor("Ljava/lang/invoke/ConstantBootstraps;"); private static final ClassDesc[] INDY_BOOTSTRAP_ARGS = { ConstantDescs.CD_MethodHandles_Lookup, From e1af6e0cd1c1c133a802344cc5efa6efd166f5dd Mon Sep 17 00:00:00 2001 From: redestad Date: Sun, 21 Apr 2024 00:53:14 +0200 Subject: [PATCH 02/13] Cache Class.descriptorString in a ClassValue --- .../share/classes/java/lang/Class.java | 12 ++++ .../bench/java/lang/ClassDescriptor.java | 62 +++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 test/micro/org/openjdk/bench/java/lang/ClassDescriptor.java diff --git a/src/java.base/share/classes/java/lang/Class.java b/src/java.base/share/classes/java/lang/Class.java index 4573a6dc69004..1a1452e8c264e 100644 --- a/src/java.base/share/classes/java/lang/Class.java +++ b/src/java.base/share/classes/java/lang/Class.java @@ -3423,6 +3423,14 @@ static boolean casAnnotationData(Class clazz, // Reflection data caches various derived names and reflective members. Cached // values may be invalidated when JVM TI RedefineClasses() is called private static class ReflectionData { + + private static final ClassValue descriptors = new ClassValue<>() { + @Override + protected String computeValue(java.lang.Class type) { + return type.descriptorStringImpl(); + } + }; + volatile Field[] declaredFields; volatile Field[] publicFields; volatile Method[] declaredMethods; @@ -4635,6 +4643,10 @@ public Class[] getNestMembers() { */ @Override public String descriptorString() { + return ReflectionData.descriptors.get(this); + } + + private String descriptorStringImpl() { if (isPrimitive()) return Wrapper.forPrimitiveType(this).basicTypeString(); diff --git a/test/micro/org/openjdk/bench/java/lang/ClassDescriptor.java b/test/micro/org/openjdk/bench/java/lang/ClassDescriptor.java new file mode 100644 index 0000000000000..6deca854bea9c --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/ClassDescriptor.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2014, 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.lang; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +import java.util.concurrent.TimeUnit; + +/** + * Tests java.lang.Class.descriptorString() with various inputs. + */ +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +@Warmup(iterations = 5, time = 1) +@Measurement(iterations = 5, time = 1) +@Fork(3) +public class ClassDescriptor { + + @Benchmark + public void descriptorStringMix(Blackhole bh) throws ClassNotFoundException { + bh.consume(A.class.descriptorString()); + bh.consume(B.class.descriptorString()); + bh.consume(C.class.descriptorString()); + bh.consume(String.class.descriptorString()); + bh.consume(Object.class.descriptorString()); + } + + static class A {} + static class B {} + static class C {} +} From 02fbcb86599f113a973c15d2cdc6b1c3603e538a Mon Sep 17 00:00:00 2001 From: redestad Date: Sun, 21 Apr 2024 13:31:49 +0200 Subject: [PATCH 03/13] Reduce overhead of ObjectMethods:: --- .../java/lang/runtime/ObjectMethods.java | 214 +++++++++--------- 1 file changed, 103 insertions(+), 111 deletions(-) diff --git a/src/java.base/share/classes/java/lang/runtime/ObjectMethods.java b/src/java.base/share/classes/java/lang/runtime/ObjectMethods.java index 6cfd7f9bb44fe..a654ae594fb9e 100644 --- a/src/java.base/share/classes/java/lang/runtime/ObjectMethods.java +++ b/src/java.base/share/classes/java/lang/runtime/ObjectMethods.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 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 @@ -25,20 +25,20 @@ package java.lang.runtime; +import jdk.internal.vm.annotation.Stable; + import java.lang.invoke.ConstantCallSite; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.lang.invoke.StringConcatFactory; import java.lang.invoke.TypeDescriptor; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Objects; +import static java.lang.invoke.MethodType.methodType; import static java.util.Objects.requireNonNull; /** @@ -56,20 +56,19 @@ private ObjectMethods() { } private static final int MAX_STRING_CONCAT_SLOTS = 20; - private static final MethodType DESCRIPTOR_MT = MethodType.methodType(MethodType.class); - private static final MethodType NAMES_MT = MethodType.methodType(List.class); - private static final MethodHandle FALSE = MethodHandles.constant(boolean.class, false); - private static final MethodHandle TRUE = MethodHandles.constant(boolean.class, true); - private static final MethodHandle ZERO = MethodHandles.constant(int.class, 0); + private @Stable static MethodHandle TRUE; + private static MethodHandle trueConstant() { + MethodHandle mh = TRUE; + if (mh == null) { + TRUE = mh = MethodHandles.constant(boolean.class, true); + } + return mh; + } + private static final MethodHandle CLASS_IS_INSTANCE; - private static final MethodHandle OBJECT_EQUALS; private static final MethodHandle OBJECTS_EQUALS; private static final MethodHandle OBJECTS_HASHCODE; - private static final MethodHandle OBJECTS_TOSTRING; private static final MethodHandle OBJECT_EQ; - private static final MethodHandle OBJECT_HASHCODE; - private static final MethodHandle OBJECT_TO_STRING; - private static final MethodHandle STRING_FORMAT; private static final MethodHandle HASH_COMBINER; private static final HashMap, MethodHandle> primitiveEquals = new HashMap<>(); @@ -82,83 +81,77 @@ private ObjectMethods() { } MethodHandles.Lookup publicLookup = MethodHandles.publicLookup(); MethodHandles.Lookup lookup = MethodHandles.lookup(); - @SuppressWarnings("removal") - ClassLoader loader = AccessController.doPrivileged(new PrivilegedAction() { - @Override public ClassLoader run() { return ClassLoader.getPlatformClassLoader(); } - }); + Class B = byte.class; + Class C = char.class; + Class I = int.class; + Class J = long.class; + Class S = short.class; + Class F = float.class; + Class D = double.class; + Class Z = boolean.class; CLASS_IS_INSTANCE = publicLookup.findVirtual(Class.class, "isInstance", - MethodType.methodType(boolean.class, Object.class)); - OBJECT_EQUALS = publicLookup.findVirtual(Object.class, "equals", - MethodType.methodType(boolean.class, Object.class)); - OBJECT_HASHCODE = publicLookup.findVirtual(Object.class, "hashCode", - MethodType.fromMethodDescriptorString("()I", loader)); - OBJECT_TO_STRING = publicLookup.findVirtual(Object.class, "toString", - MethodType.methodType(String.class)); - STRING_FORMAT = publicLookup.findStatic(String.class, "format", - MethodType.methodType(String.class, String.class, Object[].class)); + methodType(Z, Object.class)); OBJECTS_EQUALS = publicLookup.findStatic(Objects.class, "equals", - MethodType.methodType(boolean.class, Object.class, Object.class)); + methodType(Z, Object.class, Object.class)); OBJECTS_HASHCODE = publicLookup.findStatic(Objects.class, "hashCode", - MethodType.methodType(int.class, Object.class)); - OBJECTS_TOSTRING = publicLookup.findStatic(Objects.class, "toString", - MethodType.methodType(String.class, Object.class)); + methodType(I, Object.class)); OBJECT_EQ = lookup.findStatic(OBJECT_METHODS_CLASS, "eq", - MethodType.methodType(boolean.class, Object.class, Object.class)); + methodType(Z, Object.class, Object.class)); HASH_COMBINER = lookup.findStatic(OBJECT_METHODS_CLASS, "hashCombiner", - MethodType.fromMethodDescriptorString("(II)I", loader)); - - primitiveEquals.put(byte.class, lookup.findStatic(OBJECT_METHODS_CLASS, "eq", - MethodType.fromMethodDescriptorString("(BB)Z", loader))); - primitiveEquals.put(short.class, lookup.findStatic(OBJECT_METHODS_CLASS, "eq", - MethodType.fromMethodDescriptorString("(SS)Z", loader))); - primitiveEquals.put(char.class, lookup.findStatic(OBJECT_METHODS_CLASS, "eq", - MethodType.fromMethodDescriptorString("(CC)Z", loader))); - primitiveEquals.put(int.class, lookup.findStatic(OBJECT_METHODS_CLASS, "eq", - MethodType.fromMethodDescriptorString("(II)Z", loader))); - primitiveEquals.put(long.class, lookup.findStatic(OBJECT_METHODS_CLASS, "eq", - MethodType.fromMethodDescriptorString("(JJ)Z", loader))); - primitiveEquals.put(float.class, lookup.findStatic(OBJECT_METHODS_CLASS, "eq", - MethodType.fromMethodDescriptorString("(FF)Z", loader))); - primitiveEquals.put(double.class, lookup.findStatic(OBJECT_METHODS_CLASS, "eq", - MethodType.fromMethodDescriptorString("(DD)Z", loader))); - primitiveEquals.put(boolean.class, lookup.findStatic(OBJECT_METHODS_CLASS, "eq", - MethodType.fromMethodDescriptorString("(ZZ)Z", loader))); - - primitiveHashers.put(byte.class, lookup.findStatic(Byte.class, "hashCode", - MethodType.fromMethodDescriptorString("(B)I", loader))); - primitiveHashers.put(short.class, lookup.findStatic(Short.class, "hashCode", - MethodType.fromMethodDescriptorString("(S)I", loader))); - primitiveHashers.put(char.class, lookup.findStatic(Character.class, "hashCode", - MethodType.fromMethodDescriptorString("(C)I", loader))); - primitiveHashers.put(int.class, lookup.findStatic(Integer.class, "hashCode", - MethodType.fromMethodDescriptorString("(I)I", loader))); - primitiveHashers.put(long.class, lookup.findStatic(Long.class, "hashCode", - MethodType.fromMethodDescriptorString("(J)I", loader))); - primitiveHashers.put(float.class, lookup.findStatic(Float.class, "hashCode", - MethodType.fromMethodDescriptorString("(F)I", loader))); - primitiveHashers.put(double.class, lookup.findStatic(Double.class, "hashCode", - MethodType.fromMethodDescriptorString("(D)I", loader))); - primitiveHashers.put(boolean.class, lookup.findStatic(Boolean.class, "hashCode", - MethodType.fromMethodDescriptorString("(Z)I", loader))); - - primitiveToString.put(byte.class, lookup.findStatic(Byte.class, "toString", - MethodType.methodType(String.class, byte.class))); - primitiveToString.put(short.class, lookup.findStatic(Short.class, "toString", - MethodType.methodType(String.class, short.class))); - primitiveToString.put(char.class, lookup.findStatic(Character.class, "toString", - MethodType.methodType(String.class, char.class))); - primitiveToString.put(int.class, lookup.findStatic(Integer.class, "toString", - MethodType.methodType(String.class, int.class))); - primitiveToString.put(long.class, lookup.findStatic(Long.class, "toString", - MethodType.methodType(String.class, long.class))); - primitiveToString.put(float.class, lookup.findStatic(Float.class, "toString", - MethodType.methodType(String.class, float.class))); - primitiveToString.put(double.class, lookup.findStatic(Double.class, "toString", - MethodType.methodType(String.class, double.class))); - primitiveToString.put(boolean.class, lookup.findStatic(Boolean.class, "toString", - MethodType.methodType(String.class, boolean.class))); + methodType(I, I, I)); + + primitiveEquals.put(B, lookup.findStatic(OBJECT_METHODS_CLASS, "eq", + methodType(Z, B, B))); + primitiveEquals.put(S, lookup.findStatic(OBJECT_METHODS_CLASS, "eq", + methodType(Z, S, S))); + primitiveEquals.put(C, lookup.findStatic(OBJECT_METHODS_CLASS, "eq", + methodType(Z, C, C))); + primitiveEquals.put(I, lookup.findStatic(OBJECT_METHODS_CLASS, "eq", + methodType(Z, I, I))); + primitiveEquals.put(J, lookup.findStatic(OBJECT_METHODS_CLASS, "eq", + methodType(Z, J, J))); + primitiveEquals.put(F, lookup.findStatic(OBJECT_METHODS_CLASS, "eq", + methodType(Z, F, F))); + primitiveEquals.put(D, lookup.findStatic(OBJECT_METHODS_CLASS, "eq", + methodType(Z, D, D))); + primitiveEquals.put(Z, lookup.findStatic(OBJECT_METHODS_CLASS, "eq", + methodType(Z, Z, Z))); + + primitiveHashers.put(B, lookup.findStatic(Byte.class, "hashCode", + methodType(I, B))); + primitiveHashers.put(S, lookup.findStatic(Short.class, "hashCode", + methodType(I, S))); + primitiveHashers.put(C, lookup.findStatic(Character.class, "hashCode", + methodType(I, C))); + primitiveHashers.put(I, lookup.findStatic(Integer.class, "hashCode", + methodType(I, I))); + primitiveHashers.put(J, lookup.findStatic(Long.class, "hashCode", + methodType(I, J))); + primitiveHashers.put(F, lookup.findStatic(Float.class, "hashCode", + methodType(I, F))); + primitiveHashers.put(D, lookup.findStatic(Double.class, "hashCode", + methodType(I, D))); + primitiveHashers.put(Z, lookup.findStatic(Boolean.class, "hashCode", + methodType(I, Z))); + + primitiveToString.put(B, lookup.findStatic(Byte.class, "toString", + methodType(String.class, B))); + primitiveToString.put(S, lookup.findStatic(Short.class, "toString", + methodType(String.class, S))); + primitiveToString.put(C, lookup.findStatic(Character.class, "toString", + methodType(String.class, C))); + primitiveToString.put(I, lookup.findStatic(Integer.class, "toString", + methodType(String.class, I))); + primitiveToString.put(J, lookup.findStatic(Long.class, "toString", + methodType(String.class, J))); + primitiveToString.put(F, lookup.findStatic(Float.class, "toString", + methodType(String.class, F))); + primitiveToString.put(D, lookup.findStatic(Double.class, "toString", + methodType(String.class, D))); + primitiveToString.put(Z, lookup.findStatic(Boolean.class, "toString", + methodType(String.class, Z))); } catch (ReflectiveOperationException e) { throw new RuntimeException(e); @@ -183,21 +176,14 @@ private static int hashCombiner(int x, int y) { private static MethodHandle equalator(Class clazz) { return (clazz.isPrimitive() ? primitiveEquals.get(clazz) - : OBJECTS_EQUALS.asType(MethodType.methodType(boolean.class, clazz, clazz))); + : OBJECTS_EQUALS.asType(methodType(boolean.class, clazz, clazz))); } /** Get the hasher for a value of a given type */ private static MethodHandle hasher(Class clazz) { return (clazz.isPrimitive() ? primitiveHashers.get(clazz) - : OBJECTS_HASHCODE.asType(MethodType.methodType(int.class, clazz))); - } - - /** Get the stringifier for a value of a given type */ - private static MethodHandle stringifier(Class clazz) { - return (clazz.isPrimitive() - ? primitiveToString.get(clazz) - : OBJECTS_TOSTRING.asType(MethodType.methodType(String.class, clazz))); + : OBJECTS_HASHCODE.asType(methodType(int.class, clazz))); } /** @@ -208,13 +194,13 @@ private static MethodHandle stringifier(Class clazz) { */ private static MethodHandle makeEquals(Class receiverClass, List getters) { - MethodType rr = MethodType.methodType(boolean.class, receiverClass, receiverClass); - MethodType ro = MethodType.methodType(boolean.class, receiverClass, Object.class); - MethodHandle instanceFalse = MethodHandles.dropArguments(FALSE, 0, receiverClass, Object.class); // (RO)Z - MethodHandle instanceTrue = MethodHandles.dropArguments(TRUE, 0, receiverClass, Object.class); // (RO)Z + MethodType rr = methodType(boolean.class, receiverClass, receiverClass); + MethodType ro = methodType(boolean.class, receiverClass, Object.class); + MethodHandle instanceFalse = MethodHandles.dropArguments(MethodHandles.zero(boolean.class), 0, receiverClass, Object.class); // (RO)Z + MethodHandle instanceTrue = MethodHandles.dropArguments(trueConstant(), 0, receiverClass, Object.class); // (RO)Z MethodHandle isSameObject = OBJECT_EQ.asType(ro); // (RO)Z MethodHandle isInstance = MethodHandles.dropArguments(CLASS_IS_INSTANCE.bindTo(receiverClass), 0, receiverClass); // (RO)Z - MethodHandle accumulator = MethodHandles.dropArguments(TRUE, 0, receiverClass, receiverClass); // (RR)Z + MethodHandle accumulator = MethodHandles.dropArguments(trueConstant(), 0, receiverClass, receiverClass); // (RR)Z for (MethodHandle getter : getters) { MethodHandle equalator = equalator(getter.type().returnType()); // (TT)Z @@ -235,7 +221,7 @@ private static MethodHandle makeEquals(Class receiverClass, */ private static MethodHandle makeHashCode(Class receiverClass, List getters) { - MethodHandle accumulator = MethodHandles.dropArguments(ZERO, 0, receiverClass); // (R)I + MethodHandle accumulator = MethodHandles.dropArguments(MethodHandles.zero(int.class), 0, receiverClass); // (R)I // @@@ Use loop combinator instead? for (MethodHandle getter : getters) { @@ -281,19 +267,23 @@ private static MethodHandle makeToString(MethodHandles.Lookup lookup, splits = split(toSplit); mhs = new MethodHandle[splits.size()]; for (int splitIndex = 0; splitIndex < splits.size(); splitIndex++) { - String recipe = ""; + StringBuilder recipe = new StringBuilder(); if (firstTime && splitIndex == 0) { - recipe = receiverClass.getSimpleName() + "["; + recipe = new StringBuilder(receiverClass.getSimpleName() + "["); } for (int i = 0; i < splits.get(splitIndex).size(); i++) { - recipe += firstTime ? names.get(namesIndex) + "=" + "\1" : "\1"; + if (firstTime) { + recipe.append(names.get(namesIndex)).append("=\1"); + } else { + recipe.append('\1'); + } if (firstTime && namesIndex != names.size() - 1) { - recipe += ", "; + recipe.append(", "); } namesIndex++; } if (firstTime && splitIndex == splits.size() - 1) { - recipe += "]"; + recipe.append("]"); } Class[] concatTypeArgs = new Class[splits.get(splitIndex).size()]; // special case: no need to create another getters if there is only one split @@ -302,19 +292,19 @@ private static MethodHandle makeToString(MethodHandles.Lookup lookup, concatTypeArgs[j] = splits.get(splitIndex).get(j).type().returnType(); currentSplitGetters[j] = splits.get(splitIndex).get(j); } - MethodType concatMT = MethodType.methodType(String.class, concatTypeArgs); + MethodType concatMT = methodType(String.class, concatTypeArgs); try { mhs[splitIndex] = StringConcatFactory.makeConcatWithConstants( lookup, "", concatMT, - recipe, + recipe.toString(), new Object[0] ).getTarget(); mhs[splitIndex] = MethodHandles.filterArguments(mhs[splitIndex], 0, currentSplitGetters); // this will spread the receiver class across all the getters mhs[splitIndex] = MethodHandles.permuteArguments( mhs[splitIndex], - MethodType.methodType(String.class, receiverClass), + methodType(String.class, receiverClass), new int[splits.get(splitIndex).size()] ); } catch (Throwable t) { @@ -410,7 +400,9 @@ public static Object bootstrap(MethodHandles.Lookup lookup, String methodName, T requireNonNull(recordClass); requireNonNull(names); requireNonNull(getters); - Arrays.stream(getters).forEach(Objects::requireNonNull); + for (MethodHandle getter : getters) { + requireNonNull(getter); + } MethodType methodType; if (type instanceof MethodType mt) methodType = mt; @@ -422,17 +414,17 @@ public static Object bootstrap(MethodHandles.Lookup lookup, String methodName, T List getterList = List.of(getters); MethodHandle handle = switch (methodName) { case "equals" -> { - if (methodType != null && !methodType.equals(MethodType.methodType(boolean.class, recordClass, Object.class))) + if (methodType != null && !methodType.equals(methodType(boolean.class, recordClass, Object.class))) throw new IllegalArgumentException("Bad method type: " + methodType); yield makeEquals(recordClass, getterList); } case "hashCode" -> { - if (methodType != null && !methodType.equals(MethodType.methodType(int.class, recordClass))) + if (methodType != null && !methodType.equals(methodType(int.class, recordClass))) throw new IllegalArgumentException("Bad method type: " + methodType); yield makeHashCode(recordClass, getterList); } case "toString" -> { - if (methodType != null && !methodType.equals(MethodType.methodType(String.class, recordClass))) + if (methodType != null && !methodType.equals(methodType(String.class, recordClass))) throw new IllegalArgumentException("Bad method type: " + methodType); List nameList = "".equals(names) ? List.of() : List.of(names.split(";")); if (nameList.size() != getterList.size()) From a7b6ad14c1e7154c701f05810577dbe83a9b23cb Mon Sep 17 00:00:00 2001 From: redestad Date: Sun, 21 Apr 2024 20:58:31 +0200 Subject: [PATCH 04/13] charAt(0) instead of startsWith (ClassDesc constructors validate that descriptorString is non-empty) --- src/java.base/share/classes/java/lang/constant/ClassDesc.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/java/lang/constant/ClassDesc.java b/src/java.base/share/classes/java/lang/constant/ClassDesc.java index 60adc7f1ab1f0..f8b111c4c35e6 100644 --- a/src/java.base/share/classes/java/lang/constant/ClassDesc.java +++ b/src/java.base/share/classes/java/lang/constant/ClassDesc.java @@ -279,7 +279,7 @@ default ClassDesc nested(String firstNestedName, String... moreNestedNames) { * @return whether this {@linkplain ClassDesc} describes an array type */ default boolean isArray() { - return descriptorString().startsWith("["); + return descriptorString().charAt(0) == '['; } /** @@ -297,7 +297,7 @@ default boolean isPrimitive() { * @return whether this {@linkplain ClassDesc} describes a class or interface type */ default boolean isClassOrInterface() { - return descriptorString().startsWith("L"); + return descriptorString().charAt(0) == 'L'; } /** From cf0a09bd165ddcb8158feb9d6201c1727abca02a Mon Sep 17 00:00:00 2001 From: redestad Date: Tue, 23 Apr 2024 11:03:11 +0200 Subject: [PATCH 05/13] Optimize ClassDesc.ofDescriptor for primitive types, MethodTypeDescImpl.ofDescriptor more generally --- .../classes/java/lang/constant/ClassDesc.java | 2 +- .../java/lang/constant/ConstantDescs.java | 18 ++++----- .../lang/constant/MethodTypeDescImpl.java | 39 ++++++++++++++++--- .../classes/sun/invoke/util/Wrapper.java | 31 +++++++++------ .../bench/java/lang/ClassDescriptor.java | 6 +++ 5 files changed, 68 insertions(+), 28 deletions(-) diff --git a/src/java.base/share/classes/java/lang/constant/ClassDesc.java b/src/java.base/share/classes/java/lang/constant/ClassDesc.java index f8b111c4c35e6..dea0051163106 100644 --- a/src/java.base/share/classes/java/lang/constant/ClassDesc.java +++ b/src/java.base/share/classes/java/lang/constant/ClassDesc.java @@ -170,7 +170,7 @@ static ClassDesc ofDescriptor(String descriptor) { ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS + " dimensions"); } return (descriptor.length() == 1) - ? new PrimitiveClassDescImpl(descriptor) + ? Wrapper.forBasicType(descriptor.charAt(0)).primitiveClassDescriptor() : new ReferenceClassDescImpl(descriptor); } diff --git a/src/java.base/share/classes/java/lang/constant/ConstantDescs.java b/src/java.base/share/classes/java/lang/constant/ConstantDescs.java index 743923b3a9442..70bd01d734b5a 100644 --- a/src/java.base/share/classes/java/lang/constant/ConstantDescs.java +++ b/src/java.base/share/classes/java/lang/constant/ConstantDescs.java @@ -236,31 +236,31 @@ private ConstantDescs() { } CD_Object, CD_Object); /** {@link ClassDesc} representing the primitive type {@code int} */ - public static final ClassDesc CD_int = ClassDesc.ofDescriptor("I"); + public static final ClassDesc CD_int = new PrimitiveClassDescImpl("I"); /** {@link ClassDesc} representing the primitive type {@code long} */ - public static final ClassDesc CD_long = ClassDesc.ofDescriptor("J"); + public static final ClassDesc CD_long = new PrimitiveClassDescImpl("J"); /** {@link ClassDesc} representing the primitive type {@code float} */ - public static final ClassDesc CD_float = ClassDesc.ofDescriptor("F"); + public static final ClassDesc CD_float = new PrimitiveClassDescImpl("F"); /** {@link ClassDesc} representing the primitive type {@code double} */ - public static final ClassDesc CD_double = ClassDesc.ofDescriptor("D"); + public static final ClassDesc CD_double = new PrimitiveClassDescImpl("D"); /** {@link ClassDesc} representing the primitive type {@code short} */ - public static final ClassDesc CD_short = ClassDesc.ofDescriptor("S"); + public static final ClassDesc CD_short = new PrimitiveClassDescImpl("S"); /** {@link ClassDesc} representing the primitive type {@code byte} */ - public static final ClassDesc CD_byte = ClassDesc.ofDescriptor("B"); + public static final ClassDesc CD_byte = new PrimitiveClassDescImpl("B"); /** {@link ClassDesc} representing the primitive type {@code char} */ - public static final ClassDesc CD_char = ClassDesc.ofDescriptor("C"); + public static final ClassDesc CD_char = new PrimitiveClassDescImpl("C"); /** {@link ClassDesc} representing the primitive type {@code boolean} */ - public static final ClassDesc CD_boolean = ClassDesc.ofDescriptor("Z"); + public static final ClassDesc CD_boolean = new PrimitiveClassDescImpl("Z"); /** {@link ClassDesc} representing the primitive type {@code void} */ - public static final ClassDesc CD_void = ClassDesc.ofDescriptor("V"); + public static final ClassDesc CD_void = new PrimitiveClassDescImpl("V"); /** * {@link MethodHandleDesc} representing {@link MethodHandles#classData(Lookup, String, Class) MethodHandles.classData} diff --git a/src/java.base/share/classes/java/lang/constant/MethodTypeDescImpl.java b/src/java.base/share/classes/java/lang/constant/MethodTypeDescImpl.java index c50cf7c58f0a6..4ab4a56ae6765 100644 --- a/src/java.base/share/classes/java/lang/constant/MethodTypeDescImpl.java +++ b/src/java.base/share/classes/java/lang/constant/MethodTypeDescImpl.java @@ -25,11 +25,13 @@ package java.lang.constant; import jdk.internal.vm.annotation.Stable; +import sun.invoke.util.Wrapper; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.security.AccessController; import java.security.PrivilegedAction; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; @@ -90,19 +92,44 @@ static MethodTypeDescImpl ofTrusted(ClassDesc returnType, ClassDesc[] trustedArg static MethodTypeDescImpl ofDescriptor(String descriptor) { requireNonNull(descriptor); - List types = ConstantUtils.parseMethodDescriptor(descriptor); + int cur = 0, end = descriptor.length(); + ArrayList ptypes = new ArrayList<>(); - int paramCount = types.size() - 1; - var paramTypes = paramCount > 0 ? new ClassDesc[paramCount] : ConstantUtils.EMPTY_CLASSDESC; - for (int i = 0; i < paramCount; i++) { - paramTypes[i] = ClassDesc.ofDescriptor(types.get(i + 1)); + if (cur >= end || descriptor.charAt(cur) != '(') + throw new IllegalArgumentException("Bad method descriptor: " + descriptor); + + ++cur; // skip '(' + while (cur < end && descriptor.charAt(cur) != ')') { + int len = ConstantUtils.skipOverFieldSignature(descriptor, cur, end, false); + if (len == 0) + throw new IllegalArgumentException("Bad method descriptor: " + descriptor); + + ptypes.add(resolveClassDesc(descriptor, cur, len)); + cur += len; } + if (cur >= end) + throw new IllegalArgumentException("Bad method descriptor: " + descriptor); + ++cur; // skip ')' + + int rLen = ConstantUtils.skipOverFieldSignature(descriptor, cur, end, true); + if (rLen == 0 || cur + rLen != end) + throw new IllegalArgumentException("Bad method descriptor: " + descriptor); + ClassDesc returnType = resolveClassDesc(descriptor, cur, rLen); + + var paramTypes = !ptypes.isEmpty() ? ptypes.toArray(new ClassDesc[0]) : ConstantUtils.EMPTY_CLASSDESC; - MethodTypeDescImpl result = ofTrusted(ClassDesc.ofDescriptor(types.getFirst()), paramTypes); + MethodTypeDescImpl result = ofTrusted(returnType, paramTypes); result.cachedDescriptorString = descriptor; return result; } + private static ClassDesc resolveClassDesc(String descriptor, int start, int len) { + if (len == 1) { + return Wrapper.forBasicType(descriptor.charAt(start)).primitiveClassDescriptor(); + } + return ClassDesc.ofDescriptor(descriptor.substring(start, start + len)); + } + @Override public ClassDesc returnType() { return returnType; diff --git a/src/java.base/share/classes/sun/invoke/util/Wrapper.java b/src/java.base/share/classes/sun/invoke/util/Wrapper.java index 76aede094872c..c646c9399a26e 100644 --- a/src/java.base/share/classes/sun/invoke/util/Wrapper.java +++ b/src/java.base/share/classes/sun/invoke/util/Wrapper.java @@ -25,25 +25,27 @@ package sun.invoke.util; -import java.util.Map; import static sun.invoke.util.Wrapper.NumericClasses.*; import jdk.internal.vm.annotation.DontInline; +import java.lang.constant.ClassDesc; +import java.lang.constant.ConstantDescs; + public enum Wrapper { // wrapperType simple primitiveType simple char emptyArray format numericClass superClass - BOOLEAN( Boolean.class, "Boolean", boolean.class, "boolean", 'Z', new boolean[0], Format.unsigned( 1), 0, 0), + BOOLEAN( Boolean.class, "Boolean", boolean.class, "boolean", 'Z', new boolean[0], Format.unsigned( 1), 0, 0, ConstantDescs.CD_boolean), // These must be in the order defined for widening primitive conversions in JLS 5.1.2 // Avoid boxing integral types here to defer initialization of internal caches - BYTE ( Byte.class, "Byte", byte.class, "byte", 'B', new byte[0], Format.signed( 8), BYTE_CLASS, BYTE_SUPERCLASSES), - SHORT ( Short.class, "Short", short.class, "short", 'S', new short[0], Format.signed( 16), SHORT_CLASS, SHORT_SUPERCLASSES), - CHAR (Character.class, "Character", char.class, "char", 'C', new char[0], Format.unsigned(16), CHAR_CLASS, CHAR_SUPERCLASSES), - INT ( Integer.class, "Integer", int.class, "int", 'I', new int[0], Format.signed( 32), INT_CLASS, INT_SUPERCLASSES), - LONG ( Long.class, "Long", long.class, "long", 'J', new long[0], Format.signed( 64), LONG_CLASS, LONG_SUPERCLASSES), - FLOAT ( Float.class, "Float", float.class, "float", 'F', new float[0], Format.floating(32), FLOAT_CLASS, FLOAT_SUPERCLASSES), - DOUBLE ( Double.class, "Double", double.class, "double", 'D', new double[0], Format.floating(64), DOUBLE_CLASS, DOUBLE_CLASS), - OBJECT ( Object.class, "Object", Object.class, "Object", 'L', new Object[0], Format.other( 1), 0, 0), + BYTE ( Byte.class, "Byte", byte.class, "byte", 'B', new byte[0], Format.signed( 8), BYTE_CLASS, BYTE_SUPERCLASSES, ConstantDescs.CD_byte), + SHORT ( Short.class, "Short", short.class, "short", 'S', new short[0], Format.signed( 16), SHORT_CLASS, SHORT_SUPERCLASSES, ConstantDescs.CD_short), + CHAR (Character.class, "Character", char.class, "char", 'C', new char[0], Format.unsigned(16), CHAR_CLASS, CHAR_SUPERCLASSES, ConstantDescs.CD_char), + INT ( Integer.class, "Integer", int.class, "int", 'I', new int[0], Format.signed( 32), INT_CLASS, INT_SUPERCLASSES, ConstantDescs.CD_int), + LONG ( Long.class, "Long", long.class, "long", 'J', new long[0], Format.signed( 64), LONG_CLASS, LONG_SUPERCLASSES, ConstantDescs.CD_long), + FLOAT ( Float.class, "Float", float.class, "float", 'F', new float[0], Format.floating(32), FLOAT_CLASS, FLOAT_SUPERCLASSES, ConstantDescs.CD_float), + DOUBLE ( Double.class, "Double", double.class, "double", 'D', new double[0], Format.floating(64), DOUBLE_CLASS, DOUBLE_CLASS, ConstantDescs.CD_double), + OBJECT ( Object.class, "Object", Object.class, "Object", 'L', new Object[0], Format.other( 1), 0, 0, ConstantDescs.CD_Object), // VOID must be the last type, since it is "assignable" from any other type: - VOID ( Void.class, "Void", void.class, "void", 'V', null, Format.other( 0), 0, 0), + VOID ( Void.class, "Void", void.class, "void", 'V', null, Format.other( 0), 0, 0, ConstantDescs.CD_void), ; public static final int COUNT = 10; @@ -58,8 +60,9 @@ public enum Wrapper { private final int superClasses; private final String wrapperSimpleName; private final String primitiveSimpleName; + private final ClassDesc primitiveTypeDesc; - private Wrapper(Class wtype, String wtypeName, Class ptype, String ptypeName, char tchar, Object emptyArray, int format, int numericClass, int superClasses) { + private Wrapper(Class wtype, String wtypeName, Class ptype, String ptypeName, char tchar, Object emptyArray, int format, int numericClass, int superClasses, ClassDesc primitiveTypeDesc) { this.wrapperType = wtype; this.primitiveType = ptype; this.basicTypeChar = tchar; @@ -70,6 +73,7 @@ private Wrapper(Class wtype, String wtypeName, Class ptype, String ptypeNa this.superClasses = superClasses; this.wrapperSimpleName = wtypeName; this.primitiveSimpleName = ptypeName; + this.primitiveTypeDesc = primitiveTypeDesc; } /** For debugging, give the details of this wrapper. */ @@ -376,6 +380,9 @@ public static Wrapper forBasicType(Class type) { } } + /** A nominal descriptor of the primitive type */ + public ClassDesc primitiveClassDescriptor() { return primitiveTypeDesc; } + /** What is the primitive type wrapped by this wrapper? */ public Class primitiveType() { return primitiveType; } diff --git a/test/micro/org/openjdk/bench/java/lang/ClassDescriptor.java b/test/micro/org/openjdk/bench/java/lang/ClassDescriptor.java index 6deca854bea9c..df58fc025e4f8 100644 --- a/test/micro/org/openjdk/bench/java/lang/ClassDescriptor.java +++ b/test/micro/org/openjdk/bench/java/lang/ClassDescriptor.java @@ -35,6 +35,7 @@ import org.openjdk.jmh.infra.Blackhole; import java.util.concurrent.TimeUnit; +import java.lang.constant.ClassDesc; /** * Tests java.lang.Class.descriptorString() with various inputs. @@ -56,6 +57,11 @@ public void descriptorStringMix(Blackhole bh) throws ClassNotFoundException { bh.consume(Object.class.descriptorString()); } + @Benchmark + public ClassDesc ofDescriptorPrimitive() { + return ClassDesc.ofDescriptor("I"); + } + static class A {} static class B {} static class C {} From 4a150d53dfa1a39d512bf2a22674a43b5fd2a8cb Mon Sep 17 00:00:00 2001 From: redestad Date: Tue, 23 Apr 2024 11:24:57 +0200 Subject: [PATCH 06/13] Remove cloning empty bootstrapArgs --- .../share/classes/java/lang/constant/DynamicConstantDesc.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java.base/share/classes/java/lang/constant/DynamicConstantDesc.java b/src/java.base/share/classes/java/lang/constant/DynamicConstantDesc.java index bf6ae2670b159..2d951c2d5fb6d 100644 --- a/src/java.base/share/classes/java/lang/constant/DynamicConstantDesc.java +++ b/src/java.base/share/classes/java/lang/constant/DynamicConstantDesc.java @@ -89,7 +89,7 @@ protected DynamicConstantDesc(DirectMethodHandleDesc bootstrapMethod, this.bootstrapMethod = requireNonNull(bootstrapMethod); this.constantName = validateMemberName(requireNonNull(constantName), true); this.constantType = requireNonNull(constantType); - this.bootstrapArgs = requireNonNull(bootstrapArgs).clone(); + this.bootstrapArgs = bootstrapArgs.length == 0 ? EMPTY_CONSTANTDESC : bootstrapArgs.clone(); if (constantName.length() == 0) throw new IllegalArgumentException("Illegal invocation name: " + constantName); From 8239931f7b90dff8a256c3e3fb3ffab0552fa843 Mon Sep 17 00:00:00 2001 From: redestad Date: Tue, 23 Apr 2024 15:08:14 +0200 Subject: [PATCH 07/13] Further reduce overhead of ConstantDescs. --- .../java/lang/constant/ConstantDescs.java | 86 +++++++++---------- .../java/lang/constant/ConstantUtils.java | 1 - .../java/lang/constant/MethodHandleDesc.java | 9 +- 3 files changed, 47 insertions(+), 49 deletions(-) diff --git a/src/java.base/share/classes/java/lang/constant/ConstantDescs.java b/src/java.base/share/classes/java/lang/constant/ConstantDescs.java index 70bd01d734b5a..211d2d73769b0 100644 --- a/src/java.base/share/classes/java/lang/constant/ConstantDescs.java +++ b/src/java.base/share/classes/java/lang/constant/ConstantDescs.java @@ -64,125 +64,125 @@ private ConstantDescs() { } // Don't change the order of these declarations! /** {@link ClassDesc} representing {@link Object} */ - public static final ClassDesc CD_Object = ClassDesc.ofDescriptor("Ljava/lang/Object;"); + public static final ClassDesc CD_Object = new ReferenceClassDescImpl("Ljava/lang/Object;"); /** {@link ClassDesc} representing {@link String} */ - public static final ClassDesc CD_String = ClassDesc.ofDescriptor("Ljava/lang/String;"); + public static final ClassDesc CD_String = new ReferenceClassDescImpl("Ljava/lang/String;"); /** {@link ClassDesc} representing {@link Class} */ - public static final ClassDesc CD_Class = ClassDesc.ofDescriptor("Ljava/lang/Class;"); + public static final ClassDesc CD_Class = new ReferenceClassDescImpl("Ljava/lang/Class;"); /** {@link ClassDesc} representing {@link Number} */ - public static final ClassDesc CD_Number = ClassDesc.ofDescriptor("Ljava/lang/Number;"); + public static final ClassDesc CD_Number = new ReferenceClassDescImpl("Ljava/lang/Number;"); /** {@link ClassDesc} representing {@link Integer} */ - public static final ClassDesc CD_Integer = ClassDesc.ofDescriptor("Ljava/lang/Integer;"); + public static final ClassDesc CD_Integer = new ReferenceClassDescImpl("Ljava/lang/Integer;"); /** {@link ClassDesc} representing {@link Long} */ - public static final ClassDesc CD_Long = ClassDesc.ofDescriptor("Ljava/lang/Long;"); + public static final ClassDesc CD_Long = new ReferenceClassDescImpl("Ljava/lang/Long;"); /** {@link ClassDesc} representing {@link Float} */ - public static final ClassDesc CD_Float = ClassDesc.ofDescriptor("Ljava/lang/Float;"); + public static final ClassDesc CD_Float = new ReferenceClassDescImpl("Ljava/lang/Float;"); /** {@link ClassDesc} representing {@link Double} */ - public static final ClassDesc CD_Double = ClassDesc.ofDescriptor("Ljava/lang/Double;"); + public static final ClassDesc CD_Double = new ReferenceClassDescImpl("Ljava/lang/Double;"); /** {@link ClassDesc} representing {@link Short} */ - public static final ClassDesc CD_Short = ClassDesc.ofDescriptor("Ljava/lang/Short;"); + public static final ClassDesc CD_Short = new ReferenceClassDescImpl("Ljava/lang/Short;"); /** {@link ClassDesc} representing {@link Byte} */ - public static final ClassDesc CD_Byte = ClassDesc.ofDescriptor("Ljava/lang/Byte;"); + public static final ClassDesc CD_Byte = new ReferenceClassDescImpl("Ljava/lang/Byte;"); /** {@link ClassDesc} representing {@link Character} */ - public static final ClassDesc CD_Character = ClassDesc.ofDescriptor("Ljava/lang/Character;"); + public static final ClassDesc CD_Character = new ReferenceClassDescImpl("Ljava/lang/Character;"); /** {@link ClassDesc} representing {@link Boolean} */ - public static final ClassDesc CD_Boolean = ClassDesc.ofDescriptor("Ljava/lang/Boolean;"); + public static final ClassDesc CD_Boolean = new ReferenceClassDescImpl("Ljava/lang/Boolean;"); /** {@link ClassDesc} representing {@link Void} */ - public static final ClassDesc CD_Void = ClassDesc.ofDescriptor("Ljava/lang/Void;"); + public static final ClassDesc CD_Void = new ReferenceClassDescImpl("Ljava/lang/Void;"); /** {@link ClassDesc} representing {@link Throwable} */ - public static final ClassDesc CD_Throwable = ClassDesc.ofDescriptor("Ljava/lang/Throwable;"); + public static final ClassDesc CD_Throwable = new ReferenceClassDescImpl("Ljava/lang/Throwable;"); /** {@link ClassDesc} representing {@link Exception} */ - public static final ClassDesc CD_Exception = ClassDesc.ofDescriptor("Ljava/lang/Exception;"); + public static final ClassDesc CD_Exception = new ReferenceClassDescImpl("Ljava/lang/Exception;"); /** {@link ClassDesc} representing {@link Enum} */ - public static final ClassDesc CD_Enum = ClassDesc.ofDescriptor("Ljava/lang/Enum;"); + public static final ClassDesc CD_Enum = new ReferenceClassDescImpl("Ljava/lang/Enum;"); /** {@link ClassDesc} representing {@link VarHandle} */ - public static final ClassDesc CD_VarHandle = ClassDesc.ofDescriptor("Ljava/lang/invoke/VarHandle;"); + public static final ClassDesc CD_VarHandle = new ReferenceClassDescImpl("Ljava/lang/invoke/VarHandle;"); /** {@link ClassDesc} representing {@link MethodHandles} */ - public static final ClassDesc CD_MethodHandles = ClassDesc.ofDescriptor("Ljava/lang/invoke/MethodHandles;"); + public static final ClassDesc CD_MethodHandles = new ReferenceClassDescImpl("Ljava/lang/invoke/MethodHandles;"); /** {@link ClassDesc} representing {@link MethodHandles.Lookup} */ - public static final ClassDesc CD_MethodHandles_Lookup = CD_MethodHandles.nested("Lookup"); + public static final ClassDesc CD_MethodHandles_Lookup = new ReferenceClassDescImpl("Ljava/lang/invoke/MethodHandles$Lookup;"); /** {@link ClassDesc} representing {@link MethodHandle} */ - public static final ClassDesc CD_MethodHandle = ClassDesc.ofDescriptor("Ljava/lang/invoke/MethodHandle;"); + public static final ClassDesc CD_MethodHandle = new ReferenceClassDescImpl("Ljava/lang/invoke/MethodHandle;"); /** {@link ClassDesc} representing {@link MethodType} */ - public static final ClassDesc CD_MethodType = ClassDesc.ofDescriptor("Ljava/lang/invoke/MethodType;"); + public static final ClassDesc CD_MethodType = new ReferenceClassDescImpl("Ljava/lang/invoke/MethodType;"); /** {@link ClassDesc} representing {@link CallSite} */ - public static final ClassDesc CD_CallSite = ClassDesc.ofDescriptor("Ljava/lang/invoke/CallSite;"); + public static final ClassDesc CD_CallSite = new ReferenceClassDescImpl("Ljava/lang/invoke/CallSite;"); /** {@link ClassDesc} representing {@link Collection} */ - public static final ClassDesc CD_Collection = ClassDesc.ofDescriptor("Ljava/util/Collection;"); + public static final ClassDesc CD_Collection = new ReferenceClassDescImpl("Ljava/util/Collection;"); /** {@link ClassDesc} representing {@link List} */ - public static final ClassDesc CD_List = ClassDesc.ofDescriptor("Ljava/util/List;"); + public static final ClassDesc CD_List = new ReferenceClassDescImpl("Ljava/util/List;"); /** {@link ClassDesc} representing {@link Set} */ - public static final ClassDesc CD_Set = ClassDesc.ofDescriptor("Ljava/util/Set;"); + public static final ClassDesc CD_Set = new ReferenceClassDescImpl("Ljava/util/Set;"); /** {@link ClassDesc} representing {@link Map} */ - public static final ClassDesc CD_Map = ClassDesc.ofDescriptor("Ljava/util/Map;"); + public static final ClassDesc CD_Map = new ReferenceClassDescImpl("Ljava/util/Map;"); /** {@link ClassDesc} representing {@link ConstantDesc} */ - public static final ClassDesc CD_ConstantDesc = ClassDesc.ofDescriptor("Ljava/lang/constant/ConstantDesc;"); + public static final ClassDesc CD_ConstantDesc = new ReferenceClassDescImpl("Ljava/lang/constant/ConstantDesc;"); /** {@link ClassDesc} representing {@link ClassDesc} */ - public static final ClassDesc CD_ClassDesc = ClassDesc.ofDescriptor("Ljava/lang/constant/ClassDesc;"); + public static final ClassDesc CD_ClassDesc = new ReferenceClassDescImpl("Ljava/lang/constant/ClassDesc;"); /** {@link ClassDesc} representing {@link EnumDesc} */ - public static final ClassDesc CD_EnumDesc = CD_Enum.nested("EnumDesc"); + public static final ClassDesc CD_EnumDesc = new ReferenceClassDescImpl("Ljava/lang/Enum$EnumDesc;"); /** {@link ClassDesc} representing {@link MethodTypeDesc} */ - public static final ClassDesc CD_MethodTypeDesc = ClassDesc.ofDescriptor("Ljava/lang/constant/MethodTypeDesc;"); + public static final ClassDesc CD_MethodTypeDesc = new ReferenceClassDescImpl("Ljava/lang/constant/MethodTypeDesc;"); /** {@link ClassDesc} representing {@link MethodHandleDesc} */ - public static final ClassDesc CD_MethodHandleDesc = ClassDesc.ofDescriptor("Ljava/lang/constant/MethodHandleDesc;"); + public static final ClassDesc CD_MethodHandleDesc = new ReferenceClassDescImpl("Ljava/lang/constant/MethodHandleDesc;"); /** {@link ClassDesc} representing {@link DirectMethodHandleDesc} */ - public static final ClassDesc CD_DirectMethodHandleDesc = ClassDesc.ofDescriptor("Ljava/lang/constant/DirectMethodHandleDesc;"); + public static final ClassDesc CD_DirectMethodHandleDesc = new ReferenceClassDescImpl("Ljava/lang/constant/DirectMethodHandleDesc;"); /** {@link ClassDesc} representing {@link VarHandleDesc} */ - public static final ClassDesc CD_VarHandleDesc = CD_VarHandle.nested("VarHandleDesc"); + public static final ClassDesc CD_VarHandleDesc = new ReferenceClassDescImpl("Ljava/lang/invoke/VarHandle$VarHandleDesc;"); /** {@link ClassDesc} representing {@link DirectMethodHandleDesc.Kind} */ - public static final ClassDesc CD_MethodHandleDesc_Kind = CD_DirectMethodHandleDesc.nested("Kind"); + public static final ClassDesc CD_MethodHandleDesc_Kind = new ReferenceClassDescImpl("Ljava/lang/constant/DirectMethodHandleDesc$Kind;"); /** {@link ClassDesc} representing {@link DynamicConstantDesc} */ - public static final ClassDesc CD_DynamicConstantDesc = ClassDesc.ofDescriptor("Ljava/lang/constant/DynamicConstantDesc;"); + public static final ClassDesc CD_DynamicConstantDesc = new ReferenceClassDescImpl("Ljava/lang/constant/DynamicConstantDesc;"); /** {@link ClassDesc} representing {@link DynamicCallSiteDesc} */ - public static final ClassDesc CD_DynamicCallSiteDesc = ClassDesc.ofDescriptor("Ljava/lang/constant/DynamicCallSiteDesc;"); + public static final ClassDesc CD_DynamicCallSiteDesc = new ReferenceClassDescImpl("Ljava/lang/constant/DynamicCallSiteDesc;"); /** {@link ClassDesc} representing {@link ConstantBootstraps} */ - public static final ClassDesc CD_ConstantBootstraps = ClassDesc.ofDescriptor("Ljava/lang/invoke/ConstantBootstraps;"); + public static final ClassDesc CD_ConstantBootstraps = new ReferenceClassDescImpl("Ljava/lang/invoke/ConstantBootstraps;"); private static final ClassDesc[] INDY_BOOTSTRAP_ARGS = { - ConstantDescs.CD_MethodHandles_Lookup, - ConstantDescs.CD_String, - ConstantDescs.CD_MethodType}; + CD_MethodHandles_Lookup, + CD_String, + CD_MethodType}; private static final ClassDesc[] CONDY_BOOTSTRAP_ARGS = { - ConstantDescs.CD_MethodHandles_Lookup, - ConstantDescs.CD_String, - ConstantDescs.CD_Class}; + CD_MethodHandles_Lookup, + CD_String, + CD_Class}; /** {@link MethodHandleDesc} representing {@link ConstantBootstraps#primitiveClass(Lookup, String, Class) ConstantBootstraps.primitiveClass} */ public static final DirectMethodHandleDesc BSM_PRIMITIVE_CLASS diff --git a/src/java.base/share/classes/java/lang/constant/ConstantUtils.java b/src/java.base/share/classes/java/lang/constant/ConstantUtils.java index 10ed2758e3ac0..d50a01f5c08a5 100644 --- a/src/java.base/share/classes/java/lang/constant/ConstantUtils.java +++ b/src/java.base/share/classes/java/lang/constant/ConstantUtils.java @@ -144,7 +144,6 @@ public static String validateModuleName(String name) { * @throws IllegalArgumentException if the member name is invalid */ public static String validateMemberName(String name, boolean method) { - requireNonNull(name); if (name.length() == 0) throw new IllegalArgumentException("zero-length member name"); for (int i=0; i Date: Wed, 24 Apr 2024 11:45:20 +0200 Subject: [PATCH 08/13] Minor changes to classfile-based generators --- .../invoke/InnerClassLambdaMetafactory.java | 12 ++++++++--- .../lang/invoke/InvokerBytecodeGenerator.java | 20 ++++++++++++------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java b/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java index 6385f0c860328..e7122d6436cd8 100644 --- a/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java +++ b/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java @@ -563,12 +563,18 @@ static ClassDesc implClassDesc(Class cls) { return cls.isHidden() ? ClassDesc.ofInternalName(cls.getName().replace('.', '/')) : classDesc(cls); } - static ClassDesc classDesc(Class cls) { - return ClassDesc.ofDescriptor(cls.descriptorString()); + return cls == Object.class ? CD_Object + : ClassDesc.ofDescriptor(cls.descriptorString()); } static MethodTypeDesc methodDesc(MethodType mt) { - return MethodTypeDesc.ofDescriptor(mt.descriptorString()); + ClassDesc returnDesc = classDesc(mt.returnType()); + ClassDesc[] params = new ClassDesc[mt.parameterCount()]; + int i = 0; + for (Class param : mt.ptypes()) { + params[i++] = classDesc(param); + } + return MethodTypeDesc.of(returnDesc, params); } } diff --git a/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java b/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java index 4ef1f0b86760d..eddc0826ed58a 100644 --- a/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java +++ b/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java @@ -71,13 +71,13 @@ */ class InvokerBytecodeGenerator { /** Define class names for convenience. */ - private static final ClassDesc CD_DMH = ClassDesc.ofInternalName("java/lang/invoke/DirectMethodHandle"); - private static final ClassDesc CD_MHI = ClassDesc.ofInternalName("java/lang/invoke/MethodHandleImpl"); - private static final ClassDesc CD_LF = ClassDesc.ofInternalName("java/lang/invoke/LambdaForm"); - private static final ClassDesc CD_LFN = ClassDesc.ofInternalName("java/lang/invoke/LambdaForm$Name"); - private static final ClassDesc CD_OBJARY = CD_Object.arrayType(); + private static final ClassDesc CD_DMH = ClassDesc.ofDescriptor("Ljava/lang/invoke/DirectMethodHandle;"); + private static final ClassDesc CD_MHI = ClassDesc.ofDescriptor("Ljava/lang/invoke/MethodHandleImpl;"); + private static final ClassDesc CD_LF = ClassDesc.ofDescriptor("Ljava/lang/invoke/LambdaForm;"); + private static final ClassDesc CD_LFN = ClassDesc.ofDescriptor("Ljava/lang/invoke/LambdaForm$Name;"); + private static final ClassDesc CD_OBJARY = ClassDesc.ofDescriptor("[Ljava/lang/Object;"); - private static final ClassDesc CD_LOOP_CLAUSES = ClassDesc.ofInternalName("java/lang/invoke/MethodHandleImpl$LoopClauses"); + private static final ClassDesc CD_LOOP_CLAUSES = ClassDesc.ofDescriptor("Ljava/lang/invoke/MethodHandleImpl$LoopClauses;"); private static final ClassDesc CD_MHARY2 = CD_MethodHandle.arrayType(2); @@ -1722,6 +1722,12 @@ static ClassDesc classDesc(Class cls) { } static MethodTypeDesc methodDesc(MethodType mt) { - return MethodTypeDesc.ofDescriptor(mt.descriptorString()); + ClassDesc returnDesc = classDesc(mt.returnType()); + ClassDesc[] params = new ClassDesc[mt.parameterCount()]; + int i = 0; + for (Class param : mt.ptypes()) { + params[i++] = classDesc(param); + } + return MethodTypeDesc.of(returnDesc, params); } } From b6178a176aa4f5761c288a8c726047056ac35924 Mon Sep 17 00:00:00 2001 From: redestad Date: Wed, 24 Apr 2024 11:45:43 +0200 Subject: [PATCH 09/13] Simplify ClassDesc.ofDescriptor and ReferenceClassDescImpl constructor --- .../classes/java/lang/constant/ClassDesc.java | 16 +++------------- .../lang/constant/ReferenceClassDescImpl.java | 7 +++---- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/src/java.base/share/classes/java/lang/constant/ClassDesc.java b/src/java.base/share/classes/java/lang/constant/ClassDesc.java index dea0051163106..18b8c2a42a3ce 100644 --- a/src/java.base/share/classes/java/lang/constant/ClassDesc.java +++ b/src/java.base/share/classes/java/lang/constant/ClassDesc.java @@ -158,20 +158,10 @@ static ClassDesc of(String packageName, String className) { * @see ClassDesc#ofInternalName(String) */ static ClassDesc ofDescriptor(String descriptor) { - requireNonNull(descriptor); - if (descriptor.isEmpty()) { - throw new IllegalArgumentException( - "not a valid reference type descriptor: " + descriptor); + if (descriptor.length() == 1) { + return Wrapper.forBasicType(descriptor.charAt(0)).primitiveClassDescriptor(); } - int depth = ConstantUtils.arrayDepth(descriptor); - if (depth > ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS) { - throw new IllegalArgumentException( - "Cannot create an array type descriptor with more than " + - ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS + " dimensions"); - } - return (descriptor.length() == 1) - ? Wrapper.forBasicType(descriptor.charAt(0)).primitiveClassDescriptor() - : new ReferenceClassDescImpl(descriptor); + return new ReferenceClassDescImpl(descriptor); } /** diff --git a/src/java.base/share/classes/java/lang/constant/ReferenceClassDescImpl.java b/src/java.base/share/classes/java/lang/constant/ReferenceClassDescImpl.java index 4cc77b1851deb..5e2aaa98442e0 100644 --- a/src/java.base/share/classes/java/lang/constant/ReferenceClassDescImpl.java +++ b/src/java.base/share/classes/java/lang/constant/ReferenceClassDescImpl.java @@ -47,10 +47,9 @@ final class ReferenceClassDescImpl implements ClassDesc { * @jvms 4.3.2 Field Descriptors */ ReferenceClassDescImpl(String descriptor) { - requireNonNull(descriptor); - int len = ConstantUtils.skipOverFieldSignature(descriptor, 0, descriptor.length(), false); - if (len == 0 || len == 1 - || len != descriptor.length()) + int dLen = descriptor.length(); + int len = ConstantUtils.skipOverFieldSignature(descriptor, 0, dLen, false); + if (len <= 1 || len != dLen) throw new IllegalArgumentException(String.format("not a valid reference type descriptor: %s", descriptor)); this.descriptor = descriptor; } From eb972f46e06f28aa358ab6335624e0b2425f80fb Mon Sep 17 00:00:00 2001 From: redestad Date: Wed, 24 Apr 2024 16:20:25 +0200 Subject: [PATCH 10/13] Revert ClassValue cache of descriptorString --- src/java.base/share/classes/java/lang/Class.java | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/java.base/share/classes/java/lang/Class.java b/src/java.base/share/classes/java/lang/Class.java index 1a1452e8c264e..0be18b215963e 100644 --- a/src/java.base/share/classes/java/lang/Class.java +++ b/src/java.base/share/classes/java/lang/Class.java @@ -3424,13 +3424,6 @@ static boolean casAnnotationData(Class clazz, // values may be invalidated when JVM TI RedefineClasses() is called private static class ReflectionData { - private static final ClassValue descriptors = new ClassValue<>() { - @Override - protected String computeValue(java.lang.Class type) { - return type.descriptorStringImpl(); - } - }; - volatile Field[] declaredFields; volatile Field[] publicFields; volatile Method[] declaredMethods; @@ -4643,10 +4636,6 @@ public Class[] getNestMembers() { */ @Override public String descriptorString() { - return ReflectionData.descriptors.get(this); - } - - private String descriptorStringImpl() { if (isPrimitive()) return Wrapper.forPrimitiveType(this).basicTypeString(); From 4638de0a835c3822306d5c9288fa6c59ba3cd8cd Mon Sep 17 00:00:00 2001 From: redestad Date: Wed, 24 Apr 2024 18:41:50 +0200 Subject: [PATCH 11/13] Redundant requireNonNulls --- .../share/classes/java/lang/constant/MethodTypeDescImpl.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/java/lang/constant/MethodTypeDescImpl.java b/src/java.base/share/classes/java/lang/constant/MethodTypeDescImpl.java index 4ab4a56ae6765..09149f9fd997f 100644 --- a/src/java.base/share/classes/java/lang/constant/MethodTypeDescImpl.java +++ b/src/java.base/share/classes/java/lang/constant/MethodTypeDescImpl.java @@ -57,8 +57,8 @@ final class MethodTypeDescImpl implements MethodTypeDesc { * @param validatedArgTypes {@link ClassDesc}s describing the trusted and validated parameter types */ private MethodTypeDescImpl(ClassDesc returnType, ClassDesc[] validatedArgTypes) { - this.returnType = requireNonNull(returnType); - this.argTypes = requireNonNull(validatedArgTypes); + this.returnType = returnType; + this.argTypes = validatedArgTypes; } /** @@ -157,6 +157,7 @@ public ClassDesc[] parameterArray() { @Override public MethodTypeDesc changeReturnType(ClassDesc returnType) { + requireNonNull(returnType); return new MethodTypeDescImpl(returnType, argTypes); } From abd51469103c6dd1c7e54441a0263c4095311560 Mon Sep 17 00:00:00 2001 From: redestad Date: Thu, 25 Apr 2024 10:49:58 +0200 Subject: [PATCH 12/13] Optimize MethodTypeDescImpl::toString --- .../classes/java/lang/constant/MethodTypeDesc.java | 11 ++++++----- .../java/lang/constant/MethodTypeDescImpl.java | 12 +++++++----- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/java.base/share/classes/java/lang/constant/MethodTypeDesc.java b/src/java.base/share/classes/java/lang/constant/MethodTypeDesc.java index ff750ccc893bb..56df0c9ffee4a 100644 --- a/src/java.base/share/classes/java/lang/constant/MethodTypeDesc.java +++ b/src/java.base/share/classes/java/lang/constant/MethodTypeDesc.java @@ -204,11 +204,12 @@ static MethodTypeDesc of(ClassDesc returnDesc, ClassDesc... paramDescs) { * @return the human-readable descriptor for this method type */ default String displayDescriptor() { - return String.format("(%s)%s", - Stream.of(parameterArray()) - .map(ClassDesc::displayName) - .collect(Collectors.joining(",")), - returnType().displayName()); + int count = parameterCount(); + StringBuilder sb = new StringBuilder(24).append('('); + for (int i = 0; i < count; i++) { + sb.append(parameterType(i).displayName()); + } + return sb.append(')').append(returnType().displayName()).toString(); } /** diff --git a/src/java.base/share/classes/java/lang/constant/MethodTypeDescImpl.java b/src/java.base/share/classes/java/lang/constant/MethodTypeDescImpl.java index 09149f9fd997f..4f59486229e48 100644 --- a/src/java.base/share/classes/java/lang/constant/MethodTypeDescImpl.java +++ b/src/java.base/share/classes/java/lang/constant/MethodTypeDescImpl.java @@ -197,12 +197,14 @@ public String descriptorString() { var desc = this.cachedDescriptorString; if (desc != null) return desc; - - var sj = new StringJoiner("", "(", ")" + returnType().descriptorString()); - for (int i = 0; i < parameterCount(); i++) { - sj.add(parameterType(i).descriptorString()); + int count = parameterCount(); + StringBuilder sb = new StringBuilder(24).append('('); + for (int i = 0; i < count; i++) { + sb.append(parameterType(i).descriptorString()); } - return cachedDescriptorString = sj.toString(); + desc = sb.append(')').append(returnType().descriptorString()).toString(); + cachedDescriptorString = desc; + return desc; } @Override From 274bf9e65e1cc1c184accbb1936145228b202e0f Mon Sep 17 00:00:00 2001 From: redestad Date: Thu, 25 Apr 2024 12:40:17 +0200 Subject: [PATCH 13/13] Fix ClassDescTest --- src/java.base/share/classes/java/lang/constant/ClassDesc.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java.base/share/classes/java/lang/constant/ClassDesc.java b/src/java.base/share/classes/java/lang/constant/ClassDesc.java index 18b8c2a42a3ce..c628063a933d6 100644 --- a/src/java.base/share/classes/java/lang/constant/ClassDesc.java +++ b/src/java.base/share/classes/java/lang/constant/ClassDesc.java @@ -159,7 +159,7 @@ static ClassDesc of(String packageName, String className) { */ static ClassDesc ofDescriptor(String descriptor) { if (descriptor.length() == 1) { - return Wrapper.forBasicType(descriptor.charAt(0)).primitiveClassDescriptor(); + return Wrapper.forPrimitiveType(descriptor.charAt(0)).primitiveClassDescriptor(); } return new ReferenceClassDescImpl(descriptor); }