From 3fd3862c322fd9374efb03ba91b8182d10aa0c97 Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Mon, 28 Nov 2022 14:18:46 +0100 Subject: [PATCH 1/2] Provide reason for AnalysisType reachability. --- .../common/spi/ConstantFieldProvider.java | 2 + .../hotspot/test/ClassSubstitutionsTests.java | 2 +- .../hotspot/meta/HotSpotNodePlugin.java | 3 +- .../graalvm/compiler/java/BytecodeParser.java | 4 +- .../compiler/nodes/java/LoadFieldNode.java | 31 +++++++-------- .../compiler/nodes/memory/ReadNode.java | 2 +- .../compiler/nodes/util/ConstantFoldUtil.java | 15 +++++++- .../replacements/InvocationPluginHelper.java | 2 +- .../pointsto/standalone/PointsToAnalyzer.java | 19 +++++----- .../StandalonePointsToAnalysis.java | 11 +++--- .../StandaloneAnalysisFeatureImpl.java | 12 ++---- .../StandaloneConstantReflectionProvider.java | 3 +- .../pointsto/AbstractAnalysisEngine.java | 2 +- .../oracle/graal/pointsto/ObjectScanner.java | 2 +- .../graal/pointsto/PointsToAnalysis.java | 2 +- .../graal/pointsto/ReachabilityAnalysis.java | 4 +- .../pointsto/flow/MethodTypeFlowBuilder.java | 4 +- .../graal/pointsto/heap/ImageHeapScanner.java | 7 ++-- .../infrastructure/AnalysisConstantPool.java | 10 ----- .../graal/pointsto/meta/AnalysisElement.java | 21 ++++++++++ .../graal/pointsto/meta/AnalysisField.java | 17 +++++---- .../graal/pointsto/meta/AnalysisMethod.java | 6 +-- .../graal/pointsto/meta/AnalysisType.java | 20 +++++----- .../graal/pointsto/meta/AnalysisUniverse.java | 2 +- .../graal/pointsto/util/AtomicUtils.java | 9 +++++ .../DirectMethodProcessingHandler.java | 11 +++--- .../MethodSummaryBasedHandler.java | 4 +- .../ReachabilityAnalysisEngine.java | 4 +- .../ReachabilityObjectScanner.java | 14 +++---- .../SimpleInMemoryMethodSummaryProvider.java | 3 +- .../graal/hosted/FieldsOffsetsFeature.java | 2 +- .../hosted/GraalGraphObjectReplacer.java | 2 +- .../com/oracle/svm/hosted/FeatureImpl.java | 14 +++---- .../svm/hosted/NativeImageGenerator.java | 38 ++++++++----------- .../ameta/AnalysisConstantFieldProvider.java | 7 +++- ...NativeImageReachabilityAnalysisEngine.java | 9 +++-- .../svm/hosted/c/CGlobalDataFeature.java | 4 +- .../oracle/svm/hosted/c/NativeLibraries.java | 2 +- .../svm/hosted/image/StringInternFeature.java | 6 +-- .../svm/hosted/jni/JNIAccessFeature.java | 6 +-- .../phases/ConstantFoldLoadFieldPlugin.java | 3 +- .../svm/hosted/phases/HostedGraphKit.java | 5 --- ...trinsifyMethodHandlesInvocationPlugin.java | 1 - .../phases/SubstrateGraphBuilderPhase.java | 2 +- .../hosted/reflect/ReflectionDataBuilder.java | 4 +- .../AnnotationSubstitutionProcessor.java | 3 -- .../UnsafeAutomaticSubstitutionProcessor.java | 1 - .../oracle/svm/truffle/TruffleFeature.java | 2 +- .../api/SubstrateKnownTruffleTypes.java | 4 +- 49 files changed, 190 insertions(+), 173 deletions(-) diff --git a/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/ConstantFieldProvider.java b/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/ConstantFieldProvider.java index 3cc496ffcb6d..4ec55219fcb9 100644 --- a/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/ConstantFieldProvider.java +++ b/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/ConstantFieldProvider.java @@ -42,6 +42,8 @@ public interface ConstantFieldTool { JavaConstant getReceiver(); + Object getReason(); + T foldConstant(JavaConstant ret); T foldStableArray(JavaConstant ret, int stableDimensions, boolean isDefaultStable); diff --git a/compiler/src/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ClassSubstitutionsTests.java b/compiler/src/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ClassSubstitutionsTests.java index abaa3e9e472d..4ab136874f9e 100644 --- a/compiler/src/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ClassSubstitutionsTests.java +++ b/compiler/src/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ClassSubstitutionsTests.java @@ -186,7 +186,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec ResolvedJavaField field = b.getMetaAccess().lookupJavaField(f); b.addPush(JavaKind.Object, LoadFieldNode.create(b.getConstantFieldProvider(), b.getConstantReflection(), b.getMetaAccess(), b.getOptions(), - b.getAssumptions(), clazz, field, false, false)); + b.getAssumptions(), clazz, field, false, false, b.getGraph().currentNodeSourcePosition())); return true; } }); diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java index 5c6e0b560581..2fb86b1d6dc8 100644 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java @@ -119,7 +119,8 @@ private static boolean tryReadField(GraphBuilderContext b, ResolvedJavaField fie } private static boolean tryConstantFold(GraphBuilderContext b, ResolvedJavaField field, JavaConstant object) { - ConstantNode result = ConstantFoldUtil.tryConstantFold(b.getConstantFieldProvider(), b.getConstantReflection(), b.getMetaAccess(), field, object, b.getOptions()); + ConstantNode result = ConstantFoldUtil.tryConstantFold(b.getConstantFieldProvider(), b.getConstantReflection(), b.getMetaAccess(), field, object, b.getOptions(), + b.getGraph().currentNodeSourcePosition()); if (result != null) { result = b.getGraph().unique(result); b.push(field.getJavaKind(), result); diff --git a/compiler/src/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java b/compiler/src/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java index 93c1eee8f621..05f06c6e80dc 100644 --- a/compiler/src/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java +++ b/compiler/src/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java @@ -1560,10 +1560,10 @@ protected ValueNode genLoadField(ValueNode receiver, ResolvedJavaField field) { StampPair stamp = graphBuilderConfig.getPlugins().getOverridingStamp(this, field.getType(), false); if (stamp == null) { return LoadFieldNode.create(getConstantFieldProvider(), getConstantReflection(), getMetaAccess(), getOptions(), - getAssumptions(), receiver, field, false, false); + getAssumptions(), receiver, field, false, false, createBytecodePosition()); } else { return LoadFieldNode.createOverrideStamp(getConstantFieldProvider(), getConstantReflection(), getMetaAccess(), getOptions(), - stamp, receiver, field, false, false); + stamp, receiver, field, false, false, createBytecodePosition()); } } diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoadFieldNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoadFieldNode.java index e6fea170f1d2..33ebe1d6635d 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoadFieldNode.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoadFieldNode.java @@ -33,6 +33,7 @@ import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.core.common.type.StampPair; import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.NodeSourcePosition; import org.graalvm.compiler.nodeinfo.NodeCycles; import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.ConstantNode; @@ -94,9 +95,9 @@ public static LoadFieldNode create(Assumptions assumptions, ValueNode object, Re } public static ValueNode create(ConstantFieldProvider constantFields, ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, - OptionValues options, Assumptions assumptions, ValueNode object, ResolvedJavaField field, boolean canonicalizeReads, boolean allUsagesAvailable) { + OptionValues options, Assumptions assumptions, ValueNode object, ResolvedJavaField field, boolean canonicalizeReads, boolean allUsagesAvailable, NodeSourcePosition position) { return canonical(null, StampFactory.forDeclaredType(assumptions, field.getType(), false), object, - field, constantFields, constantReflection, options, metaAccess, canonicalizeReads, allUsagesAvailable, false); + field, constantFields, constantReflection, options, metaAccess, canonicalizeReads, allUsagesAvailable, false, position); } public static LoadFieldNode createOverrideImmutable(LoadFieldNode node) { @@ -108,8 +109,8 @@ public static LoadFieldNode createOverrideStamp(StampPair stamp, ValueNode objec } public static ValueNode createOverrideStamp(ConstantFieldProvider constantFields, ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, - OptionValues options, StampPair stamp, ValueNode object, ResolvedJavaField field, boolean canonicalizeReads, boolean allUsagesAvailable) { - return canonical(null, stamp, object, field, constantFields, constantReflection, options, metaAccess, canonicalizeReads, allUsagesAvailable, false); + OptionValues options, StampPair stamp, ValueNode object, ResolvedJavaField field, boolean canonicalizeReads, boolean allUsagesAvailable, NodeSourcePosition position) { + return canonical(null, stamp, object, field, constantFields, constantReflection, options, metaAccess, canonicalizeReads, allUsagesAvailable, false, position); } @Override @@ -137,21 +138,21 @@ public ValueNode canonical(CanonicalizerTool tool, ValueNode forObject) { } } return canonical(this, StampPair.create(stamp, uncheckedStamp), forObject, field, tool.getConstantFieldProvider(), - tool.getConstantReflection(), tool.getOptions(), tool.getMetaAccess(), tool.canonicalizeReads(), tool.allUsagesAvailable(), false); + tool.getConstantReflection(), tool.getOptions(), tool.getMetaAccess(), tool.canonicalizeReads(), tool.allUsagesAvailable(), false, getNodeSourcePosition()); } private static ValueNode canonical(LoadFieldNode loadFieldNode, StampPair stamp, ValueNode forObject, ResolvedJavaField field, ConstantFieldProvider constantFields, ConstantReflectionProvider constantReflection, - OptionValues options, MetaAccessProvider metaAccess, boolean canonicalizeReads, boolean allUsagesAvailable, boolean immutable) { + OptionValues options, MetaAccessProvider metaAccess, boolean canonicalizeReads, boolean allUsagesAvailable, boolean immutable, NodeSourcePosition position) { LoadFieldNode self = loadFieldNode; if (canonicalizeReads && metaAccess != null) { - ConstantNode constant = asConstant(constantFields, constantReflection, metaAccess, options, forObject, field); + ConstantNode constant = asConstant(constantFields, constantReflection, metaAccess, options, forObject, field, position); if (constant != null) { return constant; } if (allUsagesAvailable) { PhiNode phi = asPhi(constantFields, constantReflection, metaAccess, options, forObject, - field, stamp.getTrustedStamp()); + field, stamp.getTrustedStamp(), position); if (phi != null) { return phi; } @@ -171,32 +172,32 @@ private static ValueNode canonical(LoadFieldNode loadFieldNode, StampPair stamp, */ public ConstantNode asConstant(CanonicalizerTool tool, ValueNode forObject) { return asConstant(tool.getConstantFieldProvider(), tool.getConstantReflection(), - tool.getMetaAccess(), tool.getOptions(), forObject, field); + tool.getMetaAccess(), tool.getOptions(), forObject, field, getNodeSourcePosition()); } private static ConstantNode asConstant(ConstantFieldProvider constantFields, ConstantReflectionProvider constantReflection, - MetaAccessProvider metaAccess, OptionValues options, ValueNode forObject, ResolvedJavaField field) { + MetaAccessProvider metaAccess, OptionValues options, ValueNode forObject, ResolvedJavaField field, NodeSourcePosition position) { if (field.isStatic()) { - return ConstantFoldUtil.tryConstantFold(constantFields, constantReflection, metaAccess, field, null, options); + return ConstantFoldUtil.tryConstantFold(constantFields, constantReflection, metaAccess, field, null, options, position); } else if (forObject.isConstant() && !forObject.isNullConstant()) { - return ConstantFoldUtil.tryConstantFold(constantFields, constantReflection, metaAccess, field, forObject.asJavaConstant(), options); + return ConstantFoldUtil.tryConstantFold(constantFields, constantReflection, metaAccess, field, forObject.asJavaConstant(), options, position); } return null; } public ConstantNode asConstant(CanonicalizerTool tool, JavaConstant constant) { - return ConstantFoldUtil.tryConstantFold(tool.getConstantFieldProvider(), tool.getConstantReflection(), tool.getMetaAccess(), field(), constant, tool.getOptions()); + return ConstantFoldUtil.tryConstantFold(tool.getConstantFieldProvider(), tool.getConstantReflection(), tool.getMetaAccess(), field(), constant, tool.getOptions(), getNodeSourcePosition()); } private static PhiNode asPhi(ConstantFieldProvider constantFields, ConstantReflectionProvider constantReflection, - MetaAccessProvider metaAcccess, OptionValues options, ValueNode forObject, ResolvedJavaField field, Stamp stamp) { + MetaAccessProvider metaAcccess, OptionValues options, ValueNode forObject, ResolvedJavaField field, Stamp stamp, NodeSourcePosition position) { if (!field.isStatic() && (field.isFinal() || constantFields.maybeFinal(field)) && forObject instanceof ValuePhiNode && ((ValuePhiNode) forObject).values().filter(isNotA(ConstantNode.class)).isEmpty()) { PhiNode phi = (PhiNode) forObject; ConstantNode[] constantNodes = new ConstantNode[phi.valueCount()]; for (int i = 0; i < phi.valueCount(); i++) { ConstantNode constant = ConstantFoldUtil.tryConstantFold(constantFields, constantReflection, metaAcccess, field, phi.valueAt(i).asJavaConstant(), - options); + options, position); if (constant == null) { return null; } diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/ReadNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/ReadNode.java index 93bf011433bf..04f3fc18720c 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/ReadNode.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/ReadNode.java @@ -216,7 +216,7 @@ private static ValueNode canonicalizeRead(ValueNode read, Stamp accessStamp, Val // normally not considered immutable. ResolvedJavaField field = ((FieldLocationIdentity) locationIdentity).getField(); ConstantNode constantNode = ConstantFoldUtil.tryConstantFold(tool, field, object.asJavaConstant(), displacement, resultStamp, - accessStamp, read.getOptions()); + accessStamp, read.getOptions(), read.getNodeSourcePosition()); if (constantNode != null) { return constantNode; } diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/ConstantFoldUtil.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/ConstantFoldUtil.java index cf4bf659519f..1a742576f111 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/ConstantFoldUtil.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/ConstantFoldUtil.java @@ -41,7 +41,7 @@ public class ConstantFoldUtil { public static ConstantNode tryConstantFold(ConstantFieldProvider fieldProvider, ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, ResolvedJavaField field, - JavaConstant receiver, OptionValues options) { + JavaConstant receiver, OptionValues options, Object reason) { if (!field.isStatic()) { if (receiver == null || receiver.isNull()) { return null; @@ -60,6 +60,11 @@ public JavaConstant getReceiver() { return receiver; } + @Override + public Object getReason() { + return reason; + } + @Override public ConstantNode foldConstant(JavaConstant ret) { if (ret != null) { @@ -89,7 +94,8 @@ public OptionValues getOptions() { * Perform a constant folding read on a regular Java field that's already been lowered to a * {@link ReadNode}. */ - public static ConstantNode tryConstantFold(CoreProviders tool, ResolvedJavaField field, JavaConstant receiver, long displacement, Stamp resultStamp, Stamp accessStamp, OptionValues options) { + public static ConstantNode tryConstantFold(CoreProviders tool, ResolvedJavaField field, JavaConstant receiver, long displacement, Stamp resultStamp, Stamp accessStamp, OptionValues options, + Object reason) { if (!field.isStatic()) { if (receiver == null || receiver.isNull()) { return null; @@ -112,6 +118,11 @@ public JavaConstant getReceiver() { return receiver; } + @Override + public Object getReason() { + return reason; + } + @Override public ConstantNode foldConstant(JavaConstant ret) { if (ret != null) { diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/InvocationPluginHelper.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/InvocationPluginHelper.java index 44d494c8ab77..ff9a8f16979b 100644 --- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/InvocationPluginHelper.java +++ b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/InvocationPluginHelper.java @@ -272,7 +272,7 @@ public LogicNode createCompare(ValueNode x, CanonicalCondition cond, ValueNode y public ValueNode loadField(ValueNode value, ResolvedJavaField field) { return b.add(LoadFieldNode.create(b.getConstantFieldProvider(), b.getConstantReflection(), b.getMetaAccess(), - b.getOptions(), b.getAssumptions(), value, field, false, false)); + b.getOptions(), b.getAssumptions(), value, field, false, false, b.getGraph().currentNodeSourcePosition())); } /** 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 70927ac1d92d..ed8716cdadc3 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 @@ -137,7 +137,6 @@ private PointsToAnalyzer(String mainEntryClass, OptionValues options) { AnalysisUniverse aUniverse = new AnalysisUniverse(standaloneHost, wordKind, analysisPolicy, SubstitutionProcessor.IDENTITY, originalMetaAccess, snippetReflection, snippetReflection, new PointsToAnalysisFactory()); AnalysisMetaAccess aMetaAccess = new AnalysisMetaAccess(aUniverse, originalMetaAccess); - aMetaAccess.lookupJavaType(String.class).registerAsReachable(); StandaloneConstantReflectionProvider aConstantReflection = new StandaloneConstantReflectionProvider(aUniverse, HotSpotJVMCIRuntime.runtime()); StandaloneConstantFieldProvider aConstantFieldProvider = new StandaloneConstantFieldProvider(aMetaAccess); AnalysisMetaAccessExtensionProvider aMetaAccessExtensionProvider = new AnalysisMetaAccessExtensionProvider(); @@ -171,14 +170,14 @@ private PointsToAnalyzer(String mainEntryClass, OptionValues options) { * good example. */ try (Indent ignored = debugContext.logAndIndent("add initial classes/fields/methods")) { - bigbang.addRootClass(Object.class, false, false).registerAsInHeap("Root class."); - bigbang.addRootClass(String.class, false, false).registerAsInHeap("Root class."); - bigbang.addRootClass(String[].class, false, false).registerAsInHeap("Root class."); - bigbang.addRootField(String.class, "value").registerAsInHeap("Root class."); - bigbang.addRootClass(long[].class, false, false).registerAsInHeap("Root class."); - bigbang.addRootClass(byte[].class, false, false).registerAsInHeap("Root class."); - bigbang.addRootClass(byte[][].class, false, false).registerAsInHeap("Root class."); - bigbang.addRootClass(Object[].class, false, false).registerAsInHeap("Root class."); + bigbang.addRootClass(Object.class, false, false).registerAsInHeap("root class"); + bigbang.addRootClass(String.class, false, false).registerAsInHeap("root class"); + bigbang.addRootClass(String[].class, false, false).registerAsInHeap("root class"); + bigbang.addRootField(String.class, "value").registerAsInHeap("root class"); + bigbang.addRootClass(long[].class, false, false).registerAsInHeap("root class"); + bigbang.addRootClass(byte[].class, false, false).registerAsInHeap("root class"); + bigbang.addRootClass(byte[][].class, false, false).registerAsInHeap("root class"); + bigbang.addRootClass(Object[].class, false, false).registerAsInHeap("root class"); bigbang.addRootMethod(ReflectionUtil.lookupMethod(Object.class, "getClass"), true); @@ -187,7 +186,7 @@ private PointsToAnalyzer(String mainEntryClass, OptionValues options) { bigbang.addRootClass(kind.toJavaClass(), false, true); } } - bigbang.getMetaAccess().lookupJavaType(JavaKind.Void.toJavaClass()).registerAsReachable(); + bigbang.getMetaAccess().lookupJavaType(JavaKind.Void.toJavaClass()).registerAsReachable("root class"); GraphBuilderConfiguration.Plugins plugins = new GraphBuilderConfiguration.Plugins(new InvocationPlugins()); NoClassInitializationPlugin classInitializationPlugin = new NoClassInitializationPlugin(); 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 b0c7e12fc70e..8a1d4ce05f4d 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 @@ -26,6 +26,12 @@ package com.oracle.graal.pointsto.standalone; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ForkJoinPool; + +import org.graalvm.compiler.options.OptionValues; + import com.oracle.graal.pointsto.PointsToAnalysis; import com.oracle.graal.pointsto.api.HostVM; import com.oracle.graal.pointsto.constraints.UnsupportedFeatures; @@ -34,11 +40,6 @@ import com.oracle.graal.pointsto.meta.AnalysisUniverse; import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.graal.pointsto.util.TimerCollection; -import org.graalvm.compiler.options.OptionValues; - -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ForkJoinPool; public class StandalonePointsToAnalysis extends PointsToAnalysis { private Set addedClinits = ConcurrentHashMap.newKeySet(); diff --git a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/features/StandaloneAnalysisFeatureImpl.java b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/features/StandaloneAnalysisFeatureImpl.java index df8ca9ed8db5..cff12f7f5933 100644 --- a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/features/StandaloneAnalysisFeatureImpl.java +++ b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/features/StandaloneAnalysisFeatureImpl.java @@ -167,16 +167,16 @@ public BeforeAnalysisAccessImpl(StandaloneAnalysisFeatureManager featureManager, @Override public void registerAsUsed(Class clazz) { - registerAsUsed(getMetaAccess().lookupJavaType(clazz)); + registerAsUsed(getMetaAccess().lookupJavaType(clazz), "registered from Feature API"); } - public void registerAsUsed(AnalysisType aType) { - aType.registerAsReachable(); + public void registerAsUsed(AnalysisType aType, Object reason) { + aType.registerAsReachable(reason); } @Override public void registerAsInHeap(Class clazz) { - registerAsInHeap(getMetaAccess().lookupJavaType(clazz), "Registered from Feature API."); + registerAsInHeap(getMetaAccess().lookupJavaType(clazz), "registered from Feature API"); } public void registerAsInHeap(AnalysisType aType, Object reason) { @@ -185,7 +185,6 @@ public void registerAsInHeap(AnalysisType aType, Object reason) { @Override public void registerAsAccessed(Field field) { - getMetaAccess().lookupJavaType(field.getDeclaringClass()).registerAsReachable(); registerAsAccessed(getMetaAccess().lookupJavaField(field)); } @@ -194,7 +193,6 @@ public void registerAsAccessed(AnalysisField aField) { } public void registerAsRead(Field field) { - getMetaAccess().lookupJavaType(field.getDeclaringClass()).registerAsReachable(); registerAsRead(getMetaAccess().lookupJavaField(field)); } @@ -204,7 +202,6 @@ public void registerAsRead(AnalysisField aField) { @Override public void registerAsUnsafeAccessed(Field field) { - getMetaAccess().lookupJavaType(field.getDeclaringClass()).registerAsReachable(); registerAsUnsafeAccessed(getMetaAccess().lookupJavaField(field)); } @@ -221,7 +218,6 @@ public boolean registerAsUnsafeAccessed(AnalysisField aField) { } public void registerAsFrozenUnsafeAccessed(Field field) { - getMetaAccess().lookupJavaType(field.getDeclaringClass()).registerAsReachable(); registerAsFrozenUnsafeAccessed(getMetaAccess().lookupJavaField(field)); } diff --git a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/meta/StandaloneConstantReflectionProvider.java b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/meta/StandaloneConstantReflectionProvider.java index dd45f2324702..9a137b419acf 100644 --- a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/meta/StandaloneConstantReflectionProvider.java +++ b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/meta/StandaloneConstantReflectionProvider.java @@ -31,6 +31,7 @@ import com.oracle.graal.pointsto.meta.AnalysisUniverse; import com.oracle.graal.pointsto.meta.UninitializedStaticFieldValueReader; import com.oracle.graal.pointsto.standalone.StandaloneHost; + import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider; import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; import jdk.vm.ci.hotspot.HotSpotObjectConstant; @@ -74,7 +75,7 @@ public final Constant asObjectHub(ResolvedJavaType type) { private static ResolvedJavaType markReachable(ResolvedJavaType type) { if (type instanceof AnalysisType) { AnalysisType t = (AnalysisType) type; - t.registerAsReachable(); + t.registerAsReachable("registered by the StandaloneConstantReflectionProvider"); return t.getWrapped(); } else { return type; 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 ccd6766e6b97..89e730c00161 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 @@ -346,7 +346,7 @@ public static BytecodePosition sourcePosition(ValueNode node) { } /** Creates a synthetic position for the node in the given method. */ - public static BytecodePosition syntheticSourcePosition(ValueNode node, ResolvedJavaMethod method) { + public static BytecodePosition syntheticSourcePosition(Node node, ResolvedJavaMethod method) { int bci = BytecodeFrame.UNKNOWN_BCI; if (node instanceof DeoptBciSupplier) { bci = ((DeoptBciSupplier) node).bci(); diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java index 765b1a3ff20e..ea42e94d42c5 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java @@ -412,7 +412,7 @@ public static String limit(String value, int length) { private void doScan(WorklistEntry entry) { try { AnalysisType type = bb.getMetaAccess().lookupJavaType(entry.constant); - type.registerAsReachable(); + type.registerAsReachable(entry.reason); if (type.isInstanceClass()) { /* Scan constant's instance fields. */ 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 f2b5cb3fb8d6..6a39c3bc0380 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 @@ -387,13 +387,13 @@ public static PointsToAnalysisMethod assertPointsToAnalysisMethod(AnalysisMethod @Override public AnalysisType addRootClass(Class clazz, boolean addFields, boolean addArrayClass) { AnalysisType type = metaAccess.lookupJavaType(clazz); - type.registerAsReachable(); return addRootClass(type, addFields, addArrayClass); } @SuppressWarnings({"try"}) @Override public AnalysisType addRootClass(AnalysisType type, boolean addFields, boolean addArrayClass) { + type.registerAsReachable("root class"); for (AnalysisField field : type.getInstanceFields(false)) { if (addFields) { field.registerAsAccessed(); 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 045020d2d8f1..9b9cbd0cb05c 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 @@ -93,8 +93,8 @@ default boolean registerAsUnsafeAccessed(AnalysisField field, UnsafePartitionKin return false; } - default boolean markTypeAsReachable(AnalysisType type) { - return type.registerAsReachable(); + default boolean registerTypeAsReachable(AnalysisType type, Object reason) { + return type.registerAsReachable(reason); } default boolean registerTypeAsAllocated(AnalysisType type, Object reason) { diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java index 12772bc09b7f..b3e27139a4ae 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java @@ -231,7 +231,7 @@ public void registerUsedElements(boolean registerEmbeddedRoots) { InstanceOfNode node = (InstanceOfNode) n; AnalysisType type = (AnalysisType) node.type().getType(); if (!ignoreInstanceOfType(type)) { - type.registerAsReachable(); + type.registerAsReachable(AbstractAnalysisEngine.sourcePosition(node)); } } else if (n instanceof NewInstanceNode) { @@ -311,7 +311,7 @@ public void registerUsedElements(boolean registerEmbeddedRoots) { * metadata is only constructed after AOT compilation, so the image heap * scanning during static analysis does not see these classes. */ - frameStateMethod.getDeclaringClass().registerAsReachable(); + frameStateMethod.getDeclaringClass().registerAsReachable(AbstractAnalysisEngine.syntheticSourcePosition(node, method)); } } else if (n instanceof ForeignCall) { diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java index ba2fccba5e48..7a60ee977423 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java @@ -110,8 +110,9 @@ public ImageHeapScanner(BigBang bb, ImageHeap heap, AnalysisMetaAccess aMetaAcce public void scanEmbeddedRoot(JavaConstant root, BytecodePosition position) { if (isNonNullObjectConstant(root)) { AnalysisType type = metaAccess.lookupJavaType(root); - type.registerAsReachable(); - getOrCreateConstantReachableTask(root, new EmbeddedRootScan(position, root), null); + EmbeddedRootScan reason = new EmbeddedRootScan(position, root); + type.registerAsReachable(reason); + getOrCreateConstantReachableTask(root, reason, null); } } @@ -381,7 +382,7 @@ protected ImageHeapConstant createImageHeapObject(JavaConstant constant, ScanRea AnalysisType typeFromClassConstant = (AnalysisType) constantReflection.asJavaType(constant); if (typeFromClassConstant != null) { - typeFromClassConstant.registerAsReachable(); + typeFromClassConstant.registerAsReachable(reason); } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/AnalysisConstantPool.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/AnalysisConstantPool.java index 45d0ab666dd8..59b84628ff20 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/AnalysisConstantPool.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/AnalysisConstantPool.java @@ -24,14 +24,9 @@ */ package com.oracle.graal.pointsto.infrastructure; -import com.oracle.graal.pointsto.meta.AnalysisType; -import com.oracle.graal.pointsto.meta.AnalysisUniverse; - import jdk.vm.ci.meta.ConstantPool; import jdk.vm.ci.meta.JavaField; -import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.ResolvedJavaType; public class AnalysisConstantPool extends WrappedConstantPool { @@ -43,11 +38,6 @@ public AnalysisConstantPool(Universe universe, ConstantPool wrapped, WrappedJava public JavaField lookupField(int cpi, ResolvedJavaMethod method, int opcode) { ResolvedJavaMethod substMethod = universe.resolveSubstitution(((WrappedJavaMethod) method).getWrapped()); JavaField field = wrapped.lookupField(cpi, substMethod, opcode); - JavaType declaringClass = field.getDeclaringClass(); - if (declaringClass instanceof ResolvedJavaType) { - AnalysisType fieldDeclaringType = ((AnalysisUniverse) universe).lookup(declaringClass); - fieldDeclaringType.registerAsReachable(); - } return universe.lookupAllowUnresolved(field); } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisElement.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisElement.java index f71a838a7964..760bc108d58e 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisElement.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisElement.java @@ -36,9 +36,13 @@ import org.graalvm.nativeimage.hosted.Feature.DuringAnalysisAccess; +import com.oracle.graal.pointsto.ObjectScanner; import com.oracle.graal.pointsto.util.AnalysisFuture; import com.oracle.graal.pointsto.util.ConcurrentLightHashSet; +import jdk.vm.ci.code.BytecodePosition; +import jdk.vm.ci.meta.ModifiersProvider; + public abstract class AnalysisElement { /** @@ -65,6 +69,23 @@ protected void notifyReachabilityCallbacks(AnalysisUniverse universe, List isWrittenUpdater = AtomicIntegerFieldUpdater .newUpdater(AnalysisField.class, "isWritten"); - private static final AtomicIntegerFieldUpdater isFoldedUpdater = AtomicIntegerFieldUpdater - .newUpdater(AnalysisField.class, "isFolded"); + private static final AtomicReferenceFieldUpdater isFoldedUpdater = AtomicReferenceFieldUpdater + .newUpdater(AnalysisField.class, Object.class, "isFolded"); private static final AtomicIntegerFieldUpdater isUnsafeAccessedUpdater = AtomicIntegerFieldUpdater .newUpdater(AnalysisField.class, "isUnsafeAccessed"); @@ -98,7 +98,7 @@ public abstract class AnalysisField extends AnalysisElement implements WrappedJa /** Contains the {@link BytecodePosition} of the read or a reason object. */ @SuppressWarnings("unused") private volatile Object isRead; @SuppressWarnings("unused") private volatile int isWritten; - @SuppressWarnings("unused") private volatile int isFolded; + @SuppressWarnings("unused") private volatile Object isFolded; private boolean isJNIAccessed; private boolean isUsedInComparison; @@ -190,7 +190,7 @@ public void intersectAccessInfos(AnalysisField other) { isAccessedUpdater.set(this, this.isAccessed & other.isAccessed); this.canBeNull = this.canBeNull && other.canBeNull; isWrittenUpdater.set(this, this.isWritten & other.isWritten); - isFoldedUpdater.set(this, this.isFolded & other.isFolded); + isFoldedUpdater.set(this, this.isFolded != null & other.isFolded != null ? this.isFolded : null); isReadUpdater.set(this, this.isRead != null & other.isRead != null ? this.isRead : null); notifyUpdateAccessInfo(); } @@ -278,7 +278,7 @@ public boolean registerAsAccessed() { * {@link String} describing why this field was manually marked as read */ public boolean registerAsRead(Object reason) { - assert reason != null && (!(reason instanceof String) || !reason.equals("")) : "Registering a field as read needs to provide a non-empty reason."; + assert isValidReason(reason) : "Registering a field as read needs to provide a non-empty reason."; boolean firstAttempt = AtomicUtils.atomicSet(this, reason, isReadUpdater); notifyUpdateAccessInfo(); if (readBy != null) { @@ -313,9 +313,10 @@ public boolean registerAsWritten(AnalysisMethod method) { return firstAttempt; } - public void markFolded() { - if (AtomicUtils.atomicMark(this, isFoldedUpdater)) { - getDeclaringClass().registerAsReachable(); + public void registerAsFolded(Object reason) { + assert isValidReason(reason) : "Registering a field as folded needs to provide a non-empty reason."; + if (AtomicUtils.atomicSet(this, reason, isFoldedUpdater)) { + assert getDeclaringClass().isReachable(); onReachable(); } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisMethod.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisMethod.java index f3e4ecdd585e..7ee56afbb990 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisMethod.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisMethod.java @@ -289,7 +289,7 @@ public boolean registerAsImplementationInvoked() { * the method as invoked, it would have an unwanted side effect, where this method could * return before the class gets marked as reachable. */ - getDeclaringClass().registerAsReachable(); + getDeclaringClass().registerAsReachable("declared method " + this.format("%H.%n(%p)") + " is registered as implementation invoked"); return AtomicUtils.atomicMarkAndRun(this, isImplementationInvokedUpdater, this::onReachable); } @@ -327,7 +327,7 @@ public boolean isIntrinsicMethod() { * as in {@link AnalysisMethod#registerAsImplementationInvoked()}. */ public boolean registerAsVirtualRootMethod() { - getDeclaringClass().registerAsReachable(); + getDeclaringClass().registerAsReachable("declared method " + this.format("%H.%n(%p)") + " is registered as virtual root"); return AtomicUtils.atomicMark(this, isVirtualRootMethodUpdater); } @@ -335,7 +335,7 @@ public boolean registerAsVirtualRootMethod() { * Registers this method as a direct (special or static) root for the analysis. */ public boolean registerAsDirectRootMethod() { - getDeclaringClass().registerAsReachable(); + getDeclaringClass().registerAsReachable("declared method " + this.format("%H.%n(%p)") + " is registered as direct root"); return AtomicUtils.atomicMark(this, isDirectRootMethodUpdater); } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java index 9a5c51ebac27..42e1d9c44bc5 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java @@ -101,8 +101,8 @@ public abstract class AnalysisType extends AnalysisElement implements WrappedJav private static final AtomicReferenceFieldUpdater isInHeapUpdater = AtomicReferenceFieldUpdater .newUpdater(AnalysisType.class, Object.class, "isInHeap"); - private static final AtomicIntegerFieldUpdater isReachableUpdater = AtomicIntegerFieldUpdater - .newUpdater(AnalysisType.class, "isReachable"); + private static final AtomicReferenceFieldUpdater isReachableUpdater = AtomicReferenceFieldUpdater + .newUpdater(AnalysisType.class, Object.class, "isReachable"); private static final AtomicIntegerFieldUpdater isAnySubtypeInstantiatedUpdater = AtomicIntegerFieldUpdater .newUpdater(AnalysisType.class, "isAnySubtypeInstantiated"); @@ -112,7 +112,7 @@ public abstract class AnalysisType extends AnalysisElement implements WrappedJav @SuppressWarnings("unused") private volatile Object isInHeap; @SuppressWarnings("unused") private volatile Object isAllocated; - @SuppressWarnings("unused") private volatile int isReachable; + @SuppressWarnings("unused") private volatile Object isReachable; @SuppressWarnings("unused") private volatile int isAnySubtypeInstantiated; private boolean reachabilityListenerNotified; private boolean unsafeFieldsRecomputed; @@ -461,8 +461,8 @@ public static boolean verifyAssignableTypes(BigBang bb) { * describing why this type was manually marked as in-heap */ public boolean registerAsInHeap(Object reason) { - assert reason != null && (!(reason instanceof String) || !reason.equals("")) : "Registering a type as in-heap needs to provide a non-empty reason."; - registerAsReachable(); + assert isValidReason(reason) : "Registering a type as in-heap needs to provide a valid reason."; + registerAsReachable(reason); if (AtomicUtils.atomicSet(this, reason, isInHeapUpdater)) { onInstantiated(UsageKind.InHeap); return true; @@ -476,8 +476,8 @@ public boolean registerAsInHeap(Object reason) { * describing why this type was manually marked as allocated */ public boolean registerAsAllocated(Object reason) { - assert reason != null && (!(reason instanceof String) || !reason.equals("")) : "Registering a type as allocated needs to provide a non-empty reason."; - registerAsReachable(); + assert isValidReason(reason) : "Registering a type as allocated needs to provide a valid reason."; + registerAsReachable(reason); if (AtomicUtils.atomicSet(this, reason, isAllocatedUpdater)) { onInstantiated(UsageKind.Allocated); return true; @@ -531,10 +531,11 @@ private void processMethodOverrides() { public void registerAsAssignable(BigBang bb) { } - public boolean registerAsReachable() { + public boolean registerAsReachable(Object reason) { + assert isValidReason(reason) : "Registering a type as reachable needs to provide a valid reason."; if (!AtomicUtils.isSet(this, isReachableUpdater)) { /* Mark this type and all its super types as reachable. */ - forAllSuperTypes(type -> AtomicUtils.atomicMarkAndRun(type, isReachableUpdater, type::onReachable)); + forAllSuperTypes(type -> AtomicUtils.atomicSetAndRun(type, reason, isReachableUpdater, type::onReachable)); return true; } return false; @@ -1136,7 +1137,6 @@ private AnalysisField[] convertFields(ResolvedJavaField[] original, List(), false); } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java index 0643712bc2d0..b57e2a3ced5f 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java @@ -366,7 +366,7 @@ public JavaField lookupAllowUnresolved(JavaField rawField) { * it during constant folding. */ AnalysisType declaringType = lookup(field.getDeclaringClass()); - declaringType.registerAsReachable(); + declaringType.registerAsReachable(field); declaringType.ensureInitialized(); /* diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/util/AtomicUtils.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/util/AtomicUtils.java index 0aaf489dd86b..470ee17b3c23 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/util/AtomicUtils.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/util/AtomicUtils.java @@ -39,6 +39,15 @@ public static boolean atomicSet(T holder, V value, AtomicReferenceFieldUp return updater.compareAndSet(holder, null, value); } + public static boolean atomicSetAndRun(T holder, V value, AtomicReferenceFieldUpdater updater, Runnable task) { + Objects.requireNonNull(value, "The value parameter of AtomicUtils.atomicSetAndRun() should not be null."); + boolean firstAttempt = updater.compareAndSet(holder, null, value); + if (firstAttempt) { + task.run(); + } + return firstAttempt; + } + public static boolean isSet(T holder, AtomicReferenceFieldUpdater updater) { return updater.get(holder) != null; } diff --git a/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/DirectMethodProcessingHandler.java b/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/DirectMethodProcessingHandler.java index b24c5ab2c3fc..7448f1adfd20 100644 --- a/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/DirectMethodProcessingHandler.java +++ b/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/DirectMethodProcessingHandler.java @@ -79,10 +79,11 @@ private static void analyzeStructuredGraph(ReachabilityAnalysisEngine bb, Reacha int parameterCount = method.getSignature().getParameterCount(!isStatic); int offset = isStatic ? 0 : 1; for (int i = offset; i < parameterCount; i++) { - bb.markTypeAsReachable((ReachabilityAnalysisType) method.getSignature().getParameterType(i - offset, method.getDeclaringClass())); + bb.registerTypeAsReachable((ReachabilityAnalysisType) method.getSignature().getParameterType(i - offset, method.getDeclaringClass()), + "Parameter type for " + method.format("%H.%n(%p)")); } - bb.markTypeAsReachable((ReachabilityAnalysisType) method.getSignature().getReturnType(method.getDeclaringClass())); + bb.registerTypeAsReachable((ReachabilityAnalysisType) method.getSignature().getReturnType(method.getDeclaringClass()), "Return type for " + method.format("%H.%n(%p)")); } for (Node n : graph.getNodes()) { @@ -120,7 +121,7 @@ private static void analyzeStructuredGraph(ReachabilityAnalysisEngine bb, Reacha bb.handleEmbeddedConstant(method, constant, AbstractAnalysisEngine.sourcePosition(node)); } else if (n instanceof InstanceOfNode) { InstanceOfNode node = (InstanceOfNode) n; - bb.markTypeAsReachable((ReachabilityAnalysisType) node.type().getType()); + bb.registerTypeAsReachable((ReachabilityAnalysisType) node.type().getType(), AbstractAnalysisEngine.sourcePosition(node)); } else if (n instanceof LoadFieldNode) { LoadFieldNode node = (LoadFieldNode) n; bb.markFieldRead((ReachabilityAnalysisField) node.field(), AbstractAnalysisEngine.sourcePosition(node)); @@ -135,7 +136,7 @@ private static void analyzeStructuredGraph(ReachabilityAnalysisEngine bb, Reacha continue; } if (method != null) { - method.addInvoke(new ReachabilityInvokeInfo(targetMethod, ReachabilityAnalysisMethod.sourcePosition(node, method), kind.isDirect())); + method.addInvoke(new ReachabilityInvokeInfo(targetMethod, AbstractAnalysisEngine.sourcePosition(node.asNode()), kind.isDirect())); } if (kind.isDirect()) { bb.markMethodImplementationInvoked(targetMethod); @@ -153,7 +154,7 @@ private static void analyzeStructuredGraph(ReachabilityAnalysisEngine bb, Reacha * scanning during static analysis does not see these classes. */ ReachabilityAnalysisMethod analysisMethod = (ReachabilityAnalysisMethod) frameMethod; - bb.markTypeAsReachable(analysisMethod.getDeclaringClass()); + bb.registerTypeAsReachable(analysisMethod.getDeclaringClass(), AbstractAnalysisEngine.syntheticSourcePosition(node, method)); } } else if (n instanceof MacroInvokable) { MacroInvokable node = (MacroInvokable) n; diff --git a/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/MethodSummaryBasedHandler.java b/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/MethodSummaryBasedHandler.java index cf195d98c630..2ab8c907dd88 100644 --- a/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/MethodSummaryBasedHandler.java +++ b/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/MethodSummaryBasedHandler.java @@ -83,14 +83,14 @@ private static void processSummary(ReachabilityAnalysisEngine bb, ReachabilityAn bb.markMethodImplementationInvoked((ReachabilityAnalysisMethod) invokedMethod); } for (AnalysisType type : summary.accessedTypes) { - bb.markTypeAsReachable(type); + bb.registerTypeAsReachable(type, method); } for (AnalysisType type : summary.instantiatedTypes) { bb.registerTypeAsAllocated(type, method); } for (AnalysisField field : summary.readFields) { bb.markFieldRead(field, method); - bb.markTypeAsReachable(field.getType()); + bb.registerTypeAsReachable(field.getType(), method); } for (AnalysisField field : summary.writtenFields) { bb.markFieldWritten(field); 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 82514f0fbfbe..cc48dd51e34b 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 @@ -95,7 +95,6 @@ protected CompletionExecutor.Timing getTiming() { @Override public AnalysisType addRootClass(Class clazz, boolean addFields, boolean addArrayClass) { AnalysisType type = metaAccess.lookupJavaType(clazz); - type.registerAsReachable(); return addRootClass(type, addFields, addArrayClass); } @@ -107,14 +106,13 @@ public AnalysisMethod addRootMethod(Executable method, boolean invokeSpecial) { @SuppressWarnings("try") @Override public AnalysisType addRootClass(AnalysisType type, boolean addFields, boolean addArrayClass) { + type.registerAsReachable("root class"); for (AnalysisField field : type.getInstanceFields(false)) { if (addFields) { field.registerAsAccessed(); } } - markTypeAsReachable(type); - if (type.getSuperclass() != null) { addRootClass(type.getSuperclass(), addFields, addArrayClass); } diff --git a/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/ReachabilityObjectScanner.java b/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/ReachabilityObjectScanner.java index f2aad0f458ae..096e3c8ee59f 100644 --- a/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/ReachabilityObjectScanner.java +++ b/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/ReachabilityObjectScanner.java @@ -60,9 +60,9 @@ public boolean forRelocatedPointerFieldValue(JavaConstant receiver, AnalysisFiel public boolean forNullFieldValue(JavaConstant receiver, AnalysisField field, ObjectScanner.ScanReason reason) { boolean modified = false; if (receiver != null) { - modified = bb.markTypeAsReachable(constantType(receiver)); + modified = bb.registerTypeAsReachable(constantType(receiver), reason); } - return modified || bb.markTypeAsReachable(field.getType()); + return modified || bb.registerTypeAsReachable(field.getType(), reason); } @Override @@ -70,24 +70,24 @@ public boolean forNonNullFieldValue(JavaConstant receiver, AnalysisField field, boolean modified = false; if (receiver != null) { bb.registerTypeAsInHeap(constantType(receiver), reason); - modified = bb.markTypeAsReachable(constantType(receiver)); + modified = bb.registerTypeAsReachable(constantType(receiver), reason); } - return modified || bb.markTypeAsReachable(field.getType()); + return modified || bb.registerTypeAsReachable(field.getType(), reason); } @Override public boolean forNullArrayElement(JavaConstant array, AnalysisType arrayType, int elementIndex, ObjectScanner.ScanReason reason) { - return bb.markTypeAsReachable(arrayType); + return bb.registerTypeAsReachable(arrayType, reason); } @Override public boolean forNonNullArrayElement(JavaConstant array, AnalysisType arrayType, JavaConstant elementConstant, AnalysisType elementType, int elementIndex, ObjectScanner.ScanReason reason) { - return bb.markTypeAsReachable(arrayType) || bb.registerTypeAsInHeap(elementType, reason); + return bb.registerTypeAsReachable(arrayType, reason) || bb.registerTypeAsInHeap(elementType, reason); } @Override public void forEmbeddedRoot(JavaConstant root, ObjectScanner.ScanReason reason) { - bb.markTypeAsReachable(constantType(root)); + bb.registerTypeAsReachable(constantType(root), reason); bb.registerTypeAsInHeap(constantType(root), reason); } diff --git a/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/SimpleInMemoryMethodSummaryProvider.java b/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/SimpleInMemoryMethodSummaryProvider.java index 9fa4fdbbae1d..74427da768f1 100644 --- a/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/SimpleInMemoryMethodSummaryProvider.java +++ b/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/SimpleInMemoryMethodSummaryProvider.java @@ -24,6 +24,7 @@ */ package com.oracle.graal.reachability; +import com.oracle.graal.pointsto.AbstractAnalysisEngine; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.AnalysisType; @@ -143,7 +144,7 @@ private static MethodSummary createSummaryFromGraph(ReachabilityAnalysisEngine b continue; } if (method != null) { - method.addInvoke(new ReachabilityInvokeInfo(targetMethod, ReachabilityAnalysisMethod.sourcePosition(node, method), kind.isDirect())); + method.addInvoke(new ReachabilityInvokeInfo(targetMethod, AbstractAnalysisEngine.sourcePosition(node.asNode()), kind.isDirect())); } if (kind.isDirect()) { implementationInvokedMethods.add(targetMethod); diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/FieldsOffsetsFeature.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/FieldsOffsetsFeature.java index 916bbc44f035..2f3da387922d 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/FieldsOffsetsFeature.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/FieldsOffsetsFeature.java @@ -215,7 +215,7 @@ private static void registerFields(Fields fields, UnsafePartitionKind partitionK for (int i = 0; i < fields.getCount(); i++) { AnalysisField aField = config.getMetaAccess().lookupJavaField(findField(fields, i)); - aField.getType().registerAsReachable(); + aField.getType().registerAsReachable(aField); config.registerAsUnsafeAccessed(aField, partitionKind); } } diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalGraphObjectReplacer.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalGraphObjectReplacer.java index 83f18bce29cd..aa1d6c3a0604 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalGraphObjectReplacer.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalGraphObjectReplacer.java @@ -315,7 +315,7 @@ public synchronized SubstrateType createType(JavaType original) { if (sType == null) { assert !(original instanceof HostedType) : "too late to create new type"; - aType.registerAsReachable(); + aType.registerAsReachable("type reachable from Graal graphs"); DynamicHub hub = ((SVMHost) aUniverse.hostVM()).dynamicHub(aType); sType = new SubstrateType(aType.getJavaKind(), hub); types.put(aType, sType); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureImpl.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureImpl.java index 54dd1518eb34..1c13b7b0fc58 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureImpl.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureImpl.java @@ -341,11 +341,15 @@ public NativeLibraries getNativeLibraries() { @Override public void registerAsUsed(Class clazz) { - registerAsUsed(getMetaAccess().lookupJavaType(clazz)); + registerAsUsed(getMetaAccess().lookupJavaType(clazz), "Registered from Feature API."); } - public void registerAsUsed(AnalysisType aType) { - bb.markTypeAsReachable(aType); + public void registerAsUsed(Class clazz, Object reason) { + registerAsUsed(getMetaAccess().lookupJavaType(clazz), reason); + } + + public void registerAsUsed(AnalysisType aType, Object reason) { + bb.registerTypeAsReachable(aType, reason); } @Override @@ -363,7 +367,6 @@ public void registerAsInHeap(AnalysisType aType, Object reason) { @Override public void registerAsAccessed(Field field) { - registerAsUsed(getMetaAccess().lookupJavaType(field.getDeclaringClass())); registerAsAccessed(getMetaAccess().lookupJavaField(field)); } @@ -372,7 +375,6 @@ public void registerAsAccessed(AnalysisField aField) { } public void registerAsRead(Field field, Object reason) { - getMetaAccess().lookupJavaType(field.getDeclaringClass()).registerAsReachable(); registerAsRead(getMetaAccess().lookupJavaField(field), reason); } @@ -382,7 +384,6 @@ public void registerAsRead(AnalysisField aField, Object reason) { @Override public void registerAsUnsafeAccessed(Field field) { - registerAsUsed(getMetaAccess().lookupJavaType(field.getDeclaringClass())); registerAsUnsafeAccessed(getMetaAccess().lookupJavaField(field)); } @@ -400,7 +401,6 @@ public boolean registerAsUnsafeAccessed(AnalysisField aField, UnsafePartitionKin } public void registerAsFrozenUnsafeAccessed(Field field) { - registerAsUsed(getMetaAccess().lookupJavaType(field.getDeclaringClass())); registerAsFrozenUnsafeAccessed(getMetaAccess().lookupJavaField(field)); } 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 c2ef5c64d822..0ccb52e7ddc2 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 @@ -32,7 +32,6 @@ import java.io.IOException; import java.lang.annotation.Annotation; -import java.lang.ref.Reference; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Type; @@ -132,7 +131,6 @@ import org.graalvm.nativeimage.impl.CConstantValueSupport; import org.graalvm.nativeimage.impl.RuntimeClassInitializationSupport; import org.graalvm.nativeimage.impl.SizeOfSupport; -import org.graalvm.nativeimage.impl.clinit.ClassInitializationTracking; import org.graalvm.word.PointerBase; import com.oracle.graal.pointsto.AnalysisObjectScanningObserver; @@ -1045,17 +1043,17 @@ public static void initializeBigBang(Inflation bb, OptionValues options, Feature * good example. */ try (Indent ignored = debug.logAndIndent("add initial classes/fields/methods")) { - bb.registerTypeAsInHeap(bb.addRootClass(Object.class, false, false), "Root class."); + bb.registerTypeAsInHeap(bb.addRootClass(Object.class, false, false), "root class"); bb.addRootField(DynamicHub.class, "vtable"); - bb.registerTypeAsInHeap(bb.addRootClass(String.class, false, false), "Root class."); - bb.registerTypeAsInHeap(bb.addRootClass(String[].class, false, false), "Root class."); - bb.registerTypeAsInHeap(bb.addRootField(String.class, "value"), "Root class."); - bb.registerTypeAsInHeap(bb.addRootClass(long[].class, false, false), "Root class."); - bb.registerTypeAsInHeap(bb.addRootClass(byte[].class, false, false), "Root class."); - bb.registerTypeAsInHeap(bb.addRootClass(byte[][].class, false, false), "Root class."); - bb.registerTypeAsInHeap(bb.addRootClass(Object[].class, false, false), "Root class."); - bb.registerTypeAsInHeap(bb.addRootClass(CFunctionPointer[].class, false, false), "Root class."); - bb.registerTypeAsInHeap(bb.addRootClass(PointerBase[].class, false, false), "Root class."); + bb.registerTypeAsInHeap(bb.addRootClass(String.class, false, false), "root class"); + bb.registerTypeAsInHeap(bb.addRootClass(String[].class, false, false), "root class"); + bb.registerTypeAsInHeap(bb.addRootField(String.class, "value"), "root class"); + bb.registerTypeAsInHeap(bb.addRootClass(long[].class, false, false), "root class"); + bb.registerTypeAsInHeap(bb.addRootClass(byte[].class, false, false), "root class"); + bb.registerTypeAsInHeap(bb.addRootClass(byte[][].class, false, false), "root class"); + bb.registerTypeAsInHeap(bb.addRootClass(Object[].class, false, false), "root class"); + bb.registerTypeAsInHeap(bb.addRootClass(CFunctionPointer[].class, false, false), "root class"); + bb.registerTypeAsInHeap(bb.addRootClass(PointerBase[].class, false, false), "root class"); bb.addRootMethod(ReflectionUtil.lookupMethod(SubstrateArraycopySnippets.class, "doArraycopy", Object.class, int.class, Object.class, int.class, int.class), true); bb.addRootMethod(ReflectionUtil.lookupMethod(Object.class, "getClass"), true); @@ -1063,7 +1061,7 @@ public static void initializeBigBang(Inflation bb, OptionValues options, Feature for (JavaKind kind : JavaKind.values()) { if (kind.isPrimitive() && kind != JavaKind.Void) { bb.addRootClass(kind.toJavaClass(), false, true); - bb.addRootClass(kind.toBoxedJavaClass(), false, true).registerAsInHeap("Root class."); + bb.addRootClass(kind.toBoxedJavaClass(), false, true).registerAsInHeap("root class"); bb.addRootField(kind.toBoxedJavaClass(), "value"); bb.addRootMethod(ReflectionUtil.lookupMethod(kind.toBoxedJavaClass(), "valueOf", kind.toJavaClass()), true); bb.addRootMethod(ReflectionUtil.lookupMethod(kind.toBoxedJavaClass(), kind.getJavaName() + "Value"), true); @@ -1073,14 +1071,14 @@ public static void initializeBigBang(Inflation bb, OptionValues options, Feature */ Class[] innerClasses = kind.toBoxedJavaClass().getDeclaredClasses(); if (innerClasses != null && innerClasses.length > 0) { - bb.getMetaAccess().lookupJavaType(innerClasses[0]).registerAsReachable(); + bb.getMetaAccess().lookupJavaType(innerClasses[0]).registerAsReachable("inner class of root class"); } } } /* SubstrateTemplates#toLocationIdentity accesses the Counter.value field. */ - bb.getMetaAccess().lookupJavaType(JavaKind.Void.toJavaClass()).registerAsReachable(); - bb.getMetaAccess().lookupJavaType(com.oracle.svm.core.util.Counter.class).registerAsReachable(); - bb.getMetaAccess().lookupJavaType(com.oracle.svm.core.allocationprofile.AllocationCounter.class).registerAsReachable(); + bb.getMetaAccess().lookupJavaType(JavaKind.Void.toJavaClass()).registerAsReachable("root class"); + bb.getMetaAccess().lookupJavaType(com.oracle.svm.core.util.Counter.class).registerAsReachable("root class"); + bb.getMetaAccess().lookupJavaType(com.oracle.svm.core.allocationprofile.AllocationCounter.class).registerAsReachable("root class"); NativeImageGenerator.registerGraphBuilderPlugins(featureHandler, null, aProviders, aMetaAccess, aUniverse, null, null, nativeLibraries, loader, ParsingReason.PointsToAnalysis, bb.getAnnotationSubstitutionProcessor(), classInitializationPlugin, ConfigurationValues.getTarget()); @@ -1108,13 +1106,11 @@ public static Inflation createBigBang(OptionValues options, TargetDescription ta SnippetReflectionProvider aSnippetReflection, AnnotationSubstitutionProcessor annotationSubstitutionProcessor, ForeignCallsProvider aForeignCalls, ClassInitializationSupport classInitializationSupport, Providers originalProviders, SubstratePlatformConfigurationProvider platformConfig) { assert aUniverse != null : "Analysis universe must be initialized."; - aMetaAccess.lookupJavaType(String.class).registerAsReachable(); AnalysisConstantFieldProvider aConstantFieldProvider = new AnalysisConstantFieldProvider(aUniverse, aMetaAccess, aConstantReflection, classInitializationSupport); /* * Install all snippets so that the types, methods, and fields used in the snippets get * added to the universe. */ - aMetaAccess.lookupJavaType(Reference.class).registerAsReachable(); MetaAccessExtensionProvider aMetaAccessExtensionProvider = HostedConfiguration.instance().createAnalysisMetaAccessExtensionProvider(); LoweringProvider aLoweringProvider = SubstrateLoweringProvider.createForHosted(aMetaAccess, null, platformConfig, aMetaAccessExtensionProvider); StampProvider aStampProvider = new SubstrateStampProvider(aMetaAccess); @@ -1264,10 +1260,6 @@ public static void registerGraphBuilderPlugins(FeatureHandler featureHandler, Ru plugins.appendNodePlugin(new IntrinsifyMethodHandlesInvocationPlugin(reason, providers, aUniverse, hUniverse)); plugins.appendNodePlugin(new DeletedFieldsPlugin()); plugins.appendNodePlugin(new InjectedAccessorsPlugin()); - ResolvedJavaType resolvedJavaType = providers.getMetaAccess().lookupJavaType(ClassInitializationTracking.class); - if (resolvedJavaType instanceof AnalysisType) { - ((AnalysisType) resolvedJavaType).registerAsReachable(); - } plugins.appendNodePlugin(new EarlyConstantFoldLoadFieldPlugin(providers.getMetaAccess(), providers.getSnippetReflection())); plugins.appendNodePlugin(new ConstantFoldLoadFieldPlugin(reason)); plugins.appendNodePlugin(new CInterfaceInvocationPlugin(providers.getMetaAccess(), providers.getWordTypes(), nativeLibs)); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantFieldProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantFieldProvider.java index 7b7875389dea..51a16e38e792 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantFieldProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantFieldProvider.java @@ -72,9 +72,14 @@ public T readConstantField(ResolvedJavaField field, ConstantFieldTool ana if (foldedValue != null) { if (!BuildPhaseProvider.isAnalysisFinished()) { - f.markFolded(); + f.registerAsFolded(nonNullReason(analysisTool.getReason())); } } return foldedValue; } + + public static Object nonNullReason(Object reason) { + return reason == null ? "Unknown constant fold location." : reason; + } + } 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 cb23794c4305..2d371a2d1d7c 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,10 @@ */ package com.oracle.svm.hosted.analysis; +import java.util.concurrent.ForkJoinPool; + +import org.graalvm.compiler.options.OptionValues; + import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.meta.AnalysisUniverse; @@ -35,9 +39,6 @@ import com.oracle.svm.core.graal.meta.SubstrateReplacements; import com.oracle.svm.hosted.SVMHost; import com.oracle.svm.hosted.substitute.AnnotationSubstitutionProcessor; -import org.graalvm.compiler.options.OptionValues; - -import java.util.concurrent.ForkJoinPool; public class NativeImageReachabilityAnalysisEngine extends ReachabilityAnalysisEngine implements Inflation { @@ -58,7 +59,7 @@ public NativeImageReachabilityAnalysisEngine(OptionValues options, AnalysisUnive protected void injectFieldTypes(AnalysisField aField, AnalysisType... declaredTypes) { markFieldAccessed(aField); for (AnalysisType declaredType : declaredTypes) { - markTypeAsReachable(declaredType); + registerTypeAsReachable(declaredType, "injected field types for unknown annotated field " + aField.format("%H.%n")); } } }; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/CGlobalDataFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/CGlobalDataFeature.java index ad2cb7b83b5d..ec79b7cc1d40 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/CGlobalDataFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/CGlobalDataFeature.java @@ -75,11 +75,11 @@ import com.oracle.svm.core.c.CGlobalDataImpl; import com.oracle.svm.core.c.CGlobalDataNonConstantRegistry; import com.oracle.svm.core.config.ConfigurationValues; +import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.graal.code.CGlobalDataInfo; import com.oracle.svm.core.graal.nodes.CGlobalDataLoadAddressNode; import com.oracle.svm.core.meta.SubstrateObjectConstant; -import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.image.RelocatableBuffer; import com.oracle.svm.util.ReflectionUtil; @@ -142,7 +142,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec ResolvedJavaType infoType = b.getMetaAccess().lookupJavaType(CGlobalDataInfo.class); if (infoType instanceof AnalysisType) { - ((AnalysisType) infoType).registerAsReachable(); + ((AnalysisType) infoType).registerAsReachable("registered by " + CGlobalDataFeature.class.getName()); } ValueNode offset = b.add(LoadFieldNode.create(b.getAssumptions(), info, b.getMetaAccess().lookupJavaField(offsetField))); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/NativeLibraries.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/NativeLibraries.java index c10336334b54..c6b7c675bfbd 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/NativeLibraries.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/NativeLibraries.java @@ -268,7 +268,7 @@ public NativeLibraries(ConstantReflectionProvider constantReflection, MetaAccess private ResolvedJavaType lookupAndRegisterType(Class clazz) { AnalysisType type = (AnalysisType) metaAccess.lookupJavaType(clazz); - type.registerAsReachable(); + type.registerAsReachable("is native library type"); return type; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/StringInternFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/StringInternFeature.java index c52dfb8fc254..0edc1d6f0588 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/StringInternFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/StringInternFeature.java @@ -30,10 +30,9 @@ import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; -import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; +import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.jdk.StringInternSupport; -import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.hosted.FeatureImpl.BeforeAnalysisAccessImpl; import jdk.vm.ci.meta.MetaAccessProvider; @@ -45,9 +44,6 @@ class StringInternFeature implements InternalFeature { @Platforms(Platform.HOSTED_ONLY.class) public static ResolvedJavaField getInternedStringsField(MetaAccessProvider metaAccess) { try { - if (metaAccess instanceof AnalysisMetaAccess) { - ((AnalysisMetaAccess) metaAccess).lookupJavaType(StringInternSupport.class).registerAsReachable(); - } return metaAccess.lookupJavaField(StringInternSupport.class.getDeclaredField("internedStrings")); } catch (NoSuchFieldException ex) { throw shouldNotReachHere(ex); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIAccessFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIAccessFeature.java index 6e7180322015..fbef32280367 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIAccessFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIAccessFeature.java @@ -253,7 +253,6 @@ private static ConditionalConfigurationRegistry getConditionalConfigurationRegis private static void registerJavaCallTrampoline(BeforeAnalysisAccessImpl access, CallVariant variant, boolean nonVirtual) { MetaAccessProvider originalMetaAccess = access.getMetaAccess().getWrapped(); ResolvedJavaField field = JNIAccessibleMethod.getCallVariantWrapperField(originalMetaAccess, variant, nonVirtual); - access.getUniverse().lookup(field.getDeclaringClass()).registerAsReachable(); access.registerAsAccessed(access.getUniverse().lookup(field)); String name = JNIJavaCallTrampolineHolder.getTrampolineName(variant, nonVirtual); Method method = ReflectionUtil.lookupMethod(JNIJavaCallTrampolineHolder.class, name); @@ -342,9 +341,9 @@ private static JNIAccessibleClass addClass(Class classObj, DuringAnalysisAcce return JNIReflectionDictionary.singleton().addClassIfAbsent(classObj, c -> { AnalysisType analysisClass = access.getMetaAccess().lookupJavaType(classObj); if (analysisClass.isInterface() || (analysisClass.isInstanceClass() && analysisClass.isAbstract())) { - analysisClass.registerAsReachable(); + analysisClass.registerAsReachable("is accessed via JNI"); } else { - access.getBigBang().registerTypeAsAllocated(analysisClass, "Is accessed via JNI."); + access.getBigBang().registerTypeAsAllocated(analysisClass, "is accessed via JNI"); } return new JNIAccessibleClass(classObj); }); @@ -410,7 +409,6 @@ private JNIJavaCallVariantWrapperGroup createJavaCallVariantWrappers(DuringAnaly } private static void addField(Field reflField, boolean writable, DuringAnalysisAccessImpl access) { - access.getMetaAccess().lookupJavaType(reflField.getDeclaringClass()).registerAsReachable(); if (SubstitutionReflectivityFilter.shouldExclude(reflField, access.getMetaAccess(), access.getUniverse())) { return; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/ConstantFoldLoadFieldPlugin.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/ConstantFoldLoadFieldPlugin.java index 9026409daa70..fcfadaa7ad2c 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/ConstantFoldLoadFieldPlugin.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/ConstantFoldLoadFieldPlugin.java @@ -65,7 +65,8 @@ public boolean handleLoadStaticField(GraphBuilderContext b, ResolvedJavaField st private boolean tryConstantFold(GraphBuilderContext b, ResolvedJavaField field, JavaConstant receiver) { ConstantNode result; try { - result = ConstantFoldUtil.tryConstantFold(b.getConstantFieldProvider(), b.getConstantReflection(), b.getMetaAccess(), field, receiver, b.getOptions()); + result = ConstantFoldUtil.tryConstantFold(b.getConstantFieldProvider(), b.getConstantReflection(), b.getMetaAccess(), field, receiver, b.getOptions(), + b.getGraph().currentNodeSourcePosition()); } catch (UnsupportedFeatureException e) { if (reason == ParsingReason.PointsToAnalysis) { AnalysisMetaAccess metaAccess = (AnalysisMetaAccess) b.getMetaAccess(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/HostedGraphKit.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/HostedGraphKit.java index 2fe15341ba6e..6e0e19c86d19 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/HostedGraphKit.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/HostedGraphKit.java @@ -51,7 +51,6 @@ import org.graalvm.compiler.phases.OptimisticOptimizations; import com.oracle.graal.pointsto.meta.AnalysisMethod; -import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.graal.pointsto.results.StaticAnalysisResults; import com.oracle.svm.core.c.BoxedRelocatedPointer; @@ -121,10 +120,6 @@ public T appendWithUnwind(T withExceptionNode) { public LoadFieldNode createLoadFieldNode(ConstantNode receiver, Class clazz, String fieldName) { try { - ResolvedJavaType type = getMetaAccess().lookupJavaType(clazz); - if (type instanceof AnalysisType) { - ((AnalysisType) type).registerAsReachable(); - } ResolvedJavaField field = getMetaAccess().lookupJavaField(clazz.getDeclaredField(fieldName)); return LoadFieldNode.createOverrideStamp(StampPair.createSingle(wordStamp((ResolvedJavaType) field.getType())), receiver, field); } catch (NoSuchFieldException e) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/IntrinsifyMethodHandlesInvocationPlugin.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/IntrinsifyMethodHandlesInvocationPlugin.java index b00718193ae7..3d6ffea29121 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/IntrinsifyMethodHandlesInvocationPlugin.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/IntrinsifyMethodHandlesInvocationPlugin.java @@ -1010,7 +1010,6 @@ private ResolvedJavaMethod lookup(ResolvedJavaMethod method) { } private ResolvedJavaField lookup(ResolvedJavaField field) { - aUniverse.lookup(field.getDeclaringClass()).registerAsReachable(); ResolvedJavaField result = aUniverse.lookup(field); if (hUniverse != null) { result = hUniverse.lookup(result); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SubstrateGraphBuilderPhase.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SubstrateGraphBuilderPhase.java index 3932e9bfc23f..bc9967895c0b 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SubstrateGraphBuilderPhase.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SubstrateGraphBuilderPhase.java @@ -68,7 +68,7 @@ protected InlineInfo tryInline(ValueNode[] args, ResolvedJavaMethod targetMethod * InvocationPlugins.resolvedRegistrations map reachable from * SubstrateReplacements.snippetInvocationPlugins. */ - ((AnalysisType) targetMethod.getDeclaringClass()).registerAsReachable(); + ((AnalysisType) targetMethod.getDeclaringClass()).registerAsReachable("declared method " + targetMethod.format("%H.%n(%p)") + " is inlined"); } return inlineInfo; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionDataBuilder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionDataBuilder.java index 4ae5f17f06eb..c680c861a631 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionDataBuilder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionDataBuilder.java @@ -680,7 +680,7 @@ private static void registerTypes(DuringAnalysisAccessImpl access, Collection clazz) { * Make sure the class is registered as reachable before its fields are accessed below to * build the reflection metadata. */ - type.registerAsReachable(); + type.registerAsReachable("is registered for reflection"); if (unsafeInstantiatedClasses.contains(clazz)) { type.registerAsAllocated("Is registered for reflection."); } 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 8cf09b34b792..8e1a410f4ddc 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 @@ -53,7 +53,6 @@ import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.infrastructure.SubstitutionProcessor; import com.oracle.graal.pointsto.meta.AnalysisField; -import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.annotate.Alias; @@ -320,8 +319,6 @@ public void processComputedValueFields(BigBang bb) { switch (cvField.getRecomputeValueKind()) { case FieldOffset: - AnalysisType targetFieldDeclaringType = bb.getMetaAccess().lookupJavaType(cvField.getTargetField().getDeclaringClass()); - targetFieldDeclaringType.registerAsReachable(); AnalysisField targetField = bb.getMetaAccess().lookupJavaField(cvField.getTargetField()); targetField.registerAsAccessed(); assert !AnnotationAccess.isAnnotationPresent(targetField, Delete.class); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/UnsafeAutomaticSubstitutionProcessor.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/UnsafeAutomaticSubstitutionProcessor.java index 214bbc335884..2735de530b65 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/UnsafeAutomaticSubstitutionProcessor.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/UnsafeAutomaticSubstitutionProcessor.java @@ -298,7 +298,6 @@ void processComputedValueFields(DuringAnalysisAccessImpl access) { switch (cvField.getRecomputeValueKind()) { case FieldOffset: Field targetField = cvField.getTargetField(); - access.getMetaAccess().lookupJavaType(targetField.getDeclaringClass()).registerAsReachable(); if (access.registerAsUnsafeAccessed(access.getMetaAccess().lookupJavaField(targetField))) { access.requireAnalysisIteration(); } diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleFeature.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleFeature.java index d45a8182a81a..0ac6fd956aa0 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleFeature.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleFeature.java @@ -340,7 +340,7 @@ public void beforeAnalysis(BeforeAnalysisAccess access) { ImageSingletons.lookup(TruffleBaseFeature.class).setProfilingEnabled(truffleRuntime.isProfilingEnabled()); for (Class initType : truffleRuntime.getLookupTypes()) { - access.registerAsUsed(initType); + config.registerAsUsed(initType, "Truffle runtime init type."); } // register thread local foreign poll as compiled otherwise the stub won't work diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateKnownTruffleTypes.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateKnownTruffleTypes.java index 601ab8689a43..7d1d12211b69 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateKnownTruffleTypes.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateKnownTruffleTypes.java @@ -48,14 +48,14 @@ public SubstrateKnownTruffleTypes(MetaAccessProvider metaAccess) { @Override protected ResolvedJavaType lookupType(String className) { AnalysisType type = (AnalysisType) super.lookupType(className); - type.registerAsReachable(); + type.registerAsReachable("known Truffle type"); return type; } @Override protected ResolvedJavaType lookupType(Class c) { AnalysisType type = (AnalysisType) super.lookupType(c); - type.registerAsReachable(); + type.registerAsReachable("known Truffle type"); return type; } From 8f8f3f5ff12b8167de1aa5a0f9e79ff4887e8e3f Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Thu, 24 Nov 2022 14:49:33 +0100 Subject: [PATCH 2/2] Add reason for field reachability. --- .../common/spi/ConstantFieldProvider.java | 5 ++ .../StandaloneAnalysisFeatureImpl.java | 26 +++--- .../AnalysisObjectScanningObserver.java | 2 +- .../graal/pointsto/PointsToAnalysis.java | 6 +- .../graal/pointsto/ReachabilityAnalysis.java | 14 ++-- .../pointsto/flow/MethodTypeFlowBuilder.java | 4 +- .../graal/pointsto/meta/AnalysisField.java | 79 +++++++++++-------- .../DirectMethodProcessingHandler.java | 2 +- .../MethodSummaryBasedHandler.java | 2 +- .../ReachabilityAnalysisEngine.java | 4 +- .../ReachabilityObjectScanner.java | 2 +- .../graal/hosted/FieldsOffsetsFeature.java | 12 +-- .../com/oracle/svm/hosted/FeatureImpl.java | 32 ++++---- .../analysis/CustomTypeFieldHandler.java | 2 +- ...NativeImageReachabilityAnalysisEngine.java | 2 +- .../PointsToCustomTypeFieldHandler.java | 2 +- .../svm/hosted/jni/JNIAccessFeature.java | 6 +- .../hosted/reflect/ReflectionDataBuilder.java | 2 +- .../SubstrateGraphBuilderPlugins.java | 29 ++++--- .../AnnotationSubstitutionProcessor.java | 4 +- .../hosted/substitute/ComputedValueField.java | 2 +- .../UnsafeAutomaticSubstitutionProcessor.java | 2 +- .../oracle/svm/truffle/TruffleFeature.java | 2 +- 23 files changed, 134 insertions(+), 109 deletions(-) diff --git a/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/ConstantFieldProvider.java b/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/ConstantFieldProvider.java index 4ec55219fcb9..36473d487926 100644 --- a/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/ConstantFieldProvider.java +++ b/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/ConstantFieldProvider.java @@ -42,6 +42,11 @@ public interface ConstantFieldTool { JavaConstant getReceiver(); + /** + * The reason why this constant folding was attempted. Ideally this is a + * {@link jdk.vm.ci.code.BytecodePosition}, where available, or a {@link String} + * description, however it can be {@code null}. + */ Object getReason(); T foldConstant(JavaConstant ret); diff --git a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/features/StandaloneAnalysisFeatureImpl.java b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/features/StandaloneAnalysisFeatureImpl.java index cff12f7f5933..3d72bf4b593f 100644 --- a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/features/StandaloneAnalysisFeatureImpl.java +++ b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/features/StandaloneAnalysisFeatureImpl.java @@ -185,11 +185,11 @@ public void registerAsInHeap(AnalysisType aType, Object reason) { @Override public void registerAsAccessed(Field field) { - registerAsAccessed(getMetaAccess().lookupJavaField(field)); + registerAsAccessed(getMetaAccess().lookupJavaField(field), "registered from Feature API"); } - public void registerAsAccessed(AnalysisField aField) { - aField.registerAsAccessed(); + public void registerAsAccessed(AnalysisField aField, Object reason) { + aField.registerAsAccessed(reason); } public void registerAsRead(Field field) { @@ -202,14 +202,14 @@ public void registerAsRead(AnalysisField aField) { @Override public void registerAsUnsafeAccessed(Field field) { - registerAsUnsafeAccessed(getMetaAccess().lookupJavaField(field)); + registerAsUnsafeAccessed(getMetaAccess().lookupJavaField(field), "registered from Feature API"); } - public boolean registerAsUnsafeAccessed(AnalysisField aField) { + public boolean registerAsUnsafeAccessed(AnalysisField aField, Object reason) { if (!aField.isUnsafeAccessed()) { /* Register the field as unsafe accessed. */ - aField.registerAsAccessed(); - aField.registerAsUnsafeAccessed(); + aField.registerAsAccessed(reason); + aField.registerAsUnsafeAccessed(reason); /* Force the update of registered unsafe loads and stores. */ bb.forceUnsafeUpdate(aField); return true; @@ -223,18 +223,18 @@ public void registerAsFrozenUnsafeAccessed(Field field) { public void registerAsFrozenUnsafeAccessed(AnalysisField aField) { aField.setUnsafeFrozenTypeState(true); - registerAsUnsafeAccessed(aField); + registerAsUnsafeAccessed(aField, "registered from standalone feature"); } - public void registerAsUnsafeAccessed(Field field, UnsafePartitionKind partitionKind) { - registerAsUnsafeAccessed(getMetaAccess().lookupJavaField(field), partitionKind); + public void registerAsUnsafeAccessed(Field field, UnsafePartitionKind partitionKind, Object reason) { + registerAsUnsafeAccessed(getMetaAccess().lookupJavaField(field), partitionKind, reason); } - public void registerAsUnsafeAccessed(AnalysisField aField, UnsafePartitionKind partitionKind) { + public void registerAsUnsafeAccessed(AnalysisField aField, UnsafePartitionKind partitionKind, Object reason) { if (!aField.isUnsafeAccessed()) { /* Register the field as unsafe accessed. */ - aField.registerAsAccessed(); - aField.registerAsUnsafeAccessed(partitionKind); + aField.registerAsAccessed(reason); + aField.registerAsUnsafeAccessed(partitionKind, reason); /* Force the update of registered unsafe loads and stores. */ bb.forceUnsafeUpdate(aField); } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AnalysisObjectScanningObserver.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AnalysisObjectScanningObserver.java index a8d6366221ad..309a05eabd4d 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AnalysisObjectScanningObserver.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AnalysisObjectScanningObserver.java @@ -45,7 +45,7 @@ public AnalysisObjectScanningObserver(BigBang bb) { @Override public boolean forRelocatedPointerFieldValue(JavaConstant receiver, AnalysisField field, JavaConstant fieldValue, ScanReason reason) { if (!field.isWritten()) { - return field.registerAsWritten(null); + return field.registerAsWritten(reason); } return false; } 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 6a39c3bc0380..6d63c8270f60 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 @@ -396,7 +396,7 @@ public AnalysisType addRootClass(AnalysisType type, boolean addFields, boolean a type.registerAsReachable("root class"); for (AnalysisField field : type.getInstanceFields(false)) { if (addFields) { - field.registerAsAccessed(); + field.registerAsAccessed("field of root class"); } /* * For system classes any instantiated (sub)type of the declared field type can be @@ -420,7 +420,7 @@ public AnalysisType addRootField(Class clazz, String fieldName) { AnalysisType type = addRootClass(clazz, false, false); for (AnalysisField field : type.getInstanceFields(true)) { if (field.getName().equals(fieldName)) { - field.registerAsAccessed(); + field.registerAsAccessed("root field"); /* * For system classes any instantiated (sub)type of the declared field type can be * written to the field flow. @@ -440,7 +440,7 @@ public AnalysisType addRootStaticField(Class clazz, String fieldName) { try { reflectField = clazz.getField(fieldName); AnalysisField field = metaAccess.lookupJavaField(reflectField); - field.registerAsAccessed(); + field.registerAsAccessed("static root field"); TypeFlow fieldFlow = field.getType().getTypeFlow(this, true); fieldFlow.addUse(this, field.getStaticFieldFlow()); return field.getType(); 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 9b9cbd0cb05c..45760779d8df 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 @@ -43,7 +43,7 @@ public interface ReachabilityAnalysis { /** * Marks given class and all its superclasses as reachable. - * + * * @param clazz class to be marked * @param addFields if true, all instance fiels are marked as accessed * @param addArrayClass if true, the array class is registered as well @@ -85,8 +85,8 @@ default void registerAsFrozenUnsafeAccessed(AnalysisField field) { field.setUnsafeFrozenTypeState(true); } - default boolean registerAsUnsafeAccessed(AnalysisField field, UnsafePartitionKind partitionKind) { - if (field.registerAsUnsafeAccessed(partitionKind)) { + default boolean registerAsUnsafeAccessed(AnalysisField field, UnsafePartitionKind partitionKind, Object reason) { + if (field.registerAsUnsafeAccessed(partitionKind, reason)) { forceUnsafeUpdate(field); return true; } @@ -105,16 +105,16 @@ default boolean registerTypeAsInHeap(AnalysisType type, Object reason) { return type.registerAsInHeap(reason); } - default void markFieldAccessed(AnalysisField field) { - field.registerAsAccessed(); + default void markFieldAccessed(AnalysisField field, Object reason) { + field.registerAsAccessed(reason); } default void markFieldRead(AnalysisField field, Object reason) { field.registerAsRead(reason); } - default void markFieldWritten(AnalysisField field) { - field.registerAsWritten(null); + default void markFieldWritten(AnalysisField field, Object reason) { + field.registerAsWritten(reason); } /** diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java index b3e27139a4ae..a6663a611ff6 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java @@ -255,7 +255,7 @@ public void registerUsedElements(boolean registerEmbeddedRoots) { ValueNode value = values.get(objectStartIndex + i); if (!value.isJavaConstant() || !value.asJavaConstant().isDefaultForKind()) { AnalysisField field = (AnalysisField) ((VirtualInstanceNode) virtualObject).field(i); - field.registerAsWritten(method); + field.registerAsWritten(AbstractAnalysisEngine.sourcePosition(node)); } } } @@ -288,7 +288,7 @@ public void registerUsedElements(boolean registerEmbeddedRoots) { } else if (n instanceof StoreFieldNode) { StoreFieldNode node = (StoreFieldNode) n; AnalysisField field = (AnalysisField) node.field(); - field.registerAsWritten(method); + field.registerAsWritten(AbstractAnalysisEngine.sourcePosition(node)); } else if (n instanceof ConstantNode) { ConstantNode cn = (ConstantNode) n; diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisField.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisField.java index b57d00857e7c..1596d2858151 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisField.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisField.java @@ -60,20 +60,20 @@ public abstract class AnalysisField extends AnalysisElement implements WrappedJa private static final AtomicReferenceFieldUpdater OBSERVERS_UPDATER = // AtomicReferenceFieldUpdater.newUpdater(AnalysisField.class, Object.class, "observers"); - private static final AtomicIntegerFieldUpdater isAccessedUpdater = AtomicIntegerFieldUpdater - .newUpdater(AnalysisField.class, "isAccessed"); + private static final AtomicReferenceFieldUpdater isAccessedUpdater = AtomicReferenceFieldUpdater + .newUpdater(AnalysisField.class, Object.class, "isAccessed"); private static final AtomicReferenceFieldUpdater isReadUpdater = AtomicReferenceFieldUpdater .newUpdater(AnalysisField.class, Object.class, "isRead"); - private static final AtomicIntegerFieldUpdater isWrittenUpdater = AtomicIntegerFieldUpdater - .newUpdater(AnalysisField.class, "isWritten"); + private static final AtomicReferenceFieldUpdater isWrittenUpdater = AtomicReferenceFieldUpdater + .newUpdater(AnalysisField.class, Object.class, "isWritten"); private static final AtomicReferenceFieldUpdater isFoldedUpdater = AtomicReferenceFieldUpdater .newUpdater(AnalysisField.class, Object.class, "isFolded"); - private static final AtomicIntegerFieldUpdater isUnsafeAccessedUpdater = AtomicIntegerFieldUpdater - .newUpdater(AnalysisField.class, "isUnsafeAccessed"); + private static final AtomicReferenceFieldUpdater isUnsafeAccessedUpdater = AtomicReferenceFieldUpdater + .newUpdater(AnalysisField.class, Object.class, "isUnsafeAccessed"); private static final AtomicIntegerFieldUpdater unsafeFrozenTypeStateUpdater = AtomicIntegerFieldUpdater .newUpdater(AnalysisField.class, "unsafeFrozenTypeState"); @@ -94,15 +94,15 @@ public abstract class AnalysisField extends AnalysisElement implements WrappedJa */ private ContextInsensitiveFieldTypeFlow instanceFieldFlow; - @SuppressWarnings("unused") private volatile int isAccessed; - /** Contains the {@link BytecodePosition} of the read or a reason object. */ + /** The reason flags contain a {@link BytecodePosition} or a reason object. */ @SuppressWarnings("unused") private volatile Object isRead; - @SuppressWarnings("unused") private volatile int isWritten; + @SuppressWarnings("unused") private volatile Object isAccessed; + @SuppressWarnings("unused") private volatile Object isWritten; @SuppressWarnings("unused") private volatile Object isFolded; private boolean isJNIAccessed; private boolean isUsedInComparison; - @SuppressWarnings("unused") private volatile int isUnsafeAccessed; + @SuppressWarnings("unused") private volatile Object isUnsafeAccessed; @SuppressWarnings("unused") private volatile int unsafeFrozenTypeState; @SuppressWarnings("unused") private volatile Object observers; @@ -113,7 +113,7 @@ public abstract class AnalysisField extends AnalysisElement implements WrappedJa private boolean canBeNull; private ConcurrentMap readBy; - private ConcurrentMap writtenBy; + private ConcurrentMap writtenBy; protected TypeState instanceFieldTypeState; @@ -187,9 +187,9 @@ public void copyAccessInfos(AnalysisField other) { } public void intersectAccessInfos(AnalysisField other) { - isAccessedUpdater.set(this, this.isAccessed & other.isAccessed); + isAccessedUpdater.set(this, this.isAccessed != null & other.isAccessed != null ? this.isAccessed : null); this.canBeNull = this.canBeNull && other.canBeNull; - isWrittenUpdater.set(this, this.isWritten & other.isWritten); + isWrittenUpdater.set(this, this.isWritten != null & other.isWritten != null ? this.isWritten : null); isFoldedUpdater.set(this, this.isFolded != null & other.isFolded != null ? this.isFolded : null); isReadUpdater.set(this, this.isRead != null & other.isRead != null ? this.isRead : null); notifyUpdateAccessInfo(); @@ -262,8 +262,9 @@ public void cleanupAfterAnalysis() { instanceFieldTypeState = null; } - public boolean registerAsAccessed() { - boolean firstAttempt = AtomicUtils.atomicMark(this, isAccessedUpdater); + public boolean registerAsAccessed(Object reason) { + assert isValidReason(reason) : "Registering a field as accessed needs to provide a valid reason."; + boolean firstAttempt = AtomicUtils.atomicSet(this, reason, isAccessedUpdater); notifyUpdateAccessInfo(); if (firstAttempt) { onReachable(); @@ -274,11 +275,10 @@ public boolean registerAsAccessed() { } /** - * @param reason the {@link BytecodePosition} where a load from this field is seen, or a - * {@link String} describing why this field was manually marked as read + * @param reason the reason why this field is read, non-null */ public boolean registerAsRead(Object reason) { - assert isValidReason(reason) : "Registering a field as read needs to provide a non-empty reason."; + assert isValidReason(reason) : "Registering a field as read needs to provide a valid reason."; boolean firstAttempt = AtomicUtils.atomicSet(this, reason, isReadUpdater); notifyUpdateAccessInfo(); if (readBy != null) { @@ -295,14 +295,14 @@ public boolean registerAsRead(Object reason) { /** * Registers that the field is written. * - * @param method The method where the field is written or null if the method is not known, e.g. - * for an unsafe accessed field. + * @param reason the reason why this field is written, non-null */ - public boolean registerAsWritten(AnalysisMethod method) { - boolean firstAttempt = AtomicUtils.atomicMark(this, isWrittenUpdater); + public boolean registerAsWritten(Object reason) { + assert isValidReason(reason) : "Registering a field as written needs to provide a valid reason."; + boolean firstAttempt = AtomicUtils.atomicSet(this, reason, isWrittenUpdater); notifyUpdateAccessInfo(); - if (writtenBy != null && method != null) { - writtenBy.put(method, Boolean.TRUE); + if (writtenBy != null && reason != null) { + writtenBy.put(reason, Boolean.TRUE); } if (firstAttempt) { onReachable(); @@ -314,19 +314,20 @@ public boolean registerAsWritten(AnalysisMethod method) { } public void registerAsFolded(Object reason) { - assert isValidReason(reason) : "Registering a field as folded needs to provide a non-empty reason."; + assert isValidReason(reason) : "Registering a field as folded needs to provide a valid reason."; if (AtomicUtils.atomicSet(this, reason, isFoldedUpdater)) { assert getDeclaringClass().isReachable(); onReachable(); } } - public void registerAsUnsafeAccessed() { - registerAsUnsafeAccessed(DefaultUnsafePartition.get()); + public void registerAsUnsafeAccessed(Object reason) { + registerAsUnsafeAccessed(DefaultUnsafePartition.get(), reason); } - public boolean registerAsUnsafeAccessed(UnsafePartitionKind partitionKind) { - registerAsAccessed(); + public boolean registerAsUnsafeAccessed(UnsafePartitionKind partitionKind, Object reason) { + assert isValidReason(reason) : "Registering a field as unsafe accessed needs to provide a valid reason."; + registerAsAccessed(reason); /* * A field can potentially be registered as unsafe accessed multiple times. This is * especially true for the Graal nodes because FieldsOffsetsFeature.registerFields iterates @@ -336,7 +337,7 @@ public boolean registerAsUnsafeAccessed(UnsafePartitionKind partitionKind) { * only register fields as unsafe accessed with their declaring type once. */ - if (AtomicUtils.atomicMark(this, isUnsafeAccessedUpdater)) { + if (AtomicUtils.atomicSet(this, reason, isUnsafeAccessedUpdater)) { /* * The atomic updater ensures that the field is registered as unsafe accessed with its * declaring class only once. However, at the end of this call the registration might @@ -345,7 +346,7 @@ public boolean registerAsUnsafeAccessed(UnsafePartitionKind partitionKind) { * might still be in progress. */ - registerAsWritten(null); + registerAsWritten(reason); if (isStatic()) { /* Register the static field as unsafe accessed with the analysis universe. */ @@ -389,10 +390,14 @@ public Object getReadBy() { * Returns all methods where the field is written. It does not include the methods where the * field is written with unsafe access. */ - public Set getWrittenBy() { + public Set getWrittenBy() { return writtenBy.keySet(); } + private boolean isAccessedSet() { + return AtomicUtils.isSet(this, isAccessedUpdater); + } + /** * Returns true if the field is reachable. Fields that are read or manually registered as * reachable are always reachable. For fields that are write-only, more cases need to be @@ -421,10 +426,18 @@ public boolean isRead() { return AtomicUtils.isSet(this, isAccessedUpdater) || AtomicUtils.isSet(this, isReadUpdater); } + private boolean isWrittenSet() { + return AtomicUtils.isSet(this, isWrittenUpdater); + } + public boolean isWritten() { return AtomicUtils.isSet(this, isAccessedUpdater) || AtomicUtils.isSet(this, isWrittenUpdater); } + private boolean isFoldedSet() { + return AtomicUtils.isSet(this, isFoldedUpdater); + } + public boolean isFolded() { return AtomicUtils.isSet(this, isFoldedUpdater); } @@ -510,7 +523,7 @@ public AnnotatedElement getAnnotationRoot() { @Override public String toString() { - return "AnalysisField<" + format("%h.%n") + " accessed: " + isAccessed + " reads: " + isReadSet() + " written: " + isWritten + " folded: " + isFolded + ">"; + return "AnalysisField<" + format("%h.%n") + " accessed: " + isAccessedSet() + " reads: " + isReadSet() + " written: " + isWrittenSet() + " folded: " + isFoldedSet() + ">"; } public void markAsUsedInComparison() { diff --git a/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/DirectMethodProcessingHandler.java b/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/DirectMethodProcessingHandler.java index 7448f1adfd20..d63642edb581 100644 --- a/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/DirectMethodProcessingHandler.java +++ b/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/DirectMethodProcessingHandler.java @@ -127,7 +127,7 @@ private static void analyzeStructuredGraph(ReachabilityAnalysisEngine bb, Reacha bb.markFieldRead((ReachabilityAnalysisField) node.field(), AbstractAnalysisEngine.sourcePosition(node)); } else if (n instanceof StoreFieldNode) { StoreFieldNode node = (StoreFieldNode) n; - bb.markFieldWritten((ReachabilityAnalysisField) node.field()); + bb.markFieldWritten((ReachabilityAnalysisField) node.field(), AbstractAnalysisEngine.sourcePosition(node)); } else if (n instanceof Invoke) { Invoke node = (Invoke) n; CallTargetNode.InvokeKind kind = node.getInvokeKind(); diff --git a/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/MethodSummaryBasedHandler.java b/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/MethodSummaryBasedHandler.java index 2ab8c907dd88..45e361766412 100644 --- a/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/MethodSummaryBasedHandler.java +++ b/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/MethodSummaryBasedHandler.java @@ -93,7 +93,7 @@ private static void processSummary(ReachabilityAnalysisEngine bb, ReachabilityAn bb.registerTypeAsReachable(field.getType(), method); } for (AnalysisField field : summary.writtenFields) { - bb.markFieldWritten(field); + bb.markFieldWritten(field, method); } for (JavaConstant constant : summary.embeddedConstants) { bb.handleEmbeddedConstant(method, constant, method); 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 cc48dd51e34b..5ca3ac399d63 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 @@ -109,7 +109,7 @@ public AnalysisType addRootClass(AnalysisType type, boolean addFields, boolean a type.registerAsReachable("root class"); for (AnalysisField field : type.getInstanceFields(false)) { if (addFields) { - field.registerAsAccessed(); + field.registerAsAccessed("field of root class"); } } @@ -128,7 +128,7 @@ public AnalysisType addRootField(Class clazz, String fieldName) { AnalysisType type = addRootClass(clazz, false, false); for (AnalysisField field : type.getInstanceFields(true)) { if (field.getName().equals(fieldName)) { - field.registerAsAccessed(); + field.registerAsAccessed("root field"); return field.getType(); } } diff --git a/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/ReachabilityObjectScanner.java b/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/ReachabilityObjectScanner.java index 096e3c8ee59f..4b007e18c25f 100644 --- a/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/ReachabilityObjectScanner.java +++ b/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/ReachabilityObjectScanner.java @@ -51,7 +51,7 @@ public ReachabilityObjectScanner(BigBang bb, AnalysisMetaAccess access) { @Override public boolean forRelocatedPointerFieldValue(JavaConstant receiver, AnalysisField field, JavaConstant fieldValue, ObjectScanner.ScanReason reason) { if (!field.isWritten()) { - return field.registerAsWritten(null); + return field.registerAsWritten(reason); } return false; } diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/FieldsOffsetsFeature.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/FieldsOffsetsFeature.java index 2f3da387922d..05037335e037 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/FieldsOffsetsFeature.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/FieldsOffsetsFeature.java @@ -192,31 +192,31 @@ private static void registerFields(FieldIntrospection introspection, BeforeAn NodeClass nodeClass = (NodeClass) introspection; Fields dataFields = nodeClass.getData(); - registerFields(dataFields, DefaultUnsafePartition.get(), config); + registerFields(dataFields, DefaultUnsafePartition.get(), config, "Graal node data field"); Fields inputEdges = nodeClass.getInputEdges(); - registerFields(inputEdges, GraalEdgeUnsafePartition.get(), config); + registerFields(inputEdges, GraalEdgeUnsafePartition.get(), config, "Graal node input edge"); Fields successorEdges = nodeClass.getSuccessorEdges(); - registerFields(successorEdges, GraalEdgeUnsafePartition.get(), config); + registerFields(successorEdges, GraalEdgeUnsafePartition.get(), config, "Graal node successor edge"); /* Ensure field shortName is initialized, so that the instance is immutable. */ nodeClass.shortName(); } else { for (Fields fields : introspection.getAllFields()) { - registerFields(fields, DefaultUnsafePartition.get(), config); + registerFields(fields, DefaultUnsafePartition.get(), config, "Graal field"); } } } - private static void registerFields(Fields fields, UnsafePartitionKind partitionKind, BeforeAnalysisAccessImpl config) { + private static void registerFields(Fields fields, UnsafePartitionKind partitionKind, BeforeAnalysisAccessImpl config, Object reason) { getReplacements().put(fields.getOffsets(), new FieldsOffsetsReplacement(fields)); for (int i = 0; i < fields.getCount(); i++) { AnalysisField aField = config.getMetaAccess().lookupJavaField(findField(fields, i)); aField.getType().registerAsReachable(aField); - config.registerAsUnsafeAccessed(aField, partitionKind); + config.registerAsUnsafeAccessed(aField, partitionKind, reason); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureImpl.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureImpl.java index 1c13b7b0fc58..bcd460c59392 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureImpl.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureImpl.java @@ -341,7 +341,7 @@ public NativeLibraries getNativeLibraries() { @Override public void registerAsUsed(Class clazz) { - registerAsUsed(getMetaAccess().lookupJavaType(clazz), "Registered from Feature API."); + registerAsUsed(getMetaAccess().lookupJavaType(clazz), "registered from Feature API"); } public void registerAsUsed(Class clazz, Object reason) { @@ -354,7 +354,7 @@ public void registerAsUsed(AnalysisType aType, Object reason) { @Override public void registerAsInHeap(Class clazz) { - registerAsInHeap(getMetaAccess().lookupJavaType(clazz), "Registered from Feature API."); + registerAsInHeap(getMetaAccess().lookupJavaType(clazz), "registered from Feature API"); } public void registerAsInHeap(Class clazz, Object reason) { @@ -367,11 +367,11 @@ public void registerAsInHeap(AnalysisType aType, Object reason) { @Override public void registerAsAccessed(Field field) { - registerAsAccessed(getMetaAccess().lookupJavaField(field)); + registerAsAccessed(getMetaAccess().lookupJavaField(field), "registered from Feature API"); } - public void registerAsAccessed(AnalysisField aField) { - bb.markFieldAccessed(aField); + public void registerAsAccessed(AnalysisField aField, Object reason) { + bb.markFieldAccessed(aField, reason); } public void registerAsRead(Field field, Object reason) { @@ -384,29 +384,29 @@ public void registerAsRead(AnalysisField aField, Object reason) { @Override public void registerAsUnsafeAccessed(Field field) { - registerAsUnsafeAccessed(getMetaAccess().lookupJavaField(field)); + registerAsUnsafeAccessed(getMetaAccess().lookupJavaField(field), "registered from Feature API"); } - public boolean registerAsUnsafeAccessed(AnalysisField aField) { - return registerAsUnsafeAccessed(aField, DefaultUnsafePartition.get()); + public boolean registerAsUnsafeAccessed(AnalysisField aField, Object reason) { + return registerAsUnsafeAccessed(aField, DefaultUnsafePartition.get(), reason); } - public void registerAsUnsafeAccessed(Field field, UnsafePartitionKind partitionKind) { - registerAsUnsafeAccessed(getMetaAccess().lookupJavaField(field), partitionKind); + public void registerAsUnsafeAccessed(Field field, UnsafePartitionKind partitionKind, Object reason) { + registerAsUnsafeAccessed(getMetaAccess().lookupJavaField(field), partitionKind, reason); } - public boolean registerAsUnsafeAccessed(AnalysisField aField, UnsafePartitionKind partitionKind) { + public boolean registerAsUnsafeAccessed(AnalysisField aField, UnsafePartitionKind partitionKind, Object reason) { assert !AnnotationAccess.isAnnotationPresent(aField, Delete.class); - return bb.registerAsUnsafeAccessed(aField, partitionKind); + return bb.registerAsUnsafeAccessed(aField, partitionKind, reason); } - public void registerAsFrozenUnsafeAccessed(Field field) { - registerAsFrozenUnsafeAccessed(getMetaAccess().lookupJavaField(field)); + public void registerAsFrozenUnsafeAccessed(Field field, Object reason) { + registerAsFrozenUnsafeAccessed(getMetaAccess().lookupJavaField(field), reason); } - public void registerAsFrozenUnsafeAccessed(AnalysisField aField) { + public void registerAsFrozenUnsafeAccessed(AnalysisField aField, Object reason) { bb.registerAsFrozenUnsafeAccessed(aField); - registerAsUnsafeAccessed(aField); + registerAsUnsafeAccessed(aField, reason); } public void registerAsRoot(Executable method, boolean invokeSpecial) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/CustomTypeFieldHandler.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/CustomTypeFieldHandler.java index 921e56413ad3..a56a9d31bb03 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/CustomTypeFieldHandler.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/CustomTypeFieldHandler.java @@ -85,7 +85,7 @@ public void handleField(AnalysisField field) { * Register a primitive field as containing unknown values(s), i.e., is usually * written only in hosted code. */ - field.registerAsWritten(null); + field.registerAsWritten("@UnknownPrimitiveField annotated field"); } } processedFields.add(field); 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 2d371a2d1d7c..e90aa64933e5 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 @@ -57,7 +57,7 @@ public NativeImageReachabilityAnalysisEngine(OptionValues options, AnalysisUnive this.unknownFieldHandler = new CustomTypeFieldHandler(this, metaAccess) { @Override protected void injectFieldTypes(AnalysisField aField, AnalysisType... declaredTypes) { - markFieldAccessed(aField); + markFieldAccessed(aField, "@UnknownObjectField annotated field."); for (AnalysisType declaredType : declaredTypes) { registerTypeAsReachable(declaredType, "injected field types for unknown annotated field " + aField.format("%H.%n")); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/PointsToCustomTypeFieldHandler.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/PointsToCustomTypeFieldHandler.java index 5b09f969ecd6..bfc1716195c3 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/PointsToCustomTypeFieldHandler.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/PointsToCustomTypeFieldHandler.java @@ -43,7 +43,7 @@ public PointsToCustomTypeFieldHandler(BigBang bb, AnalysisMetaAccess metaAccess) protected void injectFieldTypes(AnalysisField aField, AnalysisType... customTypes) { NativeImagePointsToAnalysis analysis = (NativeImagePointsToAnalysis) bb; - aField.registerAsWritten(null); + aField.registerAsWritten("@UnknownObjectField annotated field"); /* Link the field with all declared types. */ for (AnalysisType type : customTypes) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIAccessFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIAccessFeature.java index fbef32280367..b22980d275c7 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIAccessFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIAccessFeature.java @@ -253,7 +253,7 @@ private static ConditionalConfigurationRegistry getConditionalConfigurationRegis private static void registerJavaCallTrampoline(BeforeAnalysisAccessImpl access, CallVariant variant, boolean nonVirtual) { MetaAccessProvider originalMetaAccess = access.getMetaAccess().getWrapped(); ResolvedJavaField field = JNIAccessibleMethod.getCallVariantWrapperField(originalMetaAccess, variant, nonVirtual); - access.registerAsAccessed(access.getUniverse().lookup(field)); + access.registerAsAccessed(access.getUniverse().lookup(field), "it is registered for JNI accessed"); String name = JNIJavaCallTrampolineHolder.getTrampolineName(variant, nonVirtual); Method method = ReflectionUtil.lookupMethod(JNIJavaCallTrampolineHolder.class, name); access.registerAsRoot(method, true); @@ -416,9 +416,9 @@ private static void addField(Field reflField, boolean writable, DuringAnalysisAc AnalysisField field = access.getMetaAccess().lookupJavaField(reflField); jniClass.addFieldIfAbsent(field.getName(), name -> new JNIAccessibleField(jniClass, field.getJavaKind(), field.getModifiers())); field.registerAsJNIAccessed(); - field.registerAsRead("it is registered for JNI access"); + field.registerAsRead("it is registered for as JNI accessed"); if (writable) { - field.registerAsWritten(null); + field.registerAsWritten("it is registered as JNI writable"); AnalysisType fieldType = field.getType(); if (fieldType.isArray() && !access.isReachable(fieldType)) { // For convenience, make the array type reachable if its elemental type becomes diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionDataBuilder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionDataBuilder.java index c680c861a631..6d515abc92ff 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionDataBuilder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionDataBuilder.java @@ -475,7 +475,7 @@ private void registerTypesForField(DuringAnalysisAccessImpl access, AnalysisFiel * registered as unsafe-accessible, whether they have been explicitly registered or their * Field object is reachable in the image heap. */ - access.registerAsUnsafeAccessed(analysisField); + access.registerAsUnsafeAccessed(analysisField, "is registered for reflection"); /* * The generic signature is parsed at run time, so we need to make all the types necessary diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java index 8bd7f96058d2..9a6d862f3be0 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java @@ -38,7 +38,6 @@ import java.util.function.Function; import java.util.stream.Stream; -import com.oracle.graal.pointsto.AbstractAnalysisEngine; import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.core.common.CompressEncoding; import org.graalvm.compiler.core.common.type.AbstractObjectStamp; @@ -47,6 +46,7 @@ import org.graalvm.compiler.graph.Edges; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.NodeList; +import org.graalvm.compiler.graph.NodeSourcePosition; import org.graalvm.compiler.java.BytecodeParser; import org.graalvm.compiler.nodes.AbstractBeginNode; import org.graalvm.compiler.nodes.ConstantNode; @@ -106,6 +106,7 @@ import org.graalvm.word.PointerBase; import org.graalvm.word.UnsignedWord; +import com.oracle.graal.pointsto.AbstractAnalysisEngine; import com.oracle.graal.pointsto.infrastructure.OriginalFieldProvider; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisType; @@ -486,7 +487,7 @@ private static void registerAtomicUpdaterPlugins(MetaAccessProvider metaAccess, referenceUpdaterRegistration.register(new RequiredInvocationPlugin("newUpdater", Class.class, Class.class, String.class) { @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode tclassNode, ValueNode vclassNode, ValueNode fieldNameNode) { - interceptUpdaterInvoke(metaAccess, snippetReflection, reason, tclassNode, fieldNameNode); + interceptUpdaterInvoke(b, metaAccess, snippetReflection, reason, tclassNode, fieldNameNode); /* Always return false; the call is not replaced. */ return false; } @@ -496,7 +497,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec integerUpdaterRegistration.register(new RequiredInvocationPlugin("newUpdater", Class.class, String.class) { @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode tclassNode, ValueNode fieldNameNode) { - interceptUpdaterInvoke(metaAccess, snippetReflection, reason, tclassNode, fieldNameNode); + interceptUpdaterInvoke(b, metaAccess, snippetReflection, reason, tclassNode, fieldNameNode); /* Always return false; the call is not replaced. */ return false; } @@ -506,7 +507,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec longUpdaterRegistration.register(new RequiredInvocationPlugin("newUpdater", Class.class, String.class) { @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode tclassNode, ValueNode fieldNameNode) { - interceptUpdaterInvoke(metaAccess, snippetReflection, reason, tclassNode, fieldNameNode); + interceptUpdaterInvoke(b, metaAccess, snippetReflection, reason, tclassNode, fieldNameNode); /* Always return false; the call is not replaced. */ return false; } @@ -517,7 +518,8 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec * Intercept the invoke to newUpdater. If the holder class and field name are constant register * them for reflection/unsafe access. */ - private static void interceptUpdaterInvoke(MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection, ParsingReason reason, ValueNode tclassNode, ValueNode fieldNameNode) { + private static void interceptUpdaterInvoke(GraphBuilderContext b, MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection, ParsingReason reason, ValueNode tclassNode, + ValueNode fieldNameNode) { if (SubstrateOptions.parseOnce() || reason == ParsingReason.PointsToAnalysis) { if (tclassNode.isConstant() && fieldNameNode.isConstant()) { Class tclass = snippetReflection.asObject(Class.class, tclassNode.asJavaConstant()); @@ -529,7 +531,7 @@ private static void interceptUpdaterInvoke(MetaAccessProvider metaAccess, Snippe RuntimeReflection.register(field); // register the field for unsafe access - registerAsUnsafeAccessed(metaAccess, field); + registerAsUnsafeAccessed(b, metaAccess, field); } catch (NoSuchFieldException e) { /* * Ignore the exception. : If the field does not exist, there will be an error @@ -543,10 +545,11 @@ private static void interceptUpdaterInvoke(MetaAccessProvider metaAccess, Snippe } } - private static void registerAsUnsafeAccessed(MetaAccessProvider metaAccess, Field field) { + private static void registerAsUnsafeAccessed(GraphBuilderContext b, MetaAccessProvider metaAccess, Field field) { AnalysisField targetField = (AnalysisField) metaAccess.lookupJavaField(field); - targetField.registerAsAccessed(); - targetField.registerAsUnsafeAccessed(); + Object reason = nonNullReason(b.getGraph().currentNodeSourcePosition()); + targetField.registerAsAccessed(reason); + targetField.registerAsUnsafeAccessed(reason); } private static void registerObjectPlugins(InvocationPlugins plugins) { @@ -676,7 +679,7 @@ private static boolean processFieldOffset(GraphBuilderContext b, Field targetFie if (SubstrateOptions.parseOnce() || reason == ParsingReason.PointsToAnalysis) { /* Register the field for unsafe access. */ - registerAsUnsafeAccessed(metaAccess, targetField); + registerAsUnsafeAccessed(b, metaAccess, targetField); } else { HostedMetaAccess hostedMetaAccess = (HostedMetaAccess) metaAccess; @@ -1114,6 +1117,10 @@ protected ResolvedJavaType getTypeAESCrypt(MetaAccessProvider metaAccess, Resolv } } + private static Object nonNullReason(NodeSourcePosition position) { + return position == null ? "Unknown graph builder location." : position; + } + private static void registerAESPlugins(InvocationPlugins plugins, Replacements replacements, Architecture arch) { Registration r = new Registration(plugins, "com.sun.crypto.provider.CounterMode", replacements); r.registerConditional(CounterModeAESNode.isSupported(arch), new CounterModeCryptPlugin() { @@ -1125,7 +1132,7 @@ protected boolean canApply(GraphBuilderContext b) { @Override protected ValueNode getFieldOffset(GraphBuilderContext b, ResolvedJavaField field) { if (field instanceof AnalysisField) { - ((AnalysisField) field).registerAsUnsafeAccessed(); + ((AnalysisField) field).registerAsUnsafeAccessed(nonNullReason(b.getGraph().currentNodeSourcePosition())); } return LazyConstantNode.create(StampFactory.forKind(JavaKind.Long), new FieldOffsetConstantProvider(((OriginalFieldProvider) field).getJavaField()), b); } 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 8e1a410f4ddc..d135604c3281 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 @@ -320,9 +320,9 @@ public void processComputedValueFields(BigBang bb) { switch (cvField.getRecomputeValueKind()) { case FieldOffset: AnalysisField targetField = bb.getMetaAccess().lookupJavaField(cvField.getTargetField()); - targetField.registerAsAccessed(); + targetField.registerAsAccessed(cvField); assert !AnnotationAccess.isAnnotationPresent(targetField, Delete.class); - targetField.registerAsUnsafeAccessed(); + targetField.registerAsUnsafeAccessed(cvField); break; } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/ComputedValueField.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/ComputedValueField.java index e13b27f4023f..3de264d87507 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/ComputedValueField.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/ComputedValueField.java @@ -233,7 +233,7 @@ public void processAnalysis(AnalysisMetaAccess aMetaAccess) { switch (kind) { case FieldOffset: AnalysisField target = aMetaAccess.lookupJavaField(targetField); - target.registerAsAccessed(); + target.registerAsAccessed(this); break; } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/UnsafeAutomaticSubstitutionProcessor.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/UnsafeAutomaticSubstitutionProcessor.java index 2735de530b65..1e4317f0f664 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/UnsafeAutomaticSubstitutionProcessor.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/UnsafeAutomaticSubstitutionProcessor.java @@ -298,7 +298,7 @@ void processComputedValueFields(DuringAnalysisAccessImpl access) { switch (cvField.getRecomputeValueKind()) { case FieldOffset: Field targetField = cvField.getTargetField(); - if (access.registerAsUnsafeAccessed(access.getMetaAccess().lookupJavaField(targetField))) { + if (access.registerAsUnsafeAccessed(access.getMetaAccess().lookupJavaField(targetField), cvField)) { access.requireAnalysisIteration(); } break; diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleFeature.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleFeature.java index 0ac6fd956aa0..ff62e3ce5df3 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleFeature.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleFeature.java @@ -504,7 +504,7 @@ private static void registerKnownTruffleFields(BeforeAnalysisAccessImpl config, try { Object value = field.get(knownTruffleFields); if (value instanceof ResolvedJavaField) { - config.registerAsAccessed((AnalysisField) value); + config.registerAsAccessed((AnalysisField) value, "known truffle field"); } } catch (IllegalAccessException ex) { throw VMError.shouldNotReachHere(ex);