Skip to content

Commit 2cc6bc5

Browse files
committed
Store and retrieve method metadata for methods not included in the image.
1 parent 3d7a8a7 commit 2cc6bc5

File tree

35 files changed

+2525
-182
lines changed

35 files changed

+2525
-182
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: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -40,22 +40,44 @@ 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+
/*
58+
* These exceptions may happen anytime during the lookup, so we can't simply use the
59+
* result of getJavaMethodInternal.
60+
*/
61+
return false;
62+
}
63+
}
64+
65+
static Executable getJavaMethodInternal(SnippetReflectionProvider reflectionProvider, ResolvedJavaMethod method) throws NoSuchMethodException {
66+
ResolvedJavaMethod.Parameter[] parameters = method.getParameters();
67+
Class<?>[] parameterTypes = new Class<?>[parameters.length];
68+
ResolvedJavaType declaringClassType = method.getDeclaringClass();
69+
for (int i = 0; i < parameterTypes.length; i++) {
70+
parameterTypes[i] = OriginalClassProvider.getJavaClass(reflectionProvider, parameters[i].getType().resolve(declaringClassType));
71+
}
72+
Class<?> declaringClass = OriginalClassProvider.getJavaClass(reflectionProvider, declaringClassType);
73+
if (method.isConstructor()) {
74+
return declaringClass.getDeclaredConstructor(parameterTypes);
75+
} else {
76+
return declaringClass.getDeclaredMethod(method.getName(), parameterTypes);
77+
}
78+
}
79+
6080
Executable getJavaMethod();
81+
82+
boolean hasJavaMethod();
6183
}

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: 145 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,27 @@
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+
import java.util.Arrays;
33+
import java.util.ArrayList;
34+
import java.util.List;
35+
3036
import org.graalvm.compiler.api.replacements.Fold;
3137
import org.graalvm.compiler.core.common.util.TypeConversion;
38+
import org.graalvm.compiler.core.common.util.UnsafeArrayTypeReader;
3239
import org.graalvm.compiler.options.Option;
3340
import org.graalvm.nativeimage.ImageSingletons;
3441

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

496640
class CodeInfoDecoderCounters {

0 commit comments

Comments
 (0)