Skip to content

Commit

Permalink
8342206: Convenience method to check if a constant pool entry matches…
Browse files Browse the repository at this point in the history
… nominal descriptors
  • Loading branch information
liach committed Feb 11, 2025
1 parent bb454eb commit de66927
Show file tree
Hide file tree
Showing 9 changed files with 405 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,22 @@ default ConstantDesc constantValue() {
* returned descriptor is never {@linkplain ClassDesc#isPrimitive()
* primitive}.
*
* @apiNote
* If only symbol equivalence is desired, {@link #equalsSymbol(ClassDesc)
* equalsSymbol} should be used. It requires reduced parsing and can
* improve {@code class} file reading performance.
*
* @see ConstantPoolBuilder#classEntry(ClassDesc)
* ConstantPoolBuilder::classEntry(ClassDesc)
*/
ClassDesc asSymbol();

/**
* {@return whether this entry describes the given reference type} Returns
* {@code false} if {@code desc} is primitive.
*
* @param desc the reference type
* @since 25
*/
boolean equalsSymbol(ClassDesc desc);
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,19 @@ default ConstantDesc constantValue() {
/**
* {@return a symbolic descriptor for the {@linkplain #descriptor() method
* type}}
*
* @apiNote
* If only symbol equivalence is desired, {@link #equalsSymbol(MethodTypeDesc)
* equalsSymbol} should be used. It requires reduced parsing and can
* improve {@code class} file reading performance.
*/
MethodTypeDesc asSymbol();

/**
* {@return whether this entry describes the given method type}
*
* @param desc the method type descriptor
* @since 25
*/
boolean equalsSymbol(MethodTypeDesc desc);
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,19 @@ public sealed interface ModuleEntry extends PoolEntry

/**
* {@return a symbolic descriptor for the {@linkplain #name() module name}}
*
* @apiNote
* If only symbol equivalence is desired, {@link #equalsSymbol(ModuleDesc)
* equalsSymbol} should be used. It requires reduced parsing and can
* improve {@code class} file reading performance.
*/
ModuleDesc asSymbol();

/**
* {@return whether this entry describes the given module}
*
* @param desc the module descriptor
* @since 25
*/
boolean equalsSymbol(ModuleDesc desc);
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,19 @@ public sealed interface PackageEntry extends PoolEntry

/**
* {@return a symbolic descriptor for the {@linkplain #name() package name}}
*
* @apiNote
* If only symbol equivalence is desired, {@link #equalsSymbol(PackageDesc)
* equalsSymbol} should be used. It requires reduced parsing and can
* improve {@code class} file reading performance.
*/
PackageDesc asSymbol();

/**
* {@return whether this entry describes the given package}
*
* @param desc the package descriptor
* @since 25
*/
boolean equalsSymbol(PackageDesc desc);
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,22 @@ public sealed interface StringEntry
/**
* {@return the string value for this entry}
*
* @apiNote
* A {@code Utf8Entry} can be used directly as a {@link CharSequence} if
* {@code String} functionalities are not strictly desired. If only string
* equivalence is desired, {@link #equalsString(String) equalsString} should
* be used. Reduction of string processing can significantly improve {@code
* class} file reading performance.
*
* @see ConstantPoolBuilder#stringEntry(String)
*/
String stringValue();

/**
* {@return whether this entry describes the same string as the provided string}
*
* @param value the string to compare to
* @since 25
*/
boolean equalsString(String value);
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,22 @@ public sealed interface Utf8Entry
* @param s the string to compare to
*/
boolean equalsString(String s);

/**
* {@return whether this entry describes the descriptor string of this
* field type}
*
* @param desc the field type
* @since 25
*/
boolean equalsSymbol(ClassDesc desc);

/**
* {@return whether this entry describes the descriptor string of this
* method type}
*
* @param desc the method type
* @since 25
*/
boolean equalsSymbol(MethodTypeDesc desc);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 2025, 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
Expand Down Expand Up @@ -32,6 +32,8 @@

import jdk.internal.access.JavaLangAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.constant.ClassOrInterfaceDescImpl;
import jdk.internal.constant.PrimitiveClassDescImpl;
import jdk.internal.util.ArraysSupport;
import jdk.internal.vm.annotation.Stable;

Expand Down Expand Up @@ -73,11 +75,6 @@ static int hashClassFromDescriptor(int descriptorHash) {
return hash1(PoolEntry.TAG_CLASS, descriptorHash);
}

static boolean isArrayDescriptor(Utf8EntryImpl cs) {
// Do not throw out-of-bounds for empty strings
return !cs.isEmpty() && cs.charAt(0) == '[';
}

@SuppressWarnings("unchecked")
public static <T extends PoolEntry> T maybeClone(ConstantPoolBuilder cp, T entry) {
if (cp.canWriteDirect(entry.constantPool()))
Expand Down Expand Up @@ -438,6 +435,79 @@ public MethodTypeDesc methodTypeSymbol() {
typeSym = ret;
return ret;
}

@Override
public boolean equalsSymbol(ClassDesc desc) {
var sym = typeSym;
if (sym != null) {
return sym instanceof ClassDesc cd && cd.equals(desc);
}

// In parsing, Utf8Entry is not even inflated by this point
// We can operate on the raw byte arrays, as all ascii are compatible
var ret = state == State.RAW
? rawEqualsSym(desc)
: equalsString(desc.descriptorString());
if (ret)
this.typeSym = desc;
return ret;
}

private boolean rawEqualsSym(ClassDesc desc) {
int len = rawLen;
if (len < 1) {
return false;
}
int c = rawBytes[offset];
if (len == 1) {
return desc instanceof PrimitiveClassDescImpl pd && pd.wrapper().basicTypeChar() == c;
} else if (c == 'L') {
return desc.isClassOrInterface() && equalsString(desc.descriptorString());
} else if (c == '[') {
return desc.isArray() && equalsString(desc.descriptorString());
} else {
return false;
}
}

boolean mayBeArrayDescriptor() {
if (state == State.RAW) {
return rawLen > 0 && rawBytes[offset] == '[';
} else {
return charLen > 0 && charAt(0) == '[';
}
}

@Override
public boolean equalsSymbol(MethodTypeDesc desc) {
var sym = typeSym;
if (sym != null) {
return sym instanceof MethodTypeDesc mtd && mtd.equals(desc);
}

// In parsing, Utf8Entry is not even inflated by this point
// We can operate on the raw byte arrays, as all ascii are compatible
var ret = state == State.RAW
? rawEqualsSym(desc)
: equalsString(desc.descriptorString());
if (ret)
this.typeSym = desc;
return ret;
}

private boolean rawEqualsSym(MethodTypeDesc desc) {
if (rawLen < 3) {
return false;
}
var bytes = rawBytes;
int index = offset;
int c = bytes[index] | (bytes[index + 1] << Byte.SIZE);
if ((desc.parameterCount() == 0) != (c == ('(' | (')' << Byte.SIZE)))) {
// heuristic - avoid inflation for no-arg status mismatch
return false;
}
return (c & 0xFF) == '(' && equalsString(desc.descriptorString());
}
}

abstract static sealed class AbstractRefEntry<T extends PoolEntry> extends AbstractPoolEntry {
Expand Down Expand Up @@ -538,14 +608,36 @@ public ClassDesc asSymbol() {
return sym;
}

if (isArrayDescriptor(ref1)) {
if (ref1.mayBeArrayDescriptor()) {
sym = ref1.fieldTypeSymbol(); // array, symbol already available
} else {
sym = ClassDesc.ofInternalName(asInternalName()); // class or interface
}
return this.sym = sym;
}

@Override
public boolean equalsSymbol(ClassDesc desc) {
var sym = this.sym;
if (sym != null) {
return sym.equals(desc);
}

var ret = rawEqualsSymbol(desc);
if (ret)
this.sym = desc;
return ret;
}

private boolean rawEqualsSymbol(ClassDesc desc) {
if (ref1.mayBeArrayDescriptor()) {
return desc.isArray() && ref1.equalsSymbol(desc);
} else {
return desc instanceof ClassOrInterfaceDescImpl coid
&& ref1.equalsString(coid.internalName());
}
}

@Override
public boolean equals(Object o) {
if (o == this) return true;
Expand All @@ -571,7 +663,7 @@ public int hashCode() {
if (hash != 0)
return hash;

return this.hash = hashClassFromUtf8(isArrayDescriptor(ref1), ref1);
return this.hash = hashClassFromUtf8(ref1.mayBeArrayDescriptor(), ref1);
}
}

Expand All @@ -596,6 +688,11 @@ public PackageDesc asSymbol() {
return PackageDesc.ofInternalName(asInternalName());
}

@Override
public boolean equalsSymbol(PackageDesc desc) {
return ref1.equalsString(desc.internalName());
}

@Override
public boolean equals(Object o) {
if (o == this) return true;
Expand Down Expand Up @@ -627,6 +724,11 @@ public ModuleDesc asSymbol() {
return ModuleDesc.of(asInternalName());
}

@Override
public boolean equalsSymbol(ModuleDesc desc) {
return ref1.equalsString(desc.name());
}

@Override
public boolean equals(Object o) {
if (o == this) return true;
Expand Down Expand Up @@ -983,6 +1085,11 @@ public MethodTypeDesc asSymbol() {
return ref1.methodTypeSymbol();
}

@Override
public boolean equalsSymbol(MethodTypeDesc desc) {
return ref1.equalsSymbol(desc);
}

@Override
public boolean equals(Object o) {
if (o == this) return true;
Expand Down Expand Up @@ -1016,6 +1123,11 @@ public String stringValue() {
return ref1.toString();
}

@Override
public boolean equalsString(String value) {
return ref1.equalsString(value);
}

@Override
public ConstantDesc constantValue() {
return stringValue();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 2025, 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
Expand Down Expand Up @@ -497,7 +497,7 @@ AbstractPoolEntry.Utf8EntryImpl maybeCloneUtf8Entry(Utf8Entry entry) {
@Override
public AbstractPoolEntry.ClassEntryImpl classEntry(Utf8Entry nameEntry) {
var ne = maybeCloneUtf8Entry(nameEntry);
return classEntry(ne, AbstractPoolEntry.isArrayDescriptor(ne));
return classEntry(ne, ne.mayBeArrayDescriptor());
}

AbstractPoolEntry.ClassEntryImpl classEntry(AbstractPoolEntry.Utf8EntryImpl ne, boolean isArray) {
Expand Down
Loading

0 comments on commit de66927

Please sign in to comment.