|
25 | 25 |
|
26 | 26 | package com.oracle.svm.hosted.webimage.util;
|
27 | 27 |
|
28 |
| -import java.lang.annotation.Annotation; |
29 |
| -import java.lang.reflect.GenericSignatureFormatError; |
30 | 28 | import java.lang.reflect.Method;
|
31 |
| -import java.lang.reflect.Modifier; |
32 | 29 | import java.util.Arrays;
|
33 | 30 | import java.util.HashSet;
|
34 | 31 | import java.util.LinkedHashSet;
|
|
42 | 39 |
|
43 | 40 | import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider;
|
44 | 41 | import com.oracle.graal.pointsto.infrastructure.OriginalMethodProvider;
|
| 42 | +import com.oracle.svm.hosted.ImageClassLoader; |
| 43 | +import com.oracle.svm.util.ReflectionUtil; |
45 | 44 |
|
46 | 45 | import jdk.vm.ci.meta.MetaAccessProvider;
|
47 | 46 | import jdk.vm.ci.meta.ResolvedJavaMethod;
|
@@ -169,92 +168,42 @@ private static void findAllInterfaces(Class<?> type, LinkedHashSet<Class<?>> int
|
169 | 168 | }
|
170 | 169 | }
|
171 | 170 |
|
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<>(); |
212 | 176 |
|
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); |
229 | 181 | }
|
| 182 | + |
| 183 | + return methods; |
230 | 184 | }
|
231 | 185 |
|
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) { |
235 | 192 | return;
|
236 | 193 | }
|
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 |
| - } |
246 | 194 |
|
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); |
250 | 200 | }
|
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); |
257 | 204 | }
|
258 |
| - return true; |
| 205 | + |
| 206 | + findBaseMethods(originalMethod, clazz.getSuperclass(), jsOverridenMethodSet); |
259 | 207 | }
|
| 208 | + |
260 | 209 | }
|
0 commit comments