Skip to content

Commit 4115586

Browse files
committed
Reimplement ReflectUtil#findBaseMethodsOfJSAnnotated
Is significantly faster (~200ms -> ~30ms) and simpler than before. Instead of looping through all classes, simply looks up all @js annotated methods and gathers the methods they override.
1 parent 302c4ef commit 4115586

File tree

1 file changed

+30
-81
lines changed
  • web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/util

1 file changed

+30
-81
lines changed

web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/util/ReflectUtil.java

Lines changed: 30 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,7 @@
2525

2626
package com.oracle.svm.hosted.webimage.util;
2727

28-
import java.lang.annotation.Annotation;
29-
import java.lang.reflect.GenericSignatureFormatError;
3028
import java.lang.reflect.Method;
31-
import java.lang.reflect.Modifier;
3229
import java.util.Arrays;
3330
import java.util.HashSet;
3431
import java.util.LinkedHashSet;
@@ -42,6 +39,8 @@
4239

4340
import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider;
4441
import com.oracle.graal.pointsto.infrastructure.OriginalMethodProvider;
42+
import com.oracle.svm.hosted.ImageClassLoader;
43+
import com.oracle.svm.util.ReflectionUtil;
4544

4645
import jdk.vm.ci.meta.MetaAccessProvider;
4746
import jdk.vm.ci.meta.ResolvedJavaMethod;
@@ -169,92 +168,42 @@ private static void findAllInterfaces(Class<?> type, LinkedHashSet<Class<?>> int
169168
}
170169
}
171170

172-
public static Set<Method> findBaseMethodsOfJSAnnotated(List<Class<?>> allClasses) {
173-
HashSet<Method> set = new HashSet<>();
174-
for (Class<?> cls : allClasses) {
175-
Method[] declaredMethods;
176-
try {
177-
declaredMethods = cls.getDeclaredMethods();
178-
} catch (NoClassDefFoundError e) {
179-
// Some classes may be missing on the class path, but these will not be used by the
180-
// image.
181-
continue;
182-
} catch (VerifyError | ClassFormatError | ClassCircularityError | IllegalAccessError e) {
183-
// Skip the corrupted class encountered during the analysis.
184-
System.err.printf(
185-
"Skipped JS annotated base methods lookup for class %s.%nError: %s, Message: %s.%n",
186-
cls.getName(),
187-
e.getClass().getName(),
188-
e.getMessage());
189-
continue;
190-
}
191-
for (Method method : declaredMethods) {
192-
Annotation jsAnnotation;
193-
try {
194-
jsAnnotation = method.getAnnotation(JS.class);
195-
} catch (GenericSignatureFormatError e) {
196-
// Skip the corrupted method encountered during the analysis.
197-
System.err.printf(
198-
"Skipped JS annotated base methods lookup for method %s::%s.%nError: %s, Message: %s.%n",
199-
method.getDeclaringClass().getName(),
200-
method.getName(),
201-
e.getClass().getName(),
202-
e.getMessage());
203-
continue;
204-
}
205-
if (jsAnnotation != null) {
206-
markBaseMethods(method, cls, set, new HashSet<>());
207-
}
208-
}
209-
}
210-
return set;
211-
}
171+
/**
172+
* Finds all methods annotated with {@link JS} as well as all the methods it overrides.
173+
*/
174+
public static Set<Method> findBaseMethodsOfJSAnnotated(ImageClassLoader imageClassLoader) {
175+
Set<Method> methods = new HashSet<>();
212176

213-
private static void markBaseMethods(Method method, Class<?> type, HashSet<Method> set, HashSet<Class<?>> seen) {
214-
if (seen.contains(type)) {
215-
// We already saw this type -- we skip it to avoid traversing an interface type twice.
216-
return;
217-
}
218-
seen.add(type);
219-
if (!set.contains(method)) {
220-
set.add(method);
221-
}
222-
if (Modifier.isPrivate(method.getModifiers()) || Modifier.isStatic(method.getModifiers())) {
223-
// Private and static methods cannot override anything.
224-
return;
225-
}
226-
resolveAndMarkBaseMethods(method, type.getSuperclass(), set, seen);
227-
for (Class<?> i : type.getInterfaces()) {
228-
resolveAndMarkBaseMethods(method, i, set, seen);
177+
List<Method> annotatedMethods = imageClassLoader.findAnnotatedMethods(JS.class);
178+
179+
for (Method annotatedMethod : annotatedMethods) {
180+
findBaseMethods(annotatedMethod, annotatedMethod.getDeclaringClass(), methods);
229181
}
182+
183+
return methods;
230184
}
231185

232-
private static void resolveAndMarkBaseMethods(Method method, Class<?> type, HashSet<Method> set, HashSet<Class<?>> seen) {
233-
if (type == null) {
234-
// We reached Object's superclass.
186+
/**
187+
* Finds all methods the given {@code originalMethod} overrides (including itself) from the
188+
* given class upwards and adds them to the given set.
189+
*/
190+
private static void findBaseMethods(Method originalMethod, Class<?> clazz, Set<Method> jsOverridenMethodSet) {
191+
if (clazz == null) {
235192
return;
236193
}
237-
for (Method declaredMethod : type.getDeclaredMethods()) {
238-
if (isOverriding(method, declaredMethod)) {
239-
markBaseMethods(declaredMethod, type, set, seen);
240-
return;
241-
}
242-
}
243-
// There is no override in the current class, continue using the subtype's method.
244-
markBaseMethods(method, type, set, seen);
245-
}
246194

247-
private static boolean isOverriding(Method method, Method baseMethod) {
248-
if (method.getParameterCount() != baseMethod.getParameterCount() || !method.getName().equals(baseMethod.getName())) {
249-
return false;
195+
// This is either the same method as originalMethod or a method it overrides.
196+
Method baseMethod = ReflectionUtil.lookupMethod(true, clazz, originalMethod.getName(), originalMethod.getParameterTypes());
197+
198+
if (baseMethod != null) {
199+
jsOverridenMethodSet.add(baseMethod);
250200
}
251-
Class<?>[] parameters = method.getParameterTypes();
252-
Class<?>[] baseParameters = baseMethod.getParameterTypes();
253-
for (int i = 0; i < parameters.length; i++) {
254-
if (!parameters[i].equals(baseParameters[i])) {
255-
return false;
256-
}
201+
202+
for (Class<?> clazzInterface : clazz.getInterfaces()) {
203+
findBaseMethods(originalMethod, clazzInterface, jsOverridenMethodSet);
257204
}
258-
return true;
205+
206+
findBaseMethods(originalMethod, clazz.getSuperclass(), jsOverridenMethodSet);
259207
}
208+
260209
}

0 commit comments

Comments
 (0)