|
25 | 25 | package com.oracle.graal.pointsto;
|
26 | 26 |
|
27 | 27 | import java.io.PrintWriter;
|
28 |
| -import java.lang.reflect.Constructor; |
29 |
| -import java.lang.reflect.Field; |
30 |
| -import java.lang.reflect.Method; |
31 |
| -import java.util.Arrays; |
32 | 28 | import java.util.Collections;
|
33 | 29 | import java.util.List;
|
34 | 30 | import java.util.function.Function;
|
35 |
| -import java.util.stream.Stream; |
36 | 31 |
|
37 | 32 | import org.graalvm.nativeimage.hosted.Feature;
|
38 | 33 |
|
39 |
| -import com.oracle.graal.pointsto.ClassInclusionPolicy.LayeredBaseImageInclusionPolicy; |
| 34 | +import com.oracle.graal.pointsto.ClassInclusionPolicy.SharedLayerImageInclusionPolicy; |
40 | 35 | import com.oracle.graal.pointsto.api.HostVM;
|
41 | 36 | import com.oracle.graal.pointsto.api.PointstoOptions;
|
42 | 37 | import com.oracle.graal.pointsto.constraints.UnsupportedFeatures;
|
|
68 | 63 | import jdk.vm.ci.code.BytecodeFrame;
|
69 | 64 | import jdk.vm.ci.code.BytecodePosition;
|
70 | 65 | import jdk.vm.ci.meta.ConstantReflectionProvider;
|
| 66 | +import jdk.vm.ci.meta.ResolvedJavaField; |
71 | 67 | import jdk.vm.ci.meta.ResolvedJavaMethod;
|
| 68 | +import jdk.vm.ci.meta.ResolvedJavaType; |
72 | 69 |
|
73 | 70 | /**
|
74 | 71 | * This abstract class is shared between Reachability and Points-to. It contains generic methods
|
@@ -103,6 +100,8 @@ public abstract class AbstractAnalysisEngine implements BigBang {
|
103 | 100 | protected final Timer analysisTimer;
|
104 | 101 | protected final Timer verifyHeapTimer;
|
105 | 102 | protected final ClassInclusionPolicy classInclusionPolicy;
|
| 103 | + private static final ResolvedJavaMethod[] NO_METHODS = new ResolvedJavaMethod[]{}; |
| 104 | + private static final ResolvedJavaField[] NO_FIELDS = new ResolvedJavaField[]{}; |
106 | 105 |
|
107 | 106 | @SuppressWarnings("this-escape")
|
108 | 107 | public AbstractAnalysisEngine(OptionValues options, AnalysisUniverse universe, HostVM hostVM, AnalysisMetaAccess metaAccess, SnippetReflectionProvider snippetReflectionProvider,
|
@@ -208,7 +207,7 @@ private boolean analysisModified() {
|
208 | 207 | * After the analysis reaches a stable state check if the shadow heap contains all
|
209 | 208 | * objects reachable from roots. If this leads to analysis state changes, an additional
|
210 | 209 | * analysis iteration will be run.
|
211 |
| - * |
| 210 | + * |
212 | 211 | * We reuse the analysis executor, which at this point should be in before-start state:
|
213 | 212 | * the analysis finished and it re-initialized the executor for the next iteration. The
|
214 | 213 | * verifier controls the life cycle of the executor: it starts it and then waits until
|
@@ -259,7 +258,7 @@ public void profileConstantObject(AnalysisType type) {
|
259 | 258 | }
|
260 | 259 |
|
261 | 260 | public boolean isBaseLayerAnalysisEnabled() {
|
262 |
| - return classInclusionPolicy instanceof LayeredBaseImageInclusionPolicy; |
| 261 | + return classInclusionPolicy instanceof SharedLayerImageInclusionPolicy; |
263 | 262 | }
|
264 | 263 |
|
265 | 264 | @Override
|
@@ -352,30 +351,58 @@ public final boolean executorIsStarted() {
|
352 | 351 | }
|
353 | 352 |
|
354 | 353 | @Override
|
355 |
| - public void registerTypeForBaseImage(Class<?> cls) { |
356 |
| - if (getOrDefault(cls, classInclusionPolicy::isClassIncluded, false)) { |
357 |
| - classInclusionPolicy.includeClass(cls); |
358 |
| - Stream.concat(Arrays.stream(getOrDefault(cls, Class::getDeclaredConstructors, new Constructor<?>[0])), Arrays.stream(getOrDefault(cls, Class::getDeclaredMethods, new Method[0]))) |
359 |
| - .filter(classInclusionPolicy::isMethodIncluded) |
360 |
| - .forEach(classInclusionPolicy::includeMethod); |
361 |
| - Arrays.stream(getOrDefault(cls, Class::getDeclaredFields, new Field[0])) |
362 |
| - .filter(classInclusionPolicy::isFieldIncluded) |
363 |
| - .forEach(classInclusionPolicy::includeField); |
| 354 | + public void tryRegisterTypeForBaseImage(ResolvedJavaType type) { |
| 355 | + if (tryApply(type, classInclusionPolicy::isOriginalTypeIncluded, false)) { |
| 356 | + classInclusionPolicy.includeType(type); |
| 357 | + ResolvedJavaMethod[] constructors = tryApply(type, t -> t.getDeclaredConstructors(false), NO_METHODS); |
| 358 | + ResolvedJavaMethod[] methods = tryApply(type, t -> t.getDeclaredMethods(false), NO_METHODS); |
| 359 | + for (ResolvedJavaMethod[] executables : List.of(constructors, methods)) { |
| 360 | + for (ResolvedJavaMethod executable : executables) { |
| 361 | + if (classInclusionPolicy.isOriginalMethodIncluded(executable)) { |
| 362 | + classInclusionPolicy.includeMethod(executable); |
| 363 | + } |
| 364 | + } |
| 365 | + } |
| 366 | + ResolvedJavaField[] instanceFields = tryApply(type, t -> t.getInstanceFields(false), NO_FIELDS); |
| 367 | + ResolvedJavaField[] staticFields = tryApply(type, ResolvedJavaType::getStaticFields, NO_FIELDS); |
| 368 | + for (ResolvedJavaField[] fields : List.of(instanceFields, staticFields)) { |
| 369 | + for (ResolvedJavaField field : fields) { |
| 370 | + if (classInclusionPolicy.isOriginalFieldIncluded(field)) { |
| 371 | + classInclusionPolicy.includeField(field); |
| 372 | + } |
| 373 | + } |
| 374 | + } |
364 | 375 | }
|
365 | 376 | }
|
366 | 377 |
|
367 | 378 | @Override
|
368 |
| - public void registerMethodForBaseImage(AnalysisMethod method) { |
369 |
| - if (classInclusionPolicy.isMethodIncluded(method)) { |
| 379 | + public void tryRegisterMethodForBaseImage(AnalysisMethod method) { |
| 380 | + if (classInclusionPolicy.isAnalysisMethodIncluded(method)) { |
370 | 381 | classInclusionPolicy.includeMethod(method);
|
371 | 382 | }
|
372 | 383 | }
|
373 | 384 |
|
374 |
| - public static <T, U> U getOrDefault(T cls, Function<T, U> getMembers, U backup) { |
| 385 | + @Override |
| 386 | + public void tryRegisterFieldForBaseImage(AnalysisField field) { |
| 387 | + if (classInclusionPolicy.isAnalysisFieldIncluded(field)) { |
| 388 | + classInclusionPolicy.includeField(field); |
| 389 | + } |
| 390 | + } |
| 391 | + |
| 392 | + /** |
| 393 | + * Applies {@code function} to {@code type} and returns the result or, if |
| 394 | + * {@link NoClassDefFoundError} or {@link IncompatibleClassChangeError} thrown when applying the |
| 395 | + * function, returns {@code fallback}. |
| 396 | + * <p> |
| 397 | + * The error handling allows for querying members (fields, methods or constructors) of a class |
| 398 | + * where a member signature refers to a type that is unresolvable due to an incomplete class |
| 399 | + * path. Such resolution errors need to be ignored when building a shared layer. |
| 400 | + */ |
| 401 | + private static <U> U tryApply(ResolvedJavaType type, Function<ResolvedJavaType, U> function, U fallback) { |
375 | 402 | try {
|
376 |
| - return getMembers.apply(cls); |
| 403 | + return function.apply(type); |
377 | 404 | } catch (NoClassDefFoundError | IncompatibleClassChangeError e) {
|
378 |
| - return backup; |
| 405 | + return fallback; |
379 | 406 | }
|
380 | 407 | }
|
381 | 408 |
|
|
0 commit comments