Skip to content

Commit

Permalink
Merge pull request #47 from dmlloyd/fix-jdk
Browse files Browse the repository at this point in the history
Fix breakage from JDK updates
  • Loading branch information
dmlloyd authored Jul 3, 2024
2 parents 903becf + 6372a0a commit ccb933b
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 59 deletions.
1 change: 1 addition & 0 deletions process-patch.pl
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
s[ClassDesc\.ofInternalName][ExtraClassDesc.ofInternalName]g;
s[java(.)lang.classfile][io$1github$1dmlloyd$1classfile]g;
s[jdk(.)internal.classfile][io$1github$1dmlloyd$1classfile]g;
s[jdk(.)internal.constant][io$1github$1dmlloyd$1classfile$1extras$1constant]g;
s[src/java\.base/share/classes][src/main/java]g;
print $_;
}
2 changes: 1 addition & 1 deletion src/main/java/io/github/dmlloyd/classfile/ClassFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
import io.github.dmlloyd.classfile.instruction.ExceptionCatch;
import java.util.List;
import static java.util.Objects.requireNonNull;
import static jdk.internal.constant.ConstantUtils.CD_module_info;
import static io.github.dmlloyd.classfile.extras.constant.ConstantUtils.CD_module_info;
import io.github.dmlloyd.classfile.extras.PreviewFeature;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,39 +24,95 @@
*/
package io.github.dmlloyd.classfile.extras.constant;

import static java.util.Objects.requireNonNull;

import java.lang.constant.ClassDesc;
import java.lang.constant.Constable;
import java.lang.constant.ConstantDesc;
import io.github.dmlloyd.classfile.extras.ExtraConstantDescs;
import java.lang.constant.MethodTypeDesc;
import java.lang.invoke.MethodType;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import io.github.dmlloyd.classfile.extras.ExtraConstantDescs;

/**
* Helper methods for the implementation of {@code java.lang.constant}.
*/
class ConstantUtils {
public final class ConstantUtils {
/** an empty constant descriptor */
public static final ConstantDesc[] EMPTY_CONSTANTDESC = new ConstantDesc[0];
static final ClassDesc[] EMPTY_CLASSDESC = new ClassDesc[0];
static final Constable[] EMPTY_CONSTABLE = new Constable[0];
static final int MAX_ARRAY_TYPE_DESC_DIMENSIONS = 255;
public static final ClassDesc[] EMPTY_CLASSDESC = new ClassDesc[0];
public static final int MAX_ARRAY_TYPE_DESC_DIMENSIONS = 255;
public static final ClassDesc CD_module_info = binaryNameToDesc("module-info");

private static final Set<String> pointyNames = Set.of(ExtraConstantDescs.INIT_NAME, ExtraConstantDescs.CLASS_INIT_NAME);

/** No instantiation */
private ConstantUtils() {}

// Note:
// Non-JDK users should create their own utilities that wrap
// {@code .describeConstable().orElseThrow()} calls;
// these xxDesc methods has undefined and unsafe exceptional
// behavior, so they are not suitable as public APIs.

/**
* Creates a {@linkplain ClassDesc} from a pre-validated binary name
* for a class or interface type. Validated version of {@link
* ClassDesc#of(String)}.
*
* @param binaryName a binary name
*/
public static ClassDesc binaryNameToDesc(String binaryName) {
return ClassDesc.of(binaryName);
}

/**
* Creates a ClassDesc from a Class object, requires that this class
* can always be described nominally, i.e. this class is not a
* hidden class or interface or an array with a hidden component
* type.
*/
public static ClassDesc classDesc(Class<?> type) {
return type.describeConstable().orElseThrow();
}

/**
* Creates a ClassDesc from a Class object representing a non-hidden
* class or interface or an array type with a non-hidden component type.
*/
public static ClassDesc referenceClassDesc(Class<?> type) {
return type.describeConstable().orElseThrow();
}

/**
* Creates a MethodTypeDesc from a MethodType object, requires that
* the type can be described nominally, i.e. all of its return
* type and parameter types can be described nominally.
*/
public static MethodTypeDesc methodTypeDesc(MethodType type) {
return type.describeConstable().orElseThrow();
}

/**
* Creates a MethodTypeDesc from return class and parameter
* class objects, requires that all of them can be described nominally.
* This version is mainly useful for working with Method objects.
*/
public static MethodTypeDesc methodTypeDesc(Class<?> returnType, Class<?>[] parameterTypes) {
return MethodType.methodType(returnType, parameterTypes).describeConstable().orElseThrow();
}

/**
* Validates the correctness of a binary class name. In particular checks for the presence of
* invalid characters in the name.
*
* @param name the class name
* @return the class name passed if valid
* @throws IllegalArgumentException if the class name is invalid
* @throws NullPointerException if class name is {@code null}
*/
static String validateBinaryClassName(String name) {
for (int i=0; i<name.length(); i++) {
public static String validateBinaryClassName(String name) {
for (int i = 0; i < name.length(); i++) {
char ch = name.charAt(i);
if (ch == ';' || ch == '[' || ch == '/')
throw new IllegalArgumentException("Invalid class name: " + name);
Expand All @@ -65,21 +121,22 @@ static String validateBinaryClassName(String name) {
}

/**
* Validates the correctness of an internal class name.
* In particular checks for the presence of invalid characters in the name.
*
* @param name the class name
* @return the class name passed if valid
* @throws IllegalArgumentException if the class name is invalid
*/
static String validateInternalClassName(String name) {
for (int i=0; i<name.length(); i++) {
char ch = name.charAt(i);
if (ch == ';' || ch == '[' || ch == '.')
throw new IllegalArgumentException("Invalid class name: " + name);
}
return name;
}
* Validates the correctness of an internal class name.
* In particular checks for the presence of invalid characters in the name.
*
* @param name the class name
* @return the class name passed if valid
* @throws IllegalArgumentException if the class name is invalid
* @throws NullPointerException if class name is {@code null}
*/
public static String validateInternalClassName(String name) {
for (int i = 0; i < name.length(); i++) {
char ch = name.charAt(i);
if (ch == ';' || ch == '[' || ch == '.')
throw new IllegalArgumentException("Invalid class name: " + name);
}
return name;
}

/**
* Validates the correctness of a binary package name.
Expand All @@ -92,7 +149,7 @@ static String validateInternalClassName(String name) {
* @throws NullPointerException if the package name is {@code null}
*/
public static String validateBinaryPackageName(String name) {
for (int i=0; i<name.length(); i++) {
for (int i = 0; i < name.length(); i++) {
char ch = name.charAt(i);
if (ch == ';' || ch == '[' || ch == '/')
throw new IllegalArgumentException("Invalid package name: " + name);
Expand All @@ -111,7 +168,7 @@ public static String validateBinaryPackageName(String name) {
* @throws NullPointerException if the package name is {@code null}
*/
public static String validateInternalPackageName(String name) {
for (int i=0; i<name.length(); i++) {
for (int i = 0; i < name.length(); i++) {
char ch = name.charAt(i);
if (ch == ';' || ch == '[' || ch == '.')
throw new IllegalArgumentException("Invalid package name: " + name);
Expand All @@ -132,7 +189,7 @@ public static String validateInternalPackageName(String name) {
* @throws NullPointerException if the module name is {@code null}
*/
public static String validateModuleName(String name) {
for (int i=name.length() - 1; i >= 0; i--) {
for (int i = name.length() - 1; i >= 0; i--) {
char ch = name.charAt(i);
if ((ch >= '\u0000' && ch <= '\u001F')
|| ((ch == '\\' || ch == ':' || ch =='@') && (i == 0 || name.charAt(--i) != '\\')))
Expand All @@ -147,13 +204,17 @@ public static String validateModuleName(String name) {
* @param name the name of the member
* @return the name passed if valid
* @throws IllegalArgumentException if the member name is invalid
* @throws NullPointerException if the member name is {@code null}
*/
public static String validateMemberName(String name, boolean method) {
requireNonNull(name);
if (name.length() == 0)
int len = name.length();
if (len == 0)
throw new IllegalArgumentException("zero-length member name");
for (int i=0; i<name.length(); i++) {
for (int i = 0; i < len; i++) {
char ch = name.charAt(i);
// common case fast-path
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))
continue;
if (ch == '.' || ch == ';' || ch == '[' || ch == '/')
throw new IllegalArgumentException("Invalid member name: " + name);
if (method && (ch == '<' || ch == '>')) {
Expand All @@ -164,31 +225,27 @@ public static String validateMemberName(String name, boolean method) {
return name;
}

static void validateClassOrInterface(ClassDesc classDesc) {
public static void validateClassOrInterface(ClassDesc classDesc) {
if (!classDesc.isClassOrInterface())
throw new IllegalArgumentException("not a class or interface type: " + classDesc);
}

static int arrayDepth(String descriptorString) {
public static int arrayDepth(String descriptorString) {
int depth = 0;
while (descriptorString.charAt(depth) == '[')
depth++;
return depth;
}

static String binaryToInternal(String name) {
public static String binaryToInternal(String name) {
return name.replace('.', '/');
}

static String internalToBinary(String name) {
public static String internalToBinary(String name) {
return name.replace('/', '.');
}

static String dropLastChar(String s) {
return s.substring(0, s.length() - 1);
}

static String dropFirstAndLastChar(String s) {
public static String dropFirstAndLastChar(String s) {
return s.substring(1, s.length() - 1);
}

Expand All @@ -200,10 +257,10 @@ static String dropFirstAndLastChar(String s) {
* @return the list of types
* @throws IllegalArgumentException if the descriptor string is not valid
*/
static List<String> parseMethodDescriptor(String descriptor) {
public static List<ClassDesc> parseMethodDescriptor(String descriptor) {
int cur = 0, end = descriptor.length();
ArrayList<String> ptypes = new ArrayList<>();
ptypes.add(null); //placeholder for return type
ArrayList<ClassDesc> ptypes = new ArrayList<>();
ptypes.add(null); // placeholder for return type

if (cur >= end || descriptor.charAt(cur) != '(')
throw new IllegalArgumentException("Bad method descriptor: " + descriptor);
Expand All @@ -213,7 +270,7 @@ static List<String> parseMethodDescriptor(String descriptor) {
int len = skipOverFieldSignature(descriptor, cur, end, false);
if (len == 0)
throw new IllegalArgumentException("Bad method descriptor: " + descriptor);
ptypes.add(descriptor.substring(cur, cur + len));
ptypes.add(resolveClassDesc(descriptor, cur, len));
cur += len;
}
if (cur >= end)
Expand All @@ -223,10 +280,14 @@ static List<String> parseMethodDescriptor(String descriptor) {
int rLen = skipOverFieldSignature(descriptor, cur, end, true);
if (rLen == 0 || cur + rLen != end)
throw new IllegalArgumentException("Bad method descriptor: " + descriptor);
ptypes.set(0, descriptor.substring(cur, cur + rLen));
ptypes.set(0, resolveClassDesc(descriptor, cur, rLen));
return ptypes;
}

private static ClassDesc resolveClassDesc(String descriptor, int start, int len) {
return ClassDesc.of(descriptor.substring(start, start + len));
}

private static final char JVM_SIGNATURE_ARRAY = '[';
private static final char JVM_SIGNATURE_BYTE = 'B';
private static final char JVM_SIGNATURE_CHAR = 'C';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
import static java.lang.constant.ConstantDescs.CD_Object;
import static io.github.dmlloyd.classfile.ClassFile.*;
import static java.util.Objects.requireNonNull;
import static jdk.internal.constant.ConstantUtils.referenceClassDesc;

/**
* Class hierarchy resolution framework is answering questions about classes assignability, common classes ancestor and whether the class represents an interface.
Expand Down Expand Up @@ -247,7 +246,7 @@ public ClassHierarchyInfo getClassInfo(ClassDesc cd) {
}

return cl.isInterface() ? ClassHierarchyInfo.ofInterface()
: ClassHierarchyInfo.ofClass(referenceClassDesc(cl.getSuperclass()));
: ClassHierarchyInfo.ofClass(cl.getSuperclass().describeConstable().orElseThrow());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
import io.github.dmlloyd.classfile.constantpool.ConstantPoolBuilder;
import io.github.dmlloyd.classfile.constantpool.InvokeDynamicEntry;
import io.github.dmlloyd.classfile.constantpool.MemberRefEntry;

import java.io.Serializable;
import java.lang.constant.ClassDesc;
import java.lang.constant.MethodTypeDesc;
import java.nio.ByteBuffer;
Expand All @@ -45,7 +47,6 @@
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import jdk.internal.constant.ReferenceClassDescImpl;

import static io.github.dmlloyd.classfile.ClassFile.*;
import static java.lang.constant.ConstantDescs.*;
Expand Down Expand Up @@ -1248,14 +1249,14 @@ private static record Type(int tag, ClassDesc sym, int bci) {
//frequently used types to reduce footprint
static final Type OBJECT_TYPE = referenceType(CD_Object),
THROWABLE_TYPE = referenceType(CD_Throwable),
INT_ARRAY_TYPE = referenceType(ReferenceClassDescImpl.ofValidated("[I")),
BOOLEAN_ARRAY_TYPE = referenceType(ReferenceClassDescImpl.ofValidated("[Z")),
BYTE_ARRAY_TYPE = referenceType(ReferenceClassDescImpl.ofValidated("[B")),
CHAR_ARRAY_TYPE = referenceType(ReferenceClassDescImpl.ofValidated("[C")),
SHORT_ARRAY_TYPE = referenceType(ReferenceClassDescImpl.ofValidated("[S")),
LONG_ARRAY_TYPE = referenceType(ReferenceClassDescImpl.ofValidated("[J")),
DOUBLE_ARRAY_TYPE = referenceType(ReferenceClassDescImpl.ofValidated("[D")),
FLOAT_ARRAY_TYPE = referenceType(ReferenceClassDescImpl.ofValidated("[F")),
INT_ARRAY_TYPE = referenceType(int[].class.describeConstable().orElseThrow()),
BOOLEAN_ARRAY_TYPE = referenceType(boolean[].class.describeConstable().orElseThrow()),
BYTE_ARRAY_TYPE = referenceType(byte[].class.describeConstable().orElseThrow()),
CHAR_ARRAY_TYPE = referenceType(char[].class.describeConstable().orElseThrow()),
SHORT_ARRAY_TYPE = referenceType(short[].class.describeConstable().orElseThrow()),
LONG_ARRAY_TYPE = referenceType(long[].class.describeConstable().orElseThrow()),
DOUBLE_ARRAY_TYPE = referenceType(double[].class.describeConstable().orElseThrow()),
FLOAT_ARRAY_TYPE = referenceType(float[].class.describeConstable().orElseThrow()),
STRING_TYPE = referenceType(CD_String),
CLASS_TYPE = referenceType(CD_Class),
METHOD_HANDLE_TYPE = referenceType(CD_MethodHandle),
Expand Down Expand Up @@ -1320,8 +1321,8 @@ Type mergeComponentFrom(Type from, ClassHierarchyImpl context) {
}
}

private static final ClassDesc CD_Cloneable = ReferenceClassDescImpl.ofValidated("Ljava/lang/Cloneable;");
private static final ClassDesc CD_Serializable = ReferenceClassDescImpl.ofValidated("Ljava/io/Serializable;");
private static final ClassDesc CD_Cloneable = Cloneable.class.describeConstable().orElseThrow();
private static final ClassDesc CD_Serializable = Serializable.class.describeConstable().orElseThrow();

private Type mergeReferenceFrom(Type from, ClassHierarchyImpl context) {
if (from == NULL_TYPE) {
Expand Down

0 comments on commit ccb933b

Please sign in to comment.