Skip to content

Commit 85579c3

Browse files
committed
Store and retrieve method metadata for methods not included in the image.
1 parent c0621e1 commit 85579c3

34 files changed

+2480
-165
lines changed

compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/FrequencyEncoder.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,17 @@ public void addObject(T object) {
8989
entry.frequency++;
9090
}
9191

92+
/**
93+
* Returns whether the given object has been previously added to the array.
94+
*/
95+
public boolean contains(T object) {
96+
if (object == null && containsNull) {
97+
return true;
98+
}
99+
Entry<T> entry = map.get(object);
100+
return entry != null;
101+
}
102+
92103
/**
93104
* Returns the index of an object in the array. The object must have been
94105
* {@link #addObject(Object) added} before.

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/OriginalMethodProvider.java

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -40,22 +40,40 @@ static Executable getJavaMethod(SnippetReflectionProvider reflectionProvider, Re
4040
return ((OriginalMethodProvider) method).getJavaMethod();
4141
}
4242
try {
43-
ResolvedJavaMethod.Parameter[] parameters = method.getParameters();
44-
Class<?>[] parameterTypes = new Class<?>[parameters.length];
45-
ResolvedJavaType declaringClassType = method.getDeclaringClass();
46-
for (int i = 0; i < parameterTypes.length; i++) {
47-
parameterTypes[i] = OriginalClassProvider.getJavaClass(reflectionProvider, parameters[i].getType().resolve(declaringClassType));
48-
}
49-
Class<?> declaringClass = OriginalClassProvider.getJavaClass(reflectionProvider, declaringClassType);
50-
if (method.isConstructor()) {
51-
return declaringClass.getDeclaredConstructor(parameterTypes);
52-
} else {
53-
return declaringClass.getDeclaredMethod(method.getName(), parameterTypes);
54-
}
43+
return getJavaMethodInternal(reflectionProvider, method);
5544
} catch (NoSuchMethodException e) {
5645
throw AnalysisError.shouldNotReachHere();
5746
}
5847
}
5948

49+
static boolean hasJavaMethod(SnippetReflectionProvider reflectionProvider, ResolvedJavaMethod method) {
50+
if (method instanceof OriginalMethodProvider) {
51+
return ((OriginalMethodProvider) method).hasJavaMethod();
52+
}
53+
try {
54+
getJavaMethodInternal(reflectionProvider, method);
55+
return true;
56+
} catch (NoSuchMethodException | LinkageError | RuntimeException e) {
57+
return false;
58+
}
59+
}
60+
61+
static Executable getJavaMethodInternal(SnippetReflectionProvider reflectionProvider, ResolvedJavaMethod method) throws NoSuchMethodException {
62+
ResolvedJavaMethod.Parameter[] parameters = method.getParameters();
63+
Class<?>[] parameterTypes = new Class<?>[parameters.length];
64+
ResolvedJavaType declaringClassType = method.getDeclaringClass();
65+
for (int i = 0; i < parameterTypes.length; i++) {
66+
parameterTypes[i] = OriginalClassProvider.getJavaClass(reflectionProvider, parameters[i].getType().resolve(declaringClassType));
67+
}
68+
Class<?> declaringClass = OriginalClassProvider.getJavaClass(reflectionProvider, declaringClassType);
69+
if (method.isConstructor()) {
70+
return declaringClass.getDeclaredConstructor(parameterTypes);
71+
} else {
72+
return declaringClass.getDeclaredMethod(method.getName(), parameterTypes);
73+
}
74+
}
75+
6076
Executable getJavaMethod();
77+
78+
boolean hasJavaMethod();
6179
}

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisMethod.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,11 @@ public Executable getJavaMethod() {
554554
return OriginalMethodProvider.getJavaMethod(universe.getOriginalSnippetReflection(), wrapped);
555555
}
556556

557+
@Override
558+
public boolean hasJavaMethod() {
559+
return OriginalMethodProvider.hasJavaMethod(universe.getOriginalSnippetReflection(), wrapped);
560+
}
561+
557562
/**
558563
* Unique, per method, context insensitive invoke. The context insensitive invoke uses the
559564
* receiver type of the method, i.e., its declaring class. Therefore this invoke will link with

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoAccess.java

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -293,10 +293,22 @@ public static void lookupCodeInfo(CodeInfo info, long ip, SimpleCodeInfoQueryRes
293293
}
294294

295295
@Uninterruptible(reason = "Nonmovable object arrays are not visible to GC until installed.")
296-
public static void setFrameInfo(CodeInfo info, NonmovableArray<Byte> encodings, NonmovableObjectArray<Object> objectConstants,
297-
NonmovableObjectArray<Class<?>> sourceClasses, NonmovableObjectArray<String> sourceMethodNames, NonmovableObjectArray<String> names) {
296+
public static void setFrameInfo(CodeInfo info, NonmovableArray<Byte> encodings) {
298297
CodeInfoImpl impl = cast(info);
299298
impl.setFrameInfoEncodings(encodings);
299+
}
300+
301+
public static void setCodeInfo(CodeInfo info, NonmovableArray<Byte> index, NonmovableArray<Byte> encodings, NonmovableArray<Byte> referenceMapEncoding) {
302+
CodeInfoImpl impl = cast(info);
303+
impl.setCodeInfoIndex(index);
304+
impl.setCodeInfoEncodings(encodings);
305+
impl.setStackReferenceMapEncoding(referenceMapEncoding);
306+
}
307+
308+
@Uninterruptible(reason = "Nonmovable object arrays are not visible to GC until installed.")
309+
public static void setEncodings(CodeInfo info, NonmovableObjectArray<Object> objectConstants,
310+
NonmovableObjectArray<Class<?>> sourceClasses, NonmovableObjectArray<String> sourceMethodNames, NonmovableObjectArray<String> names) {
311+
CodeInfoImpl impl = cast(info);
300312
impl.setFrameInfoObjectConstants(objectConstants);
301313
impl.setFrameInfoSourceClasses(sourceClasses);
302314
impl.setFrameInfoSourceMethodNames(sourceMethodNames);
@@ -307,13 +319,6 @@ public static void setFrameInfo(CodeInfo info, NonmovableArray<Byte> encodings,
307319
}
308320
}
309321

310-
public static void setCodeInfo(CodeInfo info, NonmovableArray<Byte> index, NonmovableArray<Byte> encodings, NonmovableArray<Byte> referenceMapEncoding) {
311-
CodeInfoImpl impl = cast(info);
312-
impl.setCodeInfoIndex(index);
313-
impl.setCodeInfoEncodings(encodings);
314-
impl.setStackReferenceMapEncoding(referenceMapEncoding);
315-
}
316-
317322
public static Log log(CodeInfo info, Log log) {
318323
return info.isNull() ? log.string("null") : log.string(CodeInfo.class.getName()).string("@").hex(info);
319324
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoDecoder.java

Lines changed: 129 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,25 @@
2626

2727
import static com.oracle.svm.core.util.VMError.shouldNotReachHere;
2828

29-
import com.oracle.svm.core.heap.ReferenceMapIndex;
29+
// Checkstyle: stop
30+
import java.lang.reflect.Executable;
31+
// Checkstyle: resume
32+
3033
import org.graalvm.compiler.api.replacements.Fold;
3134
import org.graalvm.compiler.core.common.util.TypeConversion;
35+
import org.graalvm.compiler.core.common.util.UnsafeArrayTypeReader;
3236
import org.graalvm.compiler.options.Option;
3337
import org.graalvm.nativeimage.ImageSingletons;
3438

39+
import com.oracle.svm.core.SubstrateUtil;
3540
import com.oracle.svm.core.annotate.AlwaysInline;
3641
import com.oracle.svm.core.annotate.Uninterruptible;
42+
import com.oracle.svm.core.c.NonmovableArrays;
43+
import com.oracle.svm.core.heap.ReferenceMapIndex;
44+
import com.oracle.svm.core.hub.DynamicHub;
45+
import com.oracle.svm.core.jdk.Target_jdk_internal_reflect_ConstantPool;
3746
import com.oracle.svm.core.option.HostedOptionKey;
47+
import com.oracle.svm.core.reflect.RuntimeReflectionConstructors;
3848
import com.oracle.svm.core.util.ByteArrayReader;
3949
import com.oracle.svm.core.util.Counter;
4050
import com.oracle.svm.core.util.NonmovableByteArrayReader;
@@ -491,6 +501,124 @@ private static long advanceOffset(long entryOffset, int entryFlags) {
491501
static CodeInfoDecoderCounters counters() {
492502
return ImageSingletons.lookup(CodeInfoDecoderCounters.class);
493503
}
504+
505+
/**
506+
* The metadata for methods in the image is split into two arrays: one for the index and the
507+
* other for data. The index contains an array of integers pointing to offsets in the data, and
508+
* indexed by type ID. The data array contains arrays of method metadata, ordered by type ID,
509+
* such that all methods declared by a class are stored consecutively. The data for a method is
510+
* stored in the following format:
511+
*
512+
* <pre>
513+
* {
514+
* int methodNameIndex; // index in frameInfoSourceMethodNames ("<init>" for constructors)
515+
* int modifiers;
516+
* int paramCount;
517+
* {
518+
* int paramTypeIndex; // index in frameInfoSourceClasses
519+
* } paramTypes[paramCount];
520+
* int returnTypeIndex; // index in frameInfoSourceClasses (void for constructors)
521+
* int exceptionTypeCount;
522+
* {
523+
* int exceptionTypeIndex; // index in frameInfoSourceClasses
524+
* } exceptionTypes[exceptionTypeCount];
525+
* // Annotation encodings (see {@link CodeInfoEncoder})
526+
* int annotationsLength;
527+
* byte[] annotationsEncoding[annotationsLength];
528+
* int parameterAnnotationsLength;
529+
* byte[] parameterAnnotationsEncoding[parameterAnnotationsLength];
530+
* }
531+
* </pre>
532+
*/
533+
public static Executable[] getMethodMetadata(DynamicHub declaringType) {
534+
CodeInfo info = CodeInfoTable.getImageCodeInfo();
535+
MethodMetadataEncoding encoding = ImageSingletons.lookup(MethodMetadataEncoding.class);
536+
byte[] index = encoding.getIndexEncoding();
537+
UnsafeArrayTypeReader indexReader = UnsafeArrayTypeReader.create(index, Integer.BYTES * declaringType.getTypeID(), ByteArrayReader.supportsUnalignedMemoryAccess());
538+
int offset = indexReader.getS4();
539+
if (offset == MethodMetadataEncoder.NO_METHOD_METADATA) {
540+
return new Executable[0];
541+
}
542+
byte[] data = ImageSingletons.lookup(MethodMetadataEncoding.class).getMethodsEncoding();
543+
UnsafeArrayTypeReader dataReader = UnsafeArrayTypeReader.create(data, offset, ByteArrayReader.supportsUnalignedMemoryAccess());
544+
545+
int methodCount = dataReader.getUVInt();
546+
Executable[] methods = new Executable[methodCount];
547+
Class<?> declaringClass = SubstrateUtil.cast(declaringType, Class.class);
548+
for (int i = 0; i < methodCount; ++i) {
549+
int nameIndex = dataReader.getSVInt();
550+
/* Interning the string to ensure JDK8 method search succeeds */
551+
String name = NonmovableArrays.getObject(CodeInfoAccess.getFrameInfoSourceMethodNames(info), nameIndex).intern();
552+
553+
int modifiers = dataReader.getUVInt();
554+
555+
int paramCount = dataReader.getUVInt();
556+
Class<?>[] paramTypes = new Class<?>[paramCount];
557+
for (int j = 0; j < paramCount; ++j) {
558+
int paramTypeIndex = dataReader.getSVInt();
559+
paramTypes[j] = NonmovableArrays.getObject(CodeInfoAccess.getFrameInfoSourceClasses(info), paramTypeIndex);
560+
}
561+
562+
int returnTypeIndex = dataReader.getSVInt();
563+
Class<?> returnType = NonmovableArrays.getObject(CodeInfoAccess.getFrameInfoSourceClasses(info), returnTypeIndex);
564+
565+
int exceptionCount = dataReader.getUVInt();
566+
Class<?>[] exceptionTypes = new Class<?>[exceptionCount];
567+
for (int j = 0; j < exceptionCount; ++j) {
568+
int exceptionTypeIndex = dataReader.getSVInt();
569+
exceptionTypes[j] = NonmovableArrays.getObject(CodeInfoAccess.getFrameInfoSourceClasses(info), exceptionTypeIndex);
570+
}
571+
572+
int signatureIndex = dataReader.getSVInt();
573+
String signature = NonmovableArrays.getObject(CodeInfoAccess.getFrameInfoSourceMethodNames(info), signatureIndex);
574+
575+
int annotationsLength = dataReader.getUVInt();
576+
byte[] annotations = new byte[annotationsLength];
577+
for (int j = 0; j < annotationsLength; ++j) {
578+
annotations[j] = (byte) dataReader.getS1();
579+
}
580+
581+
int parameterAnnotationsLength = dataReader.getUVInt();
582+
byte[] parameterAnnotations = new byte[parameterAnnotationsLength];
583+
for (int j = 0; j < parameterAnnotationsLength; ++j) {
584+
parameterAnnotations[j] = (byte) dataReader.getS1();
585+
}
586+
587+
int typeAnnotationsLength = dataReader.getUVInt();
588+
byte[] typeAnnotations = new byte[typeAnnotationsLength];
589+
for (int j = 0; j < typeAnnotationsLength; ++j) {
590+
typeAnnotations[j] = (byte) dataReader.getS1();
591+
}
592+
593+
boolean parameterDataPresent = dataReader.getU1() == 1;
594+
String[] parameterNames = null;
595+
int[] parameterModifiers = null;
596+
if (parameterDataPresent) {
597+
int parameterCount = dataReader.getUVInt();
598+
parameterNames = new String[parameterCount];
599+
parameterModifiers = new int[parameterCount];
600+
for (int j = 0; j < paramCount; ++j) {
601+
int parameterNameIndex = dataReader.getSVInt();
602+
parameterNames[j] = NonmovableArrays.getObject(CodeInfoAccess.getFrameInfoSourceMethodNames(info), parameterNameIndex);
603+
parameterModifiers[j] = dataReader.getS4();
604+
}
605+
}
606+
607+
if (name.equals("<init>")) {
608+
assert returnType == void.class;
609+
methods[i] = ImageSingletons.lookup(RuntimeReflectionConstructors.class).newConstructor(declaringClass, paramTypes, exceptionTypes, modifiers, signature,
610+
annotations, parameterAnnotations, typeAnnotations, parameterNames, parameterModifiers);
611+
} else {
612+
methods[i] = ImageSingletons.lookup(RuntimeReflectionConstructors.class).newMethod(declaringClass, name, paramTypes, returnType, exceptionTypes, modifiers, signature,
613+
annotations, parameterAnnotations, null, typeAnnotations, parameterNames, parameterModifiers);
614+
}
615+
}
616+
return methods;
617+
}
618+
619+
public static Target_jdk_internal_reflect_ConstantPool getMetadataPseudoConstantPool() {
620+
return new Target_jdk_internal_reflect_ConstantPool();
621+
}
494622
}
495623

496624
class CodeInfoDecoderCounters {

0 commit comments

Comments
 (0)