Skip to content

Commit

Permalink
Store and retrieve method metadata for methods not included in the im…
Browse files Browse the repository at this point in the history
…age.
  • Loading branch information
loicottet committed Sep 18, 2021
1 parent 3d7a8a7 commit 2cc6bc5
Show file tree
Hide file tree
Showing 35 changed files with 2,525 additions and 182 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,17 @@ public void addObject(T object) {
entry.frequency++;
}

/**
* Returns whether the given object has been previously added to the array.
*/
public boolean contains(T object) {
if (object == null && containsNull) {
return true;
}
Entry<T> entry = map.get(object);
return entry != null;
}

/**
* Returns the index of an object in the array. The object must have been
* {@link #addObject(Object) added} before.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,22 +40,44 @@ static Executable getJavaMethod(SnippetReflectionProvider reflectionProvider, Re
return ((OriginalMethodProvider) method).getJavaMethod();
}
try {
ResolvedJavaMethod.Parameter[] parameters = method.getParameters();
Class<?>[] parameterTypes = new Class<?>[parameters.length];
ResolvedJavaType declaringClassType = method.getDeclaringClass();
for (int i = 0; i < parameterTypes.length; i++) {
parameterTypes[i] = OriginalClassProvider.getJavaClass(reflectionProvider, parameters[i].getType().resolve(declaringClassType));
}
Class<?> declaringClass = OriginalClassProvider.getJavaClass(reflectionProvider, declaringClassType);
if (method.isConstructor()) {
return declaringClass.getDeclaredConstructor(parameterTypes);
} else {
return declaringClass.getDeclaredMethod(method.getName(), parameterTypes);
}
return getJavaMethodInternal(reflectionProvider, method);
} catch (NoSuchMethodException e) {
throw AnalysisError.shouldNotReachHere();
}
}

static boolean hasJavaMethod(SnippetReflectionProvider reflectionProvider, ResolvedJavaMethod method) {
if (method instanceof OriginalMethodProvider) {
return ((OriginalMethodProvider) method).hasJavaMethod();
}
try {
getJavaMethodInternal(reflectionProvider, method);
return true;
} catch (NoSuchMethodException | LinkageError | RuntimeException e) {
/*
* These exceptions may happen anytime during the lookup, so we can't simply use the
* result of getJavaMethodInternal.
*/
return false;
}
}

static Executable getJavaMethodInternal(SnippetReflectionProvider reflectionProvider, ResolvedJavaMethod method) throws NoSuchMethodException {
ResolvedJavaMethod.Parameter[] parameters = method.getParameters();
Class<?>[] parameterTypes = new Class<?>[parameters.length];
ResolvedJavaType declaringClassType = method.getDeclaringClass();
for (int i = 0; i < parameterTypes.length; i++) {
parameterTypes[i] = OriginalClassProvider.getJavaClass(reflectionProvider, parameters[i].getType().resolve(declaringClassType));
}
Class<?> declaringClass = OriginalClassProvider.getJavaClass(reflectionProvider, declaringClassType);
if (method.isConstructor()) {
return declaringClass.getDeclaredConstructor(parameterTypes);
} else {
return declaringClass.getDeclaredMethod(method.getName(), parameterTypes);
}
}

Executable getJavaMethod();

boolean hasJavaMethod();
}
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,11 @@ public Executable getJavaMethod() {
return OriginalMethodProvider.getJavaMethod(universe.getOriginalSnippetReflection(), wrapped);
}

@Override
public boolean hasJavaMethod() {
return OriginalMethodProvider.hasJavaMethod(universe.getOriginalSnippetReflection(), wrapped);
}

/**
* Unique, per method, context insensitive invoke. The context insensitive invoke uses the
* receiver type of the method, i.e., its declaring class. Therefore this invoke will link with
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -293,10 +293,22 @@ public static void lookupCodeInfo(CodeInfo info, long ip, SimpleCodeInfoQueryRes
}

@Uninterruptible(reason = "Nonmovable object arrays are not visible to GC until installed.")
public static void setFrameInfo(CodeInfo info, NonmovableArray<Byte> encodings, NonmovableObjectArray<Object> objectConstants,
NonmovableObjectArray<Class<?>> sourceClasses, NonmovableObjectArray<String> sourceMethodNames, NonmovableObjectArray<String> names) {
public static void setFrameInfo(CodeInfo info, NonmovableArray<Byte> encodings) {
CodeInfoImpl impl = cast(info);
impl.setFrameInfoEncodings(encodings);
}

public static void setCodeInfo(CodeInfo info, NonmovableArray<Byte> index, NonmovableArray<Byte> encodings, NonmovableArray<Byte> referenceMapEncoding) {
CodeInfoImpl impl = cast(info);
impl.setCodeInfoIndex(index);
impl.setCodeInfoEncodings(encodings);
impl.setStackReferenceMapEncoding(referenceMapEncoding);
}

@Uninterruptible(reason = "Nonmovable object arrays are not visible to GC until installed.")
public static void setEncodings(CodeInfo info, NonmovableObjectArray<Object> objectConstants,
NonmovableObjectArray<Class<?>> sourceClasses, NonmovableObjectArray<String> sourceMethodNames, NonmovableObjectArray<String> names) {
CodeInfoImpl impl = cast(info);
impl.setFrameInfoObjectConstants(objectConstants);
impl.setFrameInfoSourceClasses(sourceClasses);
impl.setFrameInfoSourceMethodNames(sourceMethodNames);
Expand All @@ -307,13 +319,6 @@ public static void setFrameInfo(CodeInfo info, NonmovableArray<Byte> encodings,
}
}

public static void setCodeInfo(CodeInfo info, NonmovableArray<Byte> index, NonmovableArray<Byte> encodings, NonmovableArray<Byte> referenceMapEncoding) {
CodeInfoImpl impl = cast(info);
impl.setCodeInfoIndex(index);
impl.setCodeInfoEncodings(encodings);
impl.setStackReferenceMapEncoding(referenceMapEncoding);
}

public static Log log(CodeInfo info, Log log) {
return info.isNull() ? log.string("null") : log.string(CodeInfo.class.getName()).string("@").hex(info);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,27 @@

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

import com.oracle.svm.core.heap.ReferenceMapIndex;
// Checkstyle: stop
import java.lang.reflect.Executable;
// Checkstyle: resume
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;

import org.graalvm.compiler.api.replacements.Fold;
import org.graalvm.compiler.core.common.util.TypeConversion;
import org.graalvm.compiler.core.common.util.UnsafeArrayTypeReader;
import org.graalvm.compiler.options.Option;
import org.graalvm.nativeimage.ImageSingletons;

import com.oracle.svm.core.annotate.AlwaysInline;
import com.oracle.svm.core.annotate.Uninterruptible;
import com.oracle.svm.core.c.NonmovableArrays;
import com.oracle.svm.core.heap.ReferenceMapIndex;
import com.oracle.svm.core.hub.DynamicHub;
import com.oracle.svm.core.jdk.Target_jdk_internal_reflect_ConstantPool;
import com.oracle.svm.core.option.HostedOptionKey;
import com.oracle.svm.core.reflect.RuntimeReflectionConstructors;
import com.oracle.svm.core.util.ByteArrayReader;
import com.oracle.svm.core.util.Counter;
import com.oracle.svm.core.util.NonmovableByteArrayReader;
Expand Down Expand Up @@ -491,6 +503,138 @@ private static long advanceOffset(long entryOffset, int entryFlags) {
static CodeInfoDecoderCounters counters() {
return ImageSingletons.lookup(CodeInfoDecoderCounters.class);
}

public static Executable[] getMethodMetadata(DynamicHub declaringType) {
return getMethodMetadata(declaringType.getTypeID());
}

public static Executable[] getAllMethodMetadata() {
List<Executable> allMethods = new ArrayList<>();
for (int i = 0; i < ImageSingletons.lookup(MethodMetadataEncoding.class).getIndexEncoding().length / Integer.BYTES; ++i) {
allMethods.addAll(Arrays.asList(getMethodMetadata(i)));
}
return allMethods.toArray(new Executable[0]);
}

/**
* The metadata for methods in the image is split into two arrays: one for the index and the
* other for data. The index contains an array of integers pointing to offsets in the data, and
* indexed by type ID. The data array contains arrays of method metadata, ordered by type ID,
* such that all methods declared by a class are stored consecutively. The data for a method is
* stored in the following format:
*
* <pre>
* {
* int methodNameIndex; // index in frameInfoSourceMethodNames ("<init>" for constructors)
* int modifiers;
* int paramCount;
* {
* int paramTypeIndex; // index in frameInfoSourceClasses
* } paramTypes[paramCount];
* int returnTypeIndex; // index in frameInfoSourceClasses (void for constructors)
* int exceptionTypeCount;
* {
* int exceptionTypeIndex; // index in frameInfoSourceClasses
* } exceptionTypes[exceptionTypeCount];
* // Annotation encodings (see {@link CodeInfoEncoder})
* int annotationsLength;
* byte[] annotationsEncoding[annotationsLength];
* int parameterAnnotationsLength;
* byte[] parameterAnnotationsEncoding[parameterAnnotationsLength];
* }
* </pre>
*/
public static Executable[] getMethodMetadata(int typeID) {
CodeInfo info = CodeInfoTable.getImageCodeInfo();
MethodMetadataEncoding encoding = ImageSingletons.lookup(MethodMetadataEncoding.class);
byte[] index = encoding.getIndexEncoding();
UnsafeArrayTypeReader indexReader = UnsafeArrayTypeReader.create(index, Integer.BYTES * typeID, ByteArrayReader.supportsUnalignedMemoryAccess());
int offset = indexReader.getS4();
if (offset == MethodMetadataEncoder.NO_METHOD_METADATA) {
return new Executable[0];
}
byte[] data = ImageSingletons.lookup(MethodMetadataEncoding.class).getMethodsEncoding();
UnsafeArrayTypeReader dataReader = UnsafeArrayTypeReader.create(data, offset, ByteArrayReader.supportsUnalignedMemoryAccess());

int methodCount = dataReader.getUVInt();
Executable[] methods = new Executable[methodCount];
for (int i = 0; i < methodCount; ++i) {
int classIndex = dataReader.getSVInt();
Class<?> declaringClass = NonmovableArrays.getObject(CodeInfoAccess.getFrameInfoSourceClasses(info), classIndex);

int nameIndex = dataReader.getSVInt();
/* Interning the string to ensure JDK8 method search succeeds */
String name = NonmovableArrays.getObject(CodeInfoAccess.getFrameInfoSourceMethodNames(info), nameIndex).intern();

int modifiers = dataReader.getUVInt();

int paramCount = dataReader.getUVInt();
Class<?>[] paramTypes = new Class<?>[paramCount];
for (int j = 0; j < paramCount; ++j) {
int paramTypeIndex = dataReader.getSVInt();
paramTypes[j] = NonmovableArrays.getObject(CodeInfoAccess.getFrameInfoSourceClasses(info), paramTypeIndex);
}

int returnTypeIndex = dataReader.getSVInt();
Class<?> returnType = NonmovableArrays.getObject(CodeInfoAccess.getFrameInfoSourceClasses(info), returnTypeIndex);

int exceptionCount = dataReader.getUVInt();
Class<?>[] exceptionTypes = new Class<?>[exceptionCount];
for (int j = 0; j < exceptionCount; ++j) {
int exceptionTypeIndex = dataReader.getSVInt();
exceptionTypes[j] = NonmovableArrays.getObject(CodeInfoAccess.getFrameInfoSourceClasses(info), exceptionTypeIndex);
}

int signatureIndex = dataReader.getSVInt();
String signature = NonmovableArrays.getObject(CodeInfoAccess.getFrameInfoSourceMethodNames(info), signatureIndex);

int annotationsLength = dataReader.getUVInt();
byte[] annotations = new byte[annotationsLength];
for (int j = 0; j < annotationsLength; ++j) {
annotations[j] = (byte) dataReader.getS1();
}

int parameterAnnotationsLength = dataReader.getUVInt();
byte[] parameterAnnotations = new byte[parameterAnnotationsLength];
for (int j = 0; j < parameterAnnotationsLength; ++j) {
parameterAnnotations[j] = (byte) dataReader.getS1();
}

int typeAnnotationsLength = dataReader.getUVInt();
byte[] typeAnnotations = new byte[typeAnnotationsLength];
for (int j = 0; j < typeAnnotationsLength; ++j) {
typeAnnotations[j] = (byte) dataReader.getS1();
}

boolean parameterDataPresent = dataReader.getU1() == 1;
String[] parameterNames = null;
int[] parameterModifiers = null;
if (parameterDataPresent) {
int parameterCount = dataReader.getUVInt();
parameterNames = new String[parameterCount];
parameterModifiers = new int[parameterCount];
for (int j = 0; j < paramCount; ++j) {
int parameterNameIndex = dataReader.getSVInt();
parameterNames[j] = NonmovableArrays.getObject(CodeInfoAccess.getFrameInfoSourceMethodNames(info), parameterNameIndex);
parameterModifiers[j] = dataReader.getS4();
}
}

if (name.equals("<init>")) {
assert returnType == void.class;
methods[i] = ImageSingletons.lookup(RuntimeReflectionConstructors.class).newConstructor(declaringClass, paramTypes, exceptionTypes, modifiers, signature,
annotations, parameterAnnotations, typeAnnotations, parameterNames, parameterModifiers);
} else {
methods[i] = ImageSingletons.lookup(RuntimeReflectionConstructors.class).newMethod(declaringClass, name, paramTypes, returnType, exceptionTypes, modifiers, signature,
annotations, parameterAnnotations, null, typeAnnotations, parameterNames, parameterModifiers);
}
}
return methods;
}

public static Target_jdk_internal_reflect_ConstantPool getMetadataPseudoConstantPool() {
return new Target_jdk_internal_reflect_ConstantPool();
}
}

class CodeInfoDecoderCounters {
Expand Down
Loading

0 comments on commit 2cc6bc5

Please sign in to comment.