|
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