diff --git a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/PointsToAnalyzer.java b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/PointsToAnalyzer.java index 2bbbca0263a0..bbb53fa0d632 100644 --- a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/PointsToAnalyzer.java +++ b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/PointsToAnalyzer.java @@ -38,19 +38,11 @@ import java.util.ArrayList; import java.util.List; -import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; -import jdk.graal.compiler.debug.DebugContext; -import jdk.graal.compiler.debug.Indent; -import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; -import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugins; -import jdk.graal.compiler.options.OptionValues; -import jdk.graal.compiler.phases.util.Providers; -import jdk.graal.compiler.printer.GraalDebugHandlersFactory; -import jdk.graal.compiler.word.WordTypes; import org.graalvm.nativeimage.hosted.Feature; import com.oracle.graal.pointsto.AnalysisObjectScanningObserver; import com.oracle.graal.pointsto.AnalysisPolicy; +import com.oracle.graal.pointsto.ClassInclusionPolicy; import com.oracle.graal.pointsto.api.PointstoOptions; import com.oracle.graal.pointsto.flow.context.bytecode.BytecodeSensitiveAnalysisPolicy; import com.oracle.graal.pointsto.heap.HeapSnapshotVerifier; @@ -79,6 +71,15 @@ import com.oracle.svm.util.ModuleSupport; import com.oracle.svm.util.ReflectionUtil; +import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; +import jdk.graal.compiler.debug.DebugContext; +import jdk.graal.compiler.debug.Indent; +import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; +import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugins; +import jdk.graal.compiler.options.OptionValues; +import jdk.graal.compiler.phases.util.Providers; +import jdk.graal.compiler.printer.GraalDebugHandlersFactory; +import jdk.graal.compiler.word.WordTypes; import jdk.vm.ci.amd64.AMD64Kind; import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; import jdk.vm.ci.meta.JavaKind; @@ -151,8 +152,9 @@ private PointsToAnalyzer(String mainEntryClass, OptionValues options) { originalProviders.getPlatformConfigurationProvider(), aMetaAccessExtensionProvider, originalProviders.getLoopsDataProvider()); standaloneHost.initializeProviders(aProviders); analysisName = getAnalysisName(mainEntryClass); + ClassInclusionPolicy classInclusionPolicy = new ClassInclusionPolicy.DefaultAllInclusionPolicy("Included in the base image"); bigbang = new StandalonePointsToAnalysis(options, aUniverse, standaloneHost, aMetaAccess, snippetReflection, aConstantReflection, aProviders.getWordTypes(), debugContext, - new TimerCollection()); + new TimerCollection(), classInclusionPolicy); standaloneHost.setImageName(analysisName); aUniverse.setBigBang(bigbang); ImageHeap heap = new ImageHeap(); diff --git a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/StandalonePointsToAnalysis.java b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/StandalonePointsToAnalysis.java index fb985be004ea..1dc26544b7aa 100644 --- a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/StandalonePointsToAnalysis.java +++ b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/StandalonePointsToAnalysis.java @@ -29,6 +29,7 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import com.oracle.graal.pointsto.ClassInclusionPolicy; import com.oracle.graal.pointsto.PointsToAnalysis; import com.oracle.graal.pointsto.api.HostVM; import com.oracle.graal.pointsto.constraints.UnsupportedFeatures; @@ -48,8 +49,8 @@ public class StandalonePointsToAnalysis extends PointsToAnalysis { private final Set addedClinits = ConcurrentHashMap.newKeySet(); public StandalonePointsToAnalysis(OptionValues options, AnalysisUniverse universe, HostVM hostVM, AnalysisMetaAccess metaAccess, SnippetReflectionProvider snippetReflectionProvider, - ConstantReflectionProvider constantReflectionProvider, WordTypes wordTypes, DebugContext debugContext, TimerCollection timerCollection) { - super(options, universe, hostVM, metaAccess, snippetReflectionProvider, constantReflectionProvider, wordTypes, new UnsupportedFeatures(), debugContext, timerCollection); + ConstantReflectionProvider constantReflectionProvider, WordTypes wordTypes, DebugContext debugContext, TimerCollection timerCollection, ClassInclusionPolicy classInclusionPolicy) { + super(options, universe, hostVM, metaAccess, snippetReflectionProvider, constantReflectionProvider, wordTypes, new UnsupportedFeatures(), debugContext, timerCollection, classInclusionPolicy); } @Override diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AbstractAnalysisEngine.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AbstractAnalysisEngine.java index 035cb2da64f0..4deb02bf6041 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AbstractAnalysisEngine.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AbstractAnalysisEngine.java @@ -25,12 +25,15 @@ package com.oracle.graal.pointsto; import java.io.PrintWriter; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.function.Function; +import java.util.stream.Stream; import org.graalvm.nativeimage.hosted.Feature; +import com.oracle.graal.pointsto.ClassInclusionPolicy.LayeredBaseImageInclusionPolicy; import com.oracle.graal.pointsto.api.HostVM; import com.oracle.graal.pointsto.api.PointstoOptions; import com.oracle.graal.pointsto.constraints.UnsupportedFeatures; @@ -97,11 +100,12 @@ public abstract class AbstractAnalysisEngine implements BigBang { protected final Timer processFeaturesTimer; protected final Timer analysisTimer; protected final Timer verifyHeapTimer; + protected final ClassInclusionPolicy classInclusionPolicy; @SuppressWarnings("this-escape") public AbstractAnalysisEngine(OptionValues options, AnalysisUniverse universe, HostVM hostVM, AnalysisMetaAccess metaAccess, SnippetReflectionProvider snippetReflectionProvider, ConstantReflectionProvider constantReflectionProvider, WordTypes wordTypes, UnsupportedFeatures unsupportedFeatures, DebugContext debugContext, - TimerCollection timerCollection) { + TimerCollection timerCollection, ClassInclusionPolicy classInclusionPolicy) { this.options = options; this.universe = universe; this.debugHandlerFactories = Collections.singletonList(new GraalDebugHandlersFactory(snippetReflectionProvider)); @@ -123,6 +127,8 @@ public AbstractAnalysisEngine(OptionValues options, AnalysisUniverse universe, H this.snippetReflectionProvider = snippetReflectionProvider; this.constantReflectionProvider = constantReflectionProvider; this.wordTypes = wordTypes; + classInclusionPolicy.setBigBang(this); + this.classInclusionPolicy = classInclusionPolicy; } /** @@ -257,6 +263,10 @@ public void profileConstantObject(AnalysisType type) { } } + public boolean isBaseLayerAnalysisEnabled() { + return classInclusionPolicy instanceof LayeredBaseImageInclusionPolicy; + } + @Override public OptionValues getOptions() { return options; @@ -346,6 +356,19 @@ public final boolean executorIsStarted() { return executor.isStarted(); } + @Override + public void registerTypeForBaseImage(Class cls) { + if (classInclusionPolicy.isClassIncluded(cls)) { + classInclusionPolicy.includeClass(cls); + Stream.concat(Arrays.stream(cls.getDeclaredConstructors()), Arrays.stream(cls.getDeclaredMethods())) + .filter(classInclusionPolicy::isMethodIncluded) + .forEach(classInclusionPolicy::includeMethod); + Arrays.stream(cls.getDeclaredFields()) + .filter(classInclusionPolicy::isFieldIncluded) + .forEach(classInclusionPolicy::includeField); + } + } + /** * Provide a non-null position. Some flows like newInstance and invoke require a non-null * position, for others is just better. The constructed position is best-effort, i.e., it diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/BigBang.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/BigBang.java index af914b935320..612ad177b792 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/BigBang.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/BigBang.java @@ -136,4 +136,8 @@ default void afterAnalysis() { default AnalysisMethod fallbackResolveConcreteMethod(AnalysisType resolvingType, AnalysisMethod method) { return null; } + + default void registerTypeForBaseImage(Class cls) { + + } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ClassInclusionPolicy.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ClassInclusionPolicy.java new file mode 100644 index 000000000000..5e1c8bdb0963 --- /dev/null +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ClassInclusionPolicy.java @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.pointsto; + +import java.lang.reflect.Executable; +import java.lang.reflect.Field; +import java.lang.reflect.Member; +import java.lang.reflect.Modifier; + +import org.graalvm.nativeimage.AnnotationAccess; + +import com.oracle.graal.pointsto.meta.AnalysisMethod; + +import jdk.graal.compiler.api.replacements.Fold; + +/** + * Policy used to determine which classes, methods and fields need to be included in the image when + * the {@code IncludeAllFromPath} and/or {@code IncludeAllFromModule} options are specified + * depending on the configuration. + */ +public abstract class ClassInclusionPolicy { + protected BigBang bb; + protected final Object reason; + + public ClassInclusionPolicy(Object reason) { + this.reason = reason; + } + + public void setBigBang(BigBang bb) { + this.bb = bb; + } + + /** + * Determine if the given class needs to be included in the image according to the policy. + */ + public abstract boolean isClassIncluded(Class cls); + + /** + * Determine if the given method needs to be included in the image according to the policy. + */ + public boolean isMethodIncluded(Executable method) { + /* + * Methods annotated with @Fold should not be included in the base image as they must be + * inlined. An extension image would inline the method as well and would not use the method + * from the base image. + */ + return !AnnotationAccess.isAnnotationPresent(bb.getMetaAccess().lookupJavaMethod(method), Fold.class); + } + + /** + * Determine if the given field needs to be included in the image according to the policy. + */ + public boolean isFieldIncluded(Field field) { + if (!bb.getHostVM().platformSupported(field)) { + return false; + } + return bb.getHostVM().isFieldIncluded(bb, field); + } + + /** + * Includes the given class in the image. + */ + public void includeClass(Class cls) { + /* + * Those classes cannot be registered as allocated as they cannot be instantiated. They are + * instead registered as reachable as they can still have methods or fields that could be + * used by an extension image. + */ + if (Modifier.isAbstract(cls.getModifiers()) || cls.isInterface() || cls.isPrimitive()) { + bb.getMetaAccess().lookupJavaType(cls).registerAsReachable(reason); + } else { + bb.getMetaAccess().lookupJavaType(cls).registerAsAllocated(reason); + } + } + + /** + * Includes the given method in the image. + */ + public abstract void includeMethod(Executable method); + + /** + * Includes the given field in the image. + */ + public void includeField(Field field) { + bb.postTask(debug -> bb.addRootField(field)); + } + + /** + * The analysis for the base layer of a layered image assumes that any method that is reachable + * using the base java access rules can be an entry point. An upper layer does not have access + * to the packages from a lower layer. Thus, only the public classes with their public and + * protected inner classes and methods can be accessed by an upper layer. + *

+ * Protected elements from a final or sealed class cannot be accessed as an upper layer cannot + * create a new class that extends the final or sealed class. + *

+ * All the fields are included disregarding access rules as a missing field would cause issues + * in the object layout. + */ + public static class LayeredBaseImageInclusionPolicy extends ClassInclusionPolicy { + public LayeredBaseImageInclusionPolicy(Object reason) { + super(reason); + } + + @Override + public boolean isClassIncluded(Class cls) { + Class enclosingClass = cls.getEnclosingClass(); + int classModifiers = cls.getModifiers(); + if (enclosingClass != null) { + return isAccessible(enclosingClass, classModifiers) && isClassIncluded(enclosingClass); + } else { + return Modifier.isPublic(classModifiers); + } + } + + @Override + public boolean isMethodIncluded(Executable method) { + return !Modifier.isAbstract(method.getModifiers()) && isAccessible(method) && super.isMethodIncluded(method); + } + + @Override + public void includeMethod(Executable method) { + bb.postTask(debug -> { + /* + * Non-abstract methods from an abstract class or default methods from an interface + * are not registered as implementation invoked by the analysis because their + * declaring class cannot be marked as instantiated and AnalysisType.getTypeFlow + * only includes instantiated types (see TypeFlow.addObserver). For now, to ensure + * those methods are included in the image, they are manually registered as + * implementation invoked. + */ + Class declaringClass = method.getDeclaringClass(); + if (!Modifier.isAbstract(method.getModifiers()) && (declaringClass.isInterface() || Modifier.isAbstract(declaringClass.getModifiers()))) { + AnalysisMethod analysisMethod = bb.getMetaAccess().lookupJavaMethod(method); + analysisMethod.registerAsDirectRootMethod(reason); + analysisMethod.registerAsImplementationInvoked(reason); + } + bb.forcedAddRootMethod(method, false, reason); + }); + } + } + + /** + * The default inclusion policy. Includes all classes and methods. Including all fields causes + * issues at the moment, so the same rules as for the {@link LayeredBaseImageInclusionPolicy} + * are used. + */ + public static class DefaultAllInclusionPolicy extends ClassInclusionPolicy { + public DefaultAllInclusionPolicy(Object reason) { + super(reason); + } + + @Override + public boolean isClassIncluded(Class cls) { + return true; + } + + @Override + public void includeMethod(Executable method) { + bb.postTask(debug -> bb.addRootMethod(method, false, reason)); + } + } + + protected boolean isAccessible(Member member) { + Class cls = member.getDeclaringClass(); + int modifiers = member.getModifiers(); + return isAccessible(cls, modifiers); + } + + protected boolean isAccessible(Class cls, int modifiers) { + return Modifier.isPublic(modifiers) || (!Modifier.isFinal(cls.getModifiers()) && !cls.isSealed() && Modifier.isProtected(modifiers)); + } +} diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java index 5def0656c55f..b73e61f43d62 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java @@ -52,6 +52,7 @@ import com.oracle.graal.pointsto.flow.InvokeTypeFlow; import com.oracle.graal.pointsto.flow.MethodFlowsGraph; import com.oracle.graal.pointsto.flow.MethodFlowsGraphInfo; +import com.oracle.graal.pointsto.flow.MethodTypeFlow; import com.oracle.graal.pointsto.flow.MethodTypeFlowBuilder; import com.oracle.graal.pointsto.flow.OffsetLoadTypeFlow.AbstractUnsafeLoadTypeFlow; import com.oracle.graal.pointsto.flow.OffsetStoreTypeFlow.AbstractUnsafeStoreTypeFlow; @@ -120,8 +121,9 @@ public abstract class PointsToAnalysis extends AbstractAnalysisEngine { @SuppressWarnings("this-escape") public PointsToAnalysis(OptionValues options, AnalysisUniverse universe, HostVM hostVM, AnalysisMetaAccess metaAccess, SnippetReflectionProvider snippetReflectionProvider, - ConstantReflectionProvider constantReflectionProvider, WordTypes wordTypes, UnsupportedFeatures unsupportedFeatures, DebugContext debugContext, TimerCollection timerCollection) { - super(options, universe, hostVM, metaAccess, snippetReflectionProvider, constantReflectionProvider, wordTypes, unsupportedFeatures, debugContext, timerCollection); + ConstantReflectionProvider constantReflectionProvider, WordTypes wordTypes, UnsupportedFeatures unsupportedFeatures, DebugContext debugContext, TimerCollection timerCollection, + ClassInclusionPolicy classInclusionPolicy) { + super(options, universe, hostVM, metaAccess, snippetReflectionProvider, constantReflectionProvider, wordTypes, unsupportedFeatures, debugContext, timerCollection, classInclusionPolicy); this.typeFlowTimer = timerCollection.createTimer("(typeflow)"); this.trackPrimitiveValues = PointstoOptions.TrackPrimitiveValues.getValue(options); this.anyPrimitiveSourceTypeFlow = new AnyPrimitiveSourceTypeFlow(null, null); @@ -315,6 +317,26 @@ public AnalysisMethod addRootMethod(Executable method, boolean invokeSpecial, Ob return addRootMethod(metaAccess.lookupJavaMethod(method), invokeSpecial, reason, otherRoots); } + @Override + public AnalysisMethod forcedAddRootMethod(Executable method, boolean invokeSpecial, Object reason, MultiMethod.MultiMethodKey... otherRoots) { + AnalysisError.guarantee(isBaseLayerAnalysisEnabled()); + PointsToAnalysisMethod analysisMethod = assertPointsToAnalysisMethod(metaAccess.lookupJavaMethod(method)); + postTask(ignore -> { + MethodTypeFlow typeFlow = analysisMethod.getTypeFlow(); + /* + * Calling MethodTypeFlow#ensureFlowsGraphCreated ensures that the method is not + * optimized away by the analysis. + */ + typeFlow.ensureFlowsGraphCreated(this, null); + /* + * Saturating all the parameters of the method allows to enforce that no optimization is + * performed using the types of the parameters of the methods. + */ + typeFlow.getMethodFlowsGraph().saturateAllParameters(this); + }); + return addRootMethod(analysisMethod, invokeSpecial, reason, otherRoots); + } + @Override @SuppressWarnings("try") public AnalysisMethod addRootMethod(AnalysisMethod aMethod, boolean invokeSpecial, Object reason, MultiMethod.MultiMethodKey... otherRoots) { @@ -455,14 +477,29 @@ public AnalysisType addRootField(Class clazz, String fieldName) { for (ResolvedJavaField javaField : type.getInstanceFields(true)) { AnalysisField field = (AnalysisField) javaField; if (field.getName().equals(fieldName)) { - field.registerAsAccessed("root field"); - processRootField(type, field); - return field.getType(); + return addRootField(type, field); } } throw shouldNotReachHere("field not found: " + fieldName); } + @Override + public AnalysisType addRootField(Field field) { + AnalysisField analysisField = getMetaAccess().lookupJavaField(field); + if (analysisField.isStatic()) { + return addRootStaticField(analysisField); + } else { + AnalysisType analysisType = getMetaAccess().lookupJavaType(field.getDeclaringClass()); + return addRootField(analysisType, analysisField); + } + } + + private AnalysisType addRootField(AnalysisType type, AnalysisField field) { + field.registerAsAccessed("root field"); + processRootField(type, field); + return field.getType(); + } + private void processRootField(AnalysisType type, AnalysisField field) { JavaKind storageKind = field.getStorageKind(); if (isSupportedJavaKind(storageKind)) { @@ -487,23 +524,27 @@ public AnalysisType addRootStaticField(Class clazz, String fieldName) { try { reflectField = clazz.getField(fieldName); AnalysisField field = metaAccess.lookupJavaField(reflectField); - field.registerAsAccessed("static root field"); - JavaKind storageKind = field.getStorageKind(); - if (isSupportedJavaKind(storageKind)) { - if (storageKind.isObject()) { - TypeFlow fieldFlow = field.getType().getTypeFlow(this, true); - fieldFlow.addUse(this, field.getStaticFieldFlow()); - } else { - field.getStaticFieldFlow().addState(this, TypeState.anyPrimitiveState()); - } - } - return field.getType(); + return addRootStaticField(field); } catch (NoSuchFieldException e) { throw shouldNotReachHere("field not found: " + fieldName); } } + private AnalysisType addRootStaticField(AnalysisField field) { + field.registerAsAccessed("static root field"); + JavaKind storageKind = field.getStorageKind(); + if (isSupportedJavaKind(storageKind)) { + if (storageKind.isObject()) { + TypeFlow fieldFlow = field.getType().getTypeFlow(this, true); + fieldFlow.addUse(this, field.getStaticFieldFlow()); + } else { + field.getStaticFieldFlow().addState(this, TypeState.anyPrimitiveState()); + } + } + return field.getType(); + } + @Override public void checkUserLimitations() { } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ReachabilityAnalysis.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ReachabilityAnalysis.java index 9838508c96cf..ba0296d28a84 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ReachabilityAnalysis.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ReachabilityAnalysis.java @@ -25,6 +25,7 @@ package com.oracle.graal.pointsto; import java.lang.reflect.Executable; +import java.lang.reflect.Field; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; @@ -58,6 +59,8 @@ public interface ReachabilityAnalysis { */ AnalysisType addRootField(Class clazz, String fieldName); + AnalysisType addRootField(Field field); + /** * Registers the method as root. Must be an {@link MultiMethod#ORIGINAL_METHOD}. * @@ -87,6 +90,16 @@ public interface ReachabilityAnalysis { */ AnalysisMethod addRootMethod(Executable method, boolean invokeSpecial, Object reason, MultiMethod.MultiMethodKey... otherRoots); + /** + * In addition to register the method as a root, saturate all the parameters. Meant to be used + * under the {@code LayeredBaseImageAnalysis} option to ensure the invocation is replaced by the + * context-insensitive invoke. + * + * @see ReachabilityAnalysis#addRootMethod(AnalysisMethod, boolean, Object, + * MultiMethod.MultiMethodKey...) + */ + AnalysisMethod forcedAddRootMethod(Executable method, boolean invokeSpecial, Object reason, MultiMethod.MultiMethodKey... otherRoots); + default void registerAsFrozenUnsafeAccessed(AnalysisField field) { field.setUnsafeFrozenTypeState(true); } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/HostVM.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/HostVM.java index 9ec95cd96b31..da1233406b79 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/HostVM.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/HostVM.java @@ -27,6 +27,7 @@ package com.oracle.graal.pointsto.api; import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; @@ -313,6 +314,10 @@ public HostedProviders getProviders(MultiMethod.MultiMethodKey key) { return providers; } + public boolean isFieldIncluded(BigBang bb, Field field) { + return true; + } + /** * Helpers to determine what analysis actions should be taken for a given Multi-Method version. */ diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodFlowsGraph.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodFlowsGraph.java index 81ee33673555..f2051b871222 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodFlowsGraph.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodFlowsGraph.java @@ -439,4 +439,34 @@ void updateInternalState(GraphKind newGraphKind) { linearizeGraph(true); } } + + /** + * Saturates all the formal parameters of the graph. This is expected to be used by layered base + * image analysis. + */ + public void saturateAllParameters(PointsToAnalysis bb) { + AnalysisError.guarantee(bb.isBaseLayerAnalysisEnabled()); + for (TypeFlow parameter : getParameters()) { + if (parameter != null && parameter.canSaturate()) { + parameter.onSaturated(bb); + } + } + + /* + * Even if saturating only parameters already ensures that all code from the base layer is + * reached, it is still necessary to saturate flows from miscEntryFlows, as the extension + * image can introduce new types and methods. For example, an ActualReturnTypeFlow returning + * from an AbstractVirtualInvokeTypeFlow would not be saturated only by saturating + * parameters, as there is no direct use/observer link between the two flows. While all the + * types returned by the implementations from the base image will be in the TypeState, a + * different type might be returned by an implementation introduced by the extension image. + */ + if (miscEntryFlows != null) { + for (TypeFlow miscEntryFlow : miscEntryFlows) { + if (miscEntryFlow != null && miscEntryFlow.canSaturate()) { + miscEntryFlow.onSaturated(bb); + } + } + } + } } diff --git a/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/ReachabilityAnalysisEngine.java b/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/ReachabilityAnalysisEngine.java index 5ca6ed4c41b7..60662dc50802 100644 --- a/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/ReachabilityAnalysisEngine.java +++ b/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/ReachabilityAnalysisEngine.java @@ -25,6 +25,7 @@ package com.oracle.graal.reachability; import java.lang.reflect.Executable; +import java.lang.reflect.Field; import java.util.ArrayDeque; import java.util.Collections; import java.util.Deque; @@ -32,6 +33,7 @@ import java.util.Set; import com.oracle.graal.pointsto.AbstractAnalysisEngine; +import com.oracle.graal.pointsto.ClassInclusionPolicy; import com.oracle.graal.pointsto.api.HostVM; import com.oracle.graal.pointsto.constraints.UnsupportedFeatures; import com.oracle.graal.pointsto.meta.AnalysisField; @@ -80,8 +82,8 @@ public abstract class ReachabilityAnalysisEngine extends AbstractAnalysisEngine @SuppressWarnings("this-escape") public ReachabilityAnalysisEngine(OptionValues options, AnalysisUniverse universe, HostVM hostVM, AnalysisMetaAccess metaAccess, SnippetReflectionProvider snippetReflectionProvider, ConstantReflectionProvider constantReflectionProvider, WordTypes wordTypes, UnsupportedFeatures unsupportedFeatures, DebugContext debugContext, TimerCollection timerCollection, - ReachabilityMethodProcessingHandler reachabilityMethodProcessingHandler) { - super(options, universe, hostVM, metaAccess, snippetReflectionProvider, constantReflectionProvider, wordTypes, unsupportedFeatures, debugContext, timerCollection); + ReachabilityMethodProcessingHandler reachabilityMethodProcessingHandler, ClassInclusionPolicy classInclusionPolicy) { + super(options, universe, hostVM, metaAccess, snippetReflectionProvider, constantReflectionProvider, wordTypes, unsupportedFeatures, debugContext, timerCollection, classInclusionPolicy); this.executor.init(getTiming()); this.reachabilityTimer = timerCollection.createTimer("(reachability)"); @@ -109,6 +111,11 @@ public AnalysisMethod addRootMethod(Executable method, boolean invokeSpecial, Ob return addRootMethod(metaAccess.lookupJavaMethod(method), invokeSpecial, reason, otherRoots); } + @Override + public AnalysisMethod forcedAddRootMethod(Executable method, boolean invokeSpecial, Object reason, MultiMethod.MultiMethodKey... otherRoots) { + return addRootMethod(method, invokeSpecial, reason, otherRoots); + } + @SuppressWarnings("try") @Override public AnalysisType addRootClass(AnalysisType type, boolean addFields, boolean addArrayClass) { @@ -143,6 +150,13 @@ public AnalysisType addRootField(Class clazz, String fieldName) { throw AnalysisError.userError("Field not found: " + fieldName); } + @Override + public AnalysisType addRootField(Field field) { + AnalysisField analysisField = getMetaAccess().lookupJavaField(field); + analysisField.registerAsAccessed("root field"); + return analysisField.getType(); + } + @Override public AnalysisMethod addRootMethod(AnalysisMethod m, boolean invokeSpecial, Object reason, MultiMethod.MultiMethodKey... otherRoots) { assert otherRoots.length == 0 : otherRoots; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java index 3394043aeebc..62f139a15cb3 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java @@ -1040,6 +1040,13 @@ public enum ReportingMode { @Option(help = "Include all classes, methods, fields, and resources from given paths", type = OptionType.Debug) // public static final HostedOptionKey IncludeAllFromPath = new HostedOptionKey<>(LocatableMultiOptionValue.Strings.build()); + public static boolean includeAll() { + return IncludeAllFromPath.hasBeenSet() || IncludeAllFromPath.hasBeenSet(); + } + + @Option(help = "Run layered image base layer open-world analysis. Includes all public types and methods that can be reached using normal Java access rules.")// + public static final HostedOptionKey LayeredBaseImageAnalysis = new HostedOptionKey<>(false); + @Option(help = "Support for calls via the Java Foreign Function and Memory API", type = Expert) // public static final HostedOptionKey ForeignAPISupport = new HostedOptionKey<>(false); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JRTSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JRTSupport.java index 5ff6a4924994..8757de6e5005 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JRTSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JRTSupport.java @@ -37,9 +37,6 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.function.BooleanSupplier; -import jdk.graal.compiler.options.Option; -import jdk.graal.compiler.options.OptionType; - import com.oracle.svm.core.annotate.Alias; import com.oracle.svm.core.annotate.Delete; import com.oracle.svm.core.annotate.RecomputeFieldValue; @@ -52,6 +49,9 @@ import com.oracle.svm.core.option.HostedOptionKey; import com.oracle.svm.core.util.VMError; +import jdk.graal.compiler.options.Option; +import jdk.graal.compiler.options.OptionType; + /** * Support to access system Java modules and the jrt:// file system. * @@ -154,6 +154,9 @@ final class Target_jdk_internal_jimage_ImageReaderFactory_JRTEnabled { */ @TargetClass(className = "jdk.internal.module.SystemModuleFinders", innerClass = "SystemImage", onlyWith = JRTDisabled.class) final class Target_jdk_internal_module_SystemModuleFinders_SystemImage_JRTDisabled { + @Delete // + static Target_jdk_internal_jimage_ImageReader READER; + @Substitute static Target_jdk_internal_jimage_ImageReader reader() { throw VMError.unsupportedFeature("JRT file system is disabled"); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JVMCISubstitutions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JVMCISubstitutions.java index bdd2904b7cc9..efae01988ad5 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JVMCISubstitutions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JVMCISubstitutions.java @@ -32,6 +32,7 @@ import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.annotate.Alias; +import com.oracle.svm.core.annotate.Delete; import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; @@ -51,6 +52,9 @@ public boolean getAsBoolean() { */ @TargetClass(value = Services.class, onlyWith = IsNotLibgraal.class) final class Target_jdk_vm_ci_services_Services { + @Delete // + static Map savedProperties; + @Substitute public static Map getSavedProperties() { return SystemPropertiesSupport.singleton().getSavedProperties(); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaLangSubstitutions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaLangSubstitutions.java index 2c9f7be081cd..a68c7ea8346a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaLangSubstitutions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaLangSubstitutions.java @@ -576,6 +576,10 @@ final class Target_jdk_internal_loader_ClassLoaders { @TargetClass(value = jdk.internal.loader.BootLoader.class) final class Target_jdk_internal_loader_BootLoader { + // Checkstyle: stop + @Delete // + static String JAVA_HOME; + // Checkstyle: resume @Substitute static Package getDefinedPackage(String name) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmstat/Target_jdk_internal_perf_PerfCounter.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmstat/Target_jdk_internal_perf_PerfCounter.java index b0a4f52c059b..e4a5dbca516f 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmstat/Target_jdk_internal_perf_PerfCounter.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmstat/Target_jdk_internal_perf_PerfCounter.java @@ -24,6 +24,9 @@ */ package com.oracle.svm.core.jvmstat; +import java.nio.LongBuffer; + +import com.oracle.svm.core.annotate.Delete; import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; @@ -34,6 +37,9 @@ */ @TargetClass(className = "jdk.internal.perf.PerfCounter") final class Target_jdk_internal_perf_PerfCounter { + @Delete // + private LongBuffer lb; + @Substitute @SuppressWarnings("static-method") public long get() { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/methodhandles/Target_java_lang_invoke_MethodHandles_Lookup.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/methodhandles/Target_java_lang_invoke_MethodHandles_Lookup.java index 1b1e2093979e..b9e2e0ed7593 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/methodhandles/Target_java_lang_invoke_MethodHandles_Lookup.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/methodhandles/Target_java_lang_invoke_MethodHandles_Lookup.java @@ -28,6 +28,7 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; +import java.util.concurrent.ConcurrentHashMap; import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.annotate.Alias; @@ -40,6 +41,11 @@ @TargetClass(value = MethodHandles.class, innerClass = "Lookup") final class Target_java_lang_invoke_MethodHandles_Lookup { + // Checkstyle: stop + @Delete // + static ConcurrentHashMap LOOKASIDE_TABLE; + // Checkstyle: resume + @SuppressWarnings("static-method") @Substitute public Class defineClass(@SuppressWarnings("unused") byte[] bytes) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java index a9e4460375ef..31ce3158dc47 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java @@ -54,7 +54,6 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.BooleanSupplier; -import java.util.stream.Stream; import org.graalvm.collections.EconomicMap; import org.graalvm.collections.EconomicSet; @@ -86,6 +85,7 @@ import com.oracle.graal.pointsto.AnalysisObjectScanningObserver; import com.oracle.graal.pointsto.AnalysisPolicy; import com.oracle.graal.pointsto.BigBang; +import com.oracle.graal.pointsto.ClassInclusionPolicy; import com.oracle.graal.pointsto.ObjectScanningObserver; import com.oracle.graal.pointsto.api.PointstoOptions; import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException; @@ -984,7 +984,7 @@ protected void setupNativeImage(OptionValues options, Map bb.registerTypeForBaseImage(cls)); registerEntryPointStubs(entryPoints); } @@ -993,16 +993,6 @@ protected void setupNativeImage(OptionValues options, Map cls) { - String reason = "Included in the base image"; - if (!(Modifier.isAbstract(cls.getModifiers()) || cls.isInterface() || cls.isPrimitive())) { - bb.getMetaAccess().lookupJavaType(cls).registerAsAllocated(reason); - } - Stream methods = Arrays.stream(cls.getDeclaredMethods()).filter(method -> bb.getMetaAccess().lookupJavaMethod(method).getAnnotation(Fold.class) == null); - Stream.concat(Arrays.stream(cls.getDeclaredConstructors()), methods) - .forEach(mthd -> bb.addRootMethod(mthd, false, reason)); - } - protected void registerEntryPointStubs(Map entryPoints) { entryPoints.forEach((method, entryPointData) -> CEntryPointCallStubSupport.singleton().registerStubForMethod(method, () -> entryPointData)); } @@ -1209,6 +1199,9 @@ private static Inflation createBigBang(DebugContext debug, OptionValues options, SnippetReflectionProvider snippetReflectionProvider = aProviders.getSnippetReflection(); ConstantReflectionProvider constantReflectionProvider = aProviders.getConstantReflection(); WordTypes wordTypes = aProviders.getWordTypes(); + String reason = "Included in the base image"; + ClassInclusionPolicy classInclusionPolicy = SubstrateOptions.LayeredBaseImageAnalysis.getValue(options) ? new ClassInclusionPolicy.LayeredBaseImageInclusionPolicy(reason) + : new ClassInclusionPolicy.DefaultAllInclusionPolicy(reason); if (PointstoOptions.UseExperimentalReachabilityAnalysis.getValue(options)) { ReachabilityMethodProcessingHandler reachabilityMethodProcessingHandler; if (PointstoOptions.UseReachabilityMethodSummaries.getValue(options)) { @@ -1219,10 +1212,10 @@ private static Inflation createBigBang(DebugContext debug, OptionValues options, reachabilityMethodProcessingHandler = new DirectMethodProcessingHandler(); } return new NativeImageReachabilityAnalysisEngine(options, aUniverse, aMetaAccess, snippetReflectionProvider, constantReflectionProvider, wordTypes, annotationSubstitutionProcessor, debug, - ImageSingletons.lookup(TimerCollection.class), reachabilityMethodProcessingHandler); + ImageSingletons.lookup(TimerCollection.class), reachabilityMethodProcessingHandler, classInclusionPolicy); } return new NativeImagePointsToAnalysis(options, aUniverse, aMetaAccess, snippetReflectionProvider, constantReflectionProvider, wordTypes, annotationSubstitutionProcessor, - new SubstrateUnsupportedFeatures(), debug, ImageSingletons.lookup(TimerCollection.class)); + new SubstrateUnsupportedFeatures(), debug, ImageSingletons.lookup(TimerCollection.class), classInclusionPolicy); } @SuppressWarnings("try") @@ -1716,13 +1709,7 @@ public static void checkName(String name, AnalysisMethod method, BigBang bb) { * The same holds for "hotspot" elements, which come from the hosting HotSpot VM, unless * they are JDK internal types. */ - String lname = name.toLowerCase(); - String message = null; - if (lname.contains("hosted")) { - message = "Hosted element used at run time: " + name; - } else if (!name.startsWith("jdk.internal") && lname.contains("hotspot")) { - message = "HotSpot element used at run time: " + name; - } + String message = checkName(name); if (message != null) { if (bb != null) { @@ -1733,6 +1720,17 @@ public static void checkName(String name, AnalysisMethod method, BigBang bb) { } } + public static String checkName(String name) { + String lname = name.toLowerCase(); + String message = null; + if (lname.contains("hosted")) { + message = "Hosted element used at run time: " + name; + } else if (!name.startsWith("jdk.internal") && lname.contains("hotspot")) { + message = "HotSpot element used at run time: " + name; + } + return message; + } + @SuppressWarnings("try") protected void processNativeLibraryImports(NativeLibraries nativeLibs, MetaAccessProvider metaAccess, ClassInitializationSupport classInitializationSupport) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java index ce07a00c936c..5a1148b2696a 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java @@ -28,6 +28,7 @@ import java.lang.ref.Reference; import java.lang.ref.SoftReference; import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; @@ -73,6 +74,8 @@ import com.oracle.svm.core.RuntimeAssertionsSupport; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.SubstrateOptions.OptimizationLevel; +import com.oracle.svm.core.annotate.InjectAccessors; +import com.oracle.svm.core.c.CGlobalData; import com.oracle.svm.core.classinitialization.EnsureClassInitializedNode; import com.oracle.svm.core.graal.meta.SubstrateForeignCallLinkage; import com.oracle.svm.core.graal.meta.SubstrateForeignCallsProvider; @@ -89,9 +92,11 @@ import com.oracle.svm.core.option.HostedOptionKey; import com.oracle.svm.core.option.SubstrateOptionsParser; import com.oracle.svm.core.thread.ContinuationSupport; +import com.oracle.svm.core.util.Counter; import com.oracle.svm.core.util.HostedStringDeduplication; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.ameta.FieldValueInterceptionSupport; +import com.oracle.svm.hosted.analysis.NativeImagePointsToAnalysis; import com.oracle.svm.hosted.analysis.SVMParsingSupport; import com.oracle.svm.hosted.classinitialization.ClassInitializationOptions; import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport; @@ -807,6 +812,35 @@ public boolean platformSupported(AnnotatedElement element) { return false; } + @Override + public boolean isFieldIncluded(BigBang bb, Field field) { + /* + * Fields of type CGlobalData can use a CGlobalDataFactory which must not be reachable at + * run time + */ + if (field.getType().equals(CGlobalData.class)) { + return false; + } + /* This field cannot be written to (see documentation) */ + if (field.equals(ReflectionUtil.lookupField(Counter.Group.class, "enabled"))) { + return false; + } + /* Fields with those names are not allowed in the image */ + if (NativeImageGenerator.checkName(field.getType().getName() + "." + field.getName()) != null) { + return false; + } + /* Fields from this package should not be in the image */ + if (field.getDeclaringClass().getName().startsWith("jdk.graal.compiler")) { + return false; + } + /* Fields that are deleted or substituted should not be in the image */ + if (bb instanceof NativeImagePointsToAnalysis nativeImagePointsToAnalysis) { + AnnotationSubstitutionProcessor annotationSubstitutionProcessor = nativeImagePointsToAnalysis.getAnnotationSubstitutionProcessor(); + return !annotationSubstitutionProcessor.isDeleted(field) && !annotationSubstitutionProcessor.isAnnotationPresent(field, InjectAccessors.class); + } + return super.isFieldIncluded(bb, field); + } + private final List> neverInlineTrivialHandlers = new CopyOnWriteArrayList<>(); public void registerNeverInlineTrivialHandler(BiPredicate handler) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImagePointsToAnalysis.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImagePointsToAnalysis.java index f9eb3ae3524d..e0eebede8300 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImagePointsToAnalysis.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImagePointsToAnalysis.java @@ -27,11 +27,14 @@ import java.lang.reflect.Executable; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.util.Arrays; +import com.oracle.graal.pointsto.ClassInclusionPolicy; import com.oracle.graal.pointsto.PointsToAnalysis; import com.oracle.graal.pointsto.constraints.UnsupportedFeatures; import com.oracle.graal.pointsto.flow.MethodFlowsGraph; import com.oracle.graal.pointsto.flow.MethodTypeFlowBuilder; +import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisMethod; @@ -39,6 +42,7 @@ import com.oracle.graal.pointsto.meta.AnalysisUniverse; import com.oracle.graal.pointsto.meta.PointsToAnalysisMethod; import com.oracle.graal.pointsto.util.TimerCollection; +import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.hosted.HostedConfiguration; import com.oracle.svm.hosted.SVMHost; import com.oracle.svm.hosted.ameta.CustomTypeFieldHandler; @@ -66,8 +70,9 @@ public NativeImagePointsToAnalysis(OptionValues options, AnalysisUniverse univer AnalysisMetaAccess metaAccess, SnippetReflectionProvider snippetReflectionProvider, ConstantReflectionProvider constantReflectionProvider, WordTypes wordTypes, AnnotationSubstitutionProcessor annotationSubstitutionProcessor, UnsupportedFeatures unsupportedFeatures, - DebugContext debugContext, TimerCollection timerCollection) { - super(options, universe, universe.hostVM(), metaAccess, snippetReflectionProvider, constantReflectionProvider, wordTypes, unsupportedFeatures, debugContext, timerCollection); + DebugContext debugContext, TimerCollection timerCollection, ClassInclusionPolicy classInclusionPolicy) { + super(options, universe, universe.hostVM(), metaAccess, snippetReflectionProvider, constantReflectionProvider, wordTypes, unsupportedFeatures, debugContext, timerCollection, + classInclusionPolicy); this.annotationSubstitutionProcessor = annotationSubstitutionProcessor; dynamicHubInitializer = new DynamicHubInitializer(this); @@ -114,7 +119,14 @@ public void onFieldAccessed(AnalysisField field) { @Override public void onTypeReachable(AnalysisType type) { - postTask(d -> type.getInitializeMetaDataTask().ensureDone()); + postTask(d -> { + type.getInitializeMetaDataTask().ensureDone(); + if (SubstrateOptions.includeAll()) { + Arrays.stream(OriginalClassProvider.getJavaClass(type).getDeclaredFields()) + .filter(classInclusionPolicy::isFieldIncluded) + .forEach(classInclusionPolicy::includeField); + } + }); } @Override @@ -211,5 +223,4 @@ private static Class findResolutionError /* Not matching method found at all. */ return AbstractMethodError.class; } - } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImageReachabilityAnalysisEngine.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImageReachabilityAnalysisEngine.java index be0373bf07b4..8b2dc40e7112 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImageReachabilityAnalysisEngine.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImageReachabilityAnalysisEngine.java @@ -24,6 +24,7 @@ */ package com.oracle.svm.hosted.analysis; +import com.oracle.graal.pointsto.ClassInclusionPolicy; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisType; @@ -50,9 +51,9 @@ public class NativeImageReachabilityAnalysisEngine extends ReachabilityAnalysisE @SuppressWarnings("this-escape") public NativeImageReachabilityAnalysisEngine(OptionValues options, AnalysisUniverse universe, AnalysisMetaAccess metaAccess, SnippetReflectionProvider snippetReflectionProvider, ConstantReflectionProvider constantReflectionProvider, WordTypes wordTypes, AnnotationSubstitutionProcessor annotationSubstitutionProcessor, DebugContext debugContext, - TimerCollection timerCollection, ReachabilityMethodProcessingHandler reachabilityMethodProcessingHandler) { + TimerCollection timerCollection, ReachabilityMethodProcessingHandler reachabilityMethodProcessingHandler, ClassInclusionPolicy classInclusionPolicy) { super(options, universe, universe.hostVM(), metaAccess, snippetReflectionProvider, constantReflectionProvider, wordTypes, new SubstrateUnsupportedFeatures(), debugContext, timerCollection, - reachabilityMethodProcessingHandler); + reachabilityMethodProcessingHandler, classInclusionPolicy); this.annotationSubstitutionProcessor = annotationSubstitutionProcessor; this.dynamicHubInitializer = new DynamicHubInitializer(this); this.unknownFieldHandler = new CustomTypeFieldHandler(this, metaAccess) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JDKInitializationFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JDKInitializationFeature.java index bb86216030bc..ab69e9166381 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JDKInitializationFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JDKInitializationFeature.java @@ -196,6 +196,8 @@ public void afterRegistration(AfterRegistrationAccess access) { rci.rerunInitialization("jdk.internal.foreign.SystemLookup$WindowsFallbackSymbols", "Does not work on non-Windows modular images"); + rci.rerunInitialization("jdk.internal.logger.LoggerFinderLoader", "Contains a static field with a FilePermission value"); + /* * The local class Holder in FallbackLinker#getInstance fails the build time initialization * starting JDK 22. There is no way to obtain a list of local classes using reflection. They diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotationSubstitutionProcessor.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotationSubstitutionProcessor.java index ac5460c17e89..7752e66bf8f3 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotationSubstitutionProcessor.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotationSubstitutionProcessor.java @@ -197,9 +197,17 @@ public boolean isDeleted(ResolvedJavaField field) { if (deleteAnnotations.get(field) != null) { return true; } + return isAnnotationPresent(field, Delete.class); + } + + public boolean isAnnotationPresent(Field field, Class annotationClass) { + return isAnnotationPresent(metaAccess.lookupJavaField(field), annotationClass); + } + + public boolean isAnnotationPresent(ResolvedJavaField field, Class annotationClass) { ResolvedJavaField substitutionField = fieldSubstitutions.get(field); if (substitutionField != null) { - return AnnotationAccess.isAnnotationPresent(substitutionField, Delete.class); + return AnnotationAccess.isAnnotationPresent(substitutionField, annotationClass); } return false; }