Skip to content

Commit

Permalink
[GR-59062] Espresso processors: support inner classes in `getInternal…
Browse files Browse the repository at this point in the history
…Name`.

PullRequest: graal/19097
  • Loading branch information
gilles-duboscq committed Oct 25, 2024
2 parents 82a556b + 9de60a7 commit 7b55a3b
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 72 deletions.
2 changes: 1 addition & 1 deletion espresso/mx.espresso/suite.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@
"requires": [
"java.compiler"
],
"javaCompliance" : "17+",
"javaCompliance" : "21+",
"checkstyle": "com.oracle.truffle.espresso",
},

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import javax.lang.model.element.Name;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.ArrayType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.tools.Diagnostic;
Expand Down Expand Up @@ -391,7 +392,7 @@ String getReturnTypeFromHost(ExecutableElement method) {
// passing the method as anchor for reporting errors instead.
return getClassFromJavaType(a, method);
}
return getInternalName(returnType.toString());
return getInternalName(returnType);
}

private List<String> getGuestTypes(ExecutableElement inner, boolean hasReceiver) {
Expand All @@ -408,7 +409,7 @@ private List<String> getGuestTypes(ExecutableElement inner, boolean hasReceiver)
if (!isReceiver && processingEnv.getTypeUtils().isSameType(parameter.asType(), staticObject.asType())) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "non-receiver StaticObject parameters require the @JavaType annotation", parameter);
}
String arg = getInternalName(parameter.asType().toString());
String arg = getInternalName(parameter.asType());
parameterTypeNames.add(arg);
}
isReceiver = false;
Expand Down Expand Up @@ -454,7 +455,7 @@ private String getClassFromJavaType(AnnotationMirror annotation, Element element
// .internalName overrides .value .
if (internalName == null || internalName.isEmpty()) {
TypeMirror value = getAnnotationValue(annotation, "value", TypeMirror.class);
internalName = getInternalName(value.toString());
internalName = getInternalName(value);
// JavaType.value = JavaType.class is used as the "no type" type, forbid accidental
// usages.
if (processingEnv.getTypeUtils().isSameType(value, javaType.asType())) {
Expand All @@ -472,69 +473,62 @@ private String getClassFromJavaType(AnnotationMirror annotation, Element element
return internalName;
}

private static String getArraySubstring(int nbDim) {
char[] chars = new char[nbDim];
Arrays.fill(chars, '[');
return new String(chars);
}

/**
* Given a qualified class name, returns the fully qualified internal name of the class.
* Given a type, returns its fully qualified internal name.
*
* In particular,
* <li>This transforms primitives (boolean, int) to their JVM signature (Z, I).
* <li>Replaces "." by "/" and, if not present, prepends a "L" an appends a ";" to reference
* types (/ex: java.lang.Object -> Ljava/lang/Object;)
* <li>If an array is passed, it is of the form "java.lang.Object[]" or "byte[][]". This
* prepends the correct number of "[" before applying this function to the name without the
* "[]". (/ex: byte[][] -> [[B)
* <li>Primitives (boolean, int) use their JVM signature (Z, I).
* <li>Use "/" rather than "." to separate packages (/ex: java.lang.Object ->
* Ljava/lang/Object;)
* <li>Array types use "[" followed by the internal name of the component type.
*/
private String getInternalName(String className) {
int arrayStart = className.indexOf("[]");
if (arrayStart != -1) {
int nbDim = 0;
boolean isOpen = false;
for (int i = arrayStart; i < className.length(); i++) {
if (isOpen) {
if (className.charAt(i) != ']') {
throw new IllegalArgumentException("Malformed class name: " + className);
}
nbDim++;
} else {
if (className.charAt(i) != '[') {
throw new IllegalArgumentException("Malformed class name: " + className);
}
}
isOpen = !isOpen;
}
return getArraySubstring(nbDim) + getInternalName(className.substring(0, arrayStart));
}

if (className.startsWith("[") || className.endsWith(";")) {
return className.replace('.', '/');
}
switch (className) {
case "boolean":
return "Z";
case "byte":
return "B";
case "char":
return "C";
case "short":
return "S";
case "int":
return "I";
case "float":
return "F";
case "double":
return "D";
case "long":
return "J";
case "void":
return "V";
}
// Reference type.
return "L" + className.replace('.', '/') + ";";
private String getInternalName(TypeMirror type) {
int arrayDims = 0;
TypeMirror elementalType = type;
while (elementalType.getKind() == TypeKind.ARRAY) {
elementalType = ((ArrayType) elementalType).getComponentType();
arrayDims += 1;
}

if (arrayDims == 0) {
return getNonArrayInternalName(type);
}
StringBuilder sb = new StringBuilder();
sb.repeat('[', arrayDims);
sb.append(getNonArrayInternalName(elementalType));
return sb.toString();
}

private String getNonArrayInternalName(TypeMirror type) {
TypeKind typeKind = type.getKind();
assert typeKind != TypeKind.ARRAY;
if (typeKind.isPrimitive() || typeKind == TypeKind.VOID) {
return switch (typeKind) {
case BOOLEAN -> "Z";
case BYTE -> "B";
case CHAR -> "C";
case SHORT -> "S";
case INT -> "I";
case FLOAT -> "F";
case DOUBLE -> "D";
case LONG -> "J";
case VOID -> "V";
default -> throw new IllegalStateException("Unexpected primitive type kind: " + typeKind);
};
}
if (typeKind != TypeKind.DECLARED) {
throw new IllegalStateException("Unexpected type kind: " + typeKind);
}
Element element = processingEnv.getTypeUtils().asElement(type);
Name binaryName = processingEnv.getElementUtils().getBinaryName((TypeElement) element);
StringBuilder sb = new StringBuilder();
sb.append("L").append(binaryName).append(';');
int idx = sb.indexOf(".", 1);
while (idx >= 0) {
sb.setCharAt(idx, '/');
idx = sb.indexOf(".", idx + 1);
}
return sb.toString();
}

private List<String> getEspressoTypes(ExecutableElement inner) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@

package com.oracle.truffle.espresso.substitutions;

import java.lang.invoke.CallSite;
import java.lang.invoke.LambdaMetafactory;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;

import com.oracle.truffle.api.dsl.Bind;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Specialization;
Expand All @@ -31,11 +37,6 @@
import com.oracle.truffle.espresso.runtime.EspressoContext;
import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;

import java.lang.invoke.CallSite;
import java.lang.invoke.LambdaMetafactory;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;

/**
* This class exists for serializable continuations. It forcibly overrides the lambda generation
* mode to request that serializability is always included. This is insufficient to enable
Expand All @@ -48,7 +49,7 @@ public final class Target_java_lang_invoke_LambdaMetafactory {
@Substitution
abstract static class Metafactory extends SubstitutionNode {
abstract @JavaType(CallSite.class) StaticObject execute(
@JavaType(internalName = "Ljava/lang/invoke/MethodHandles$Lookup;") StaticObject caller,
@JavaType(MethodHandles.Lookup.class) StaticObject caller,
@JavaType(String.class) StaticObject interfaceMethodName,
@JavaType(MethodType.class) StaticObject factoryType,
@JavaType(MethodType.class) StaticObject interfaceMethodType,
Expand All @@ -58,7 +59,7 @@ abstract static class Metafactory extends SubstitutionNode {
@Specialization
@JavaType(CallSite.class)
StaticObject doCached(
@JavaType(internalName = "Ljava/lang/invoke/MethodHandles$Lookup;") StaticObject caller,
@JavaType(MethodHandles.Lookup.class) StaticObject caller,
@JavaType(String.class) StaticObject interfaceMethodName,
@JavaType(MethodType.class) StaticObject factoryType,
@JavaType(MethodType.class) StaticObject interfaceMethodType,
Expand Down Expand Up @@ -87,15 +88,15 @@ StaticObject doCached(
@Substitution
abstract static class AltMetafactory extends SubstitutionNode {
abstract @JavaType(CallSite.class) StaticObject execute(
@JavaType(internalName = "Ljava/lang/invoke/MethodHandles$Lookup;") StaticObject caller,
@JavaType(MethodHandles.Lookup.class) StaticObject caller,
@JavaType(String.class) StaticObject interfaceMethodName,
@JavaType(MethodType.class) StaticObject factoryType,
@JavaType(Object[].class) StaticObject args);

@Specialization
@JavaType(CallSite.class)
StaticObject doCached(
@JavaType(internalName = "Ljava/lang/invoke/MethodHandles$Lookup;") StaticObject caller,
@JavaType(MethodHandles.Lookup.class) StaticObject caller,
@JavaType(String.class) StaticObject interfaceMethodName,
@JavaType(MethodType.class) StaticObject factoryType,
@JavaType(Object[].class) StaticObject args,
Expand Down

0 comments on commit 7b55a3b

Please sign in to comment.