diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java index e2a825498e8ad..35b9f2dd1bb33 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java @@ -382,38 +382,6 @@ else if ((state == State.STRING && u.state == State.STRING)) return stringValue().equals(u.stringValue()); } - /** - * Returns if this utf8 entry's content equals a substring - * of {@code s} obtained as {@code s.substring(start, end - start)}. - * This check avoids a substring allocation. - */ - public boolean equalsRegion(String s, int start, int end) { - // start and end values trusted - if (state == State.RAW) - inflate(); - int len = charLen; - if (len != end - start) - return false; - - var sv = stringValue; - if (sv != null) { - return sv.regionMatches(0, s, start, len); - } - - var chars = this.chars; - if (chars != null) { - for (int i = 0; i < len; i++) - if (chars[i] != s.charAt(start + i)) - return false; - } else { - var bytes = this.rawBytes; - for (int i = 0; i < len; i++) - if (bytes[offset + i] != s.charAt(start + i)) - return false; - } - return true; - } - @Override public boolean equalsString(String s) { if (state == State.RAW) diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java b/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java index d1ae1066d13f8..f0e0047f57d98 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java @@ -394,24 +394,6 @@ private AbstractPoolEntry.Utf8EntryImpl tryFindUtf8(int hash, AbstractPoolEntry. return null; } - private AbstractPoolEntry.Utf8EntryImpl tryFindUtf8OfRegion(int hash, String target, int start, int end) { - EntryMap map = map(); - while (true) { - for (int token = map.firstToken(hash); token != -1; token = map.nextToken(hash, token)) { - PoolEntry e = entryByIndex(map.getIndexByToken(token)); - if (e.tag() == TAG_UTF8 - && e instanceof AbstractPoolEntry.Utf8EntryImpl ce - && ce.equalsRegion(target, start, end)) - return ce; - } - if (!doneFullScan) { - fullScan(); - continue; - } - return null; - } - } - private AbstractPoolEntry.ClassEntryImpl tryFindClassOrInterface(int hash, ClassDesc cd) { while (true) { EntryMap map = map(); @@ -429,8 +411,7 @@ private AbstractPoolEntry.ClassEntryImpl tryFindClassOrInterface(int hash, Class } // no symbol available - var desc = cd.descriptorString(); - if (ce.ref1.equalsRegion(desc, 1, desc.length() - 1)) { + if (ce.ref1.equalsString(Util.toInternalName(cd))) { // definite match, propagate symbol ce.sym = cd; return ce; @@ -454,10 +435,11 @@ private AbstractPoolEntry.ClassEntryImpl classEntryForClassOrInterface(ClassDesc if (ce != null) return ce; - var utfHash = Util.internalNameHash(desc); - var utf = tryFindUtf8OfRegion(AbstractPoolEntry.hashString(utfHash), desc, 1, desc.length() - 1); + String internalName = Util.toInternalName(cd); + var utfHash = internalName.hashCode(); + var utf = tryFindUtf8(AbstractPoolEntry.hashString(utfHash), internalName); if (utf == null) - utf = internalAdd(new AbstractPoolEntry.Utf8EntryImpl(this, size, ConstantUtils.dropFirstAndLastChar(desc), utfHash)); + utf = internalAdd(new AbstractPoolEntry.Utf8EntryImpl(this, size, internalName, utfHash)); return internalAdd(new AbstractPoolEntry.ClassEntryImpl(this, size, utf, hash, cd)); } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java b/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java index 352019dd9dace..848d153c24bdf 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java @@ -42,6 +42,7 @@ import java.util.function.Function; import jdk.internal.access.SharedSecrets; +import jdk.internal.constant.ReferenceClassDescImpl; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.annotation.Stable; @@ -133,10 +134,10 @@ public static String toBinaryName(ClassDesc cd) { } public static String toInternalName(ClassDesc cd) { - var desc = cd.descriptorString(); - if (desc.charAt(0) == 'L') - return desc.substring(1, desc.length() - 1); - throw new IllegalArgumentException(desc); + if (cd instanceof ReferenceClassDescImpl rcd) { + return rcd.internalName(); + } + throw new IllegalArgumentException(cd.descriptorString()); } public static ClassDesc toClassDesc(String classInternalNameOrArrayDesc) { @@ -321,15 +322,6 @@ interface WritableLocalVariable { boolean writeLocalTo(BufWriterImpl buf); } - /** - * Returns the hash code of an internal name given the class or interface L descriptor. - */ - public static int internalNameHash(String desc) { - if (desc.length() > 0xffff) - throw new IllegalArgumentException("String too long: ".concat(Integer.toString(desc.length()))); - return (desc.hashCode() - pow31(desc.length() - 1) * 'L' - ';') * INVERSE_31; - } - /** * Returns the hash code of a class or interface L descriptor given the internal name. */ diff --git a/src/java.base/share/classes/jdk/internal/constant/ReferenceClassDescImpl.java b/src/java.base/share/classes/jdk/internal/constant/ReferenceClassDescImpl.java index b8cc9aacfe0a4..8124abc6b75b0 100644 --- a/src/java.base/share/classes/jdk/internal/constant/ReferenceClassDescImpl.java +++ b/src/java.base/share/classes/jdk/internal/constant/ReferenceClassDescImpl.java @@ -27,6 +27,7 @@ import java.lang.constant.ClassDesc; import java.lang.invoke.MethodHandles; +import jdk.internal.vm.annotation.Stable; import static jdk.internal.constant.ConstantUtils.*; /** @@ -36,6 +37,7 @@ */ public final class ReferenceClassDescImpl implements ClassDesc { private final String descriptor; + private @Stable String internalName; private ReferenceClassDescImpl(String descriptor) { this.descriptor = descriptor; @@ -76,6 +78,16 @@ public String descriptorString() { return descriptor; } + public String internalName() { + var internalName = this.internalName; + if (internalName == null) { + var desc = this.descriptor; + this.internalName = internalName = desc.charAt(0) == 'L' ? dropFirstAndLastChar(desc) : desc; + } + + return internalName; + } + @Override public Class resolveConstantDesc(MethodHandles.Lookup lookup) throws ReflectiveOperationException { @@ -90,7 +102,7 @@ public Class resolveConstantDesc(MethodHandles.Lookup lookup) clazz = clazz.arrayType(); return clazz; } - return lookup.findClass(internalToBinary(dropFirstAndLastChar(descriptor))); + return lookup.findClass(internalToBinary(internalName())); } /** diff --git a/test/jdk/jdk/classfile/UtilTest.java b/test/jdk/jdk/classfile/UtilTest.java index 6ba7e146b0371..cc41a326045ce 100644 --- a/test/jdk/jdk/classfile/UtilTest.java +++ b/test/jdk/jdk/classfile/UtilTest.java @@ -103,20 +103,6 @@ void testPow31() { } } - @ParameterizedTest - @ValueSource(classes = { - Long.class, - Object.class, - Util.class, - Test.class, - CopyOnWriteArrayList.class, - AtomicReferenceFieldUpdater.class - }) - void testInternalNameHash(Class type) { - var cd = type.describeConstable().orElseThrow(); - assertEquals(ConstantUtils.binaryToInternal(type.getName()).hashCode(), Util.internalNameHash(cd.descriptorString())); - } - // Ensures the initialization statement of the powers array is filling in the right values @Test void testPowersArray() {