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 e48d66606b73..fb985be004ea 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 @@ -49,7 +49,7 @@ public class StandalonePointsToAnalysis extends PointsToAnalysis { public StandalonePointsToAnalysis(OptionValues options, AnalysisUniverse universe, HostVM hostVM, AnalysisMetaAccess metaAccess, SnippetReflectionProvider snippetReflectionProvider, ConstantReflectionProvider constantReflectionProvider, WordTypes wordTypes, DebugContext debugContext, TimerCollection timerCollection) { - super(options, universe, hostVM, metaAccess, snippetReflectionProvider, constantReflectionProvider, wordTypes, new UnsupportedFeatures(), debugContext, timerCollection, true); + super(options, universe, hostVM, metaAccess, snippetReflectionProvider, constantReflectionProvider, wordTypes, new UnsupportedFeatures(), debugContext, timerCollection); } @Override diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AbstractAnalysisEngine.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AbstractAnalysisEngine.java index be32d2919e5a..33e680264228 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 @@ -29,18 +29,6 @@ import java.util.List; import java.util.function.Function; -import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; -import jdk.graal.compiler.debug.DebugContext; -import jdk.graal.compiler.debug.DebugContext.Builder; -import jdk.graal.compiler.debug.DebugHandlersFactory; -import jdk.graal.compiler.debug.Indent; -import jdk.graal.compiler.graph.Node; -import jdk.graal.compiler.nodes.DeoptBciSupplier; -import jdk.graal.compiler.nodes.StateSplit; -import jdk.graal.compiler.nodes.ValueNode; -import jdk.graal.compiler.options.OptionValues; -import jdk.graal.compiler.printer.GraalDebugHandlersFactory; -import jdk.graal.compiler.word.WordTypes; import org.graalvm.nativeimage.hosted.Feature; import com.oracle.graal.pointsto.api.HostVM; @@ -59,6 +47,18 @@ import com.oracle.graal.pointsto.util.TimerCollection; import com.oracle.svm.common.meta.MultiMethod; +import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; +import jdk.graal.compiler.debug.DebugContext; +import jdk.graal.compiler.debug.DebugContext.Builder; +import jdk.graal.compiler.debug.DebugHandlersFactory; +import jdk.graal.compiler.debug.Indent; +import jdk.graal.compiler.graph.Node; +import jdk.graal.compiler.nodes.DeoptBciSupplier; +import jdk.graal.compiler.nodes.StateSplit; +import jdk.graal.compiler.nodes.ValueNode; +import jdk.graal.compiler.options.OptionValues; +import jdk.graal.compiler.printer.GraalDebugHandlersFactory; +import jdk.graal.compiler.word.WordTypes; import jdk.vm.ci.code.BytecodeFrame; import jdk.vm.ci.code.BytecodePosition; import jdk.vm.ci.meta.ConstantReflectionProvider; diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/BigBang.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/BigBang.java index c89363f7f860..2dfb06b1aa65 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/BigBang.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/BigBang.java @@ -28,12 +28,6 @@ import java.util.List; import java.util.function.Function; -import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; -import jdk.graal.compiler.debug.DebugContext; -import jdk.graal.compiler.debug.DebugHandlersFactory; -import jdk.graal.compiler.options.OptionValues; -import jdk.graal.compiler.word.WordTypes; - import com.oracle.graal.pointsto.api.HostVM; import com.oracle.graal.pointsto.constraints.UnsupportedFeatures; import com.oracle.graal.pointsto.meta.AnalysisField; @@ -45,6 +39,11 @@ import com.oracle.graal.pointsto.util.CompletionExecutor; import com.oracle.svm.common.meta.MultiMethod; +import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; +import jdk.graal.compiler.debug.DebugContext; +import jdk.graal.compiler.debug.DebugHandlersFactory; +import jdk.graal.compiler.options.OptionValues; +import jdk.graal.compiler.word.WordTypes; import jdk.vm.ci.code.BytecodePosition; import jdk.vm.ci.meta.ConstantReflectionProvider; @@ -95,8 +94,6 @@ default HostedProviders getProviders(AnalysisMethod method) { void runAnalysis(DebugContext debug, Function duringAnalysisAction) throws InterruptedException; - boolean strengthenGraalGraphs(); - /** You can blacklist certain callees here. */ @SuppressWarnings("unused") default boolean isCallAllowed(PointsToAnalysis bb, AnalysisMethod caller, AnalysisMethod target, BytecodePosition srcPosition) { 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 cda851aa7c95..3a7f70efd98a 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 @@ -102,17 +102,12 @@ public abstract class PointsToAnalysis extends AbstractAnalysisEngine { public final Timer typeFlowTimer; - private final boolean strengthenGraalGraphs; - @SuppressWarnings("this-escape") public PointsToAnalysis(OptionValues options, AnalysisUniverse universe, HostVM hostVM, AnalysisMetaAccess metaAccess, SnippetReflectionProvider snippetReflectionProvider, - ConstantReflectionProvider constantReflectionProvider, WordTypes wordTypes, UnsupportedFeatures unsupportedFeatures, DebugContext debugContext, TimerCollection timerCollection, - boolean strengthenGraalGraphs) { + ConstantReflectionProvider constantReflectionProvider, WordTypes wordTypes, UnsupportedFeatures unsupportedFeatures, DebugContext debugContext, TimerCollection timerCollection) { super(options, universe, hostVM, metaAccess, snippetReflectionProvider, constantReflectionProvider, wordTypes, unsupportedFeatures, debugContext, timerCollection); this.typeFlowTimer = timerCollection.createTimer("(typeflow)"); - this.strengthenGraalGraphs = strengthenGraalGraphs; - this.objectType = metaAccess.lookupJavaType(Object.class); /* * Make sure the all-instantiated type flow is created early. We do not have any @@ -149,11 +144,6 @@ public void printTimerStatistics(PrintWriter out) { StatisticsPrinter.printLast(out, "total_memory_bytes", analysisTimer.getTotalMemory()); } - @Override - public boolean strengthenGraalGraphs() { - return strengthenGraalGraphs; - } - public boolean trackTypeFlowInputs() { return trackTypeFlowInputs; } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/InstanceOfTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/InstanceOfTypeFlow.java deleted file mode 100644 index 0e0550c1ba76..000000000000 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/InstanceOfTypeFlow.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.pointsto.flow; - -import com.oracle.graal.pointsto.PointsToAnalysis; -import com.oracle.graal.pointsto.meta.AnalysisType; -import com.oracle.graal.pointsto.typestate.TypeState; - -import jdk.vm.ci.code.BytecodePosition; - -/** - * Reflects all types flow into an instanceof node, i.e., the state of this flow contains all types - * that flow into it, with no filtering. There is a separate {@link FilterTypeFlow} that implements - * the filtering operation and propagates the reduced state to uses. An InstanceOfTypeFlow is a sink - * flow, i.e., it doesn't have any uses. - */ -public class InstanceOfTypeFlow extends TypeFlow { - - public InstanceOfTypeFlow(BytecodePosition position, AnalysisType declaredType) { - super(position, declaredType); - } - - public InstanceOfTypeFlow(InstanceOfTypeFlow original, MethodFlowsGraph methodFlows) { - super(original, methodFlows); - } - - @Override - public TypeState filter(PointsToAnalysis bb, TypeState newState) { - /* - * Since the InstanceOfTypeFlow needs to reflect all types flowing into an instanceof node - * it doesn't implement any filtering. The filtering is done by the associated - * FilterTypeFlow. - */ - return newState; - } - - @Override - public TypeFlow copy(PointsToAnalysis bb, MethodFlowsGraph methodFlows) { - return new InstanceOfTypeFlow(this, methodFlows); - } - - @Override - public String toString() { - return "InstanceOfTypeFlow<" + getState() + ">"; - } -} diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodFlowsGraph.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodFlowsGraph.java index a94c33ce89e3..3fbbf47bc076 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodFlowsGraph.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodFlowsGraph.java @@ -27,8 +27,6 @@ import java.lang.reflect.Modifier; import java.util.ArrayDeque; import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; import java.util.Deque; import java.util.HashSet; import java.util.Iterator; @@ -36,16 +34,14 @@ import java.util.Set; import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.EconomicSet; -import jdk.graal.compiler.graph.Node; -import jdk.graal.compiler.nodes.EncodedGraph.EncodedNodeReference; import com.oracle.graal.pointsto.PointsToAnalysis; import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.PointsToAnalysisMethod; import com.oracle.graal.pointsto.util.AnalysisError; -import jdk.vm.ci.code.BytecodePosition; +import jdk.graal.compiler.graph.Node; +import jdk.graal.compiler.nodes.EncodedGraph.EncodedNodeReference; public class MethodFlowsGraph implements MethodFlowsGraphInfo { /** @@ -76,14 +72,7 @@ public enum GraphKind { protected FormalParamTypeFlow[] parameters; protected List> miscEntryFlows; protected EconomicMap> nodeFlows; - /* - * We keep a bci->flow mapping for instanceof and invoke flows since they are queried by the - * analysis results builder. - */ - protected EconomicSet nonUniqueBcis; - protected EconomicMap instanceOfFlows; - protected EconomicMap invokeFlows; - + protected List invokeFlows; protected FormalReturnTypeFlow returnFlow; protected volatile boolean isLinearized; @@ -214,13 +203,8 @@ private Iterator> flowsIterator() { } } } - if (instanceOfFlows != null) { - for (var value : instanceOfFlows.getValues()) { - worklist.add(value); - } - } if (invokeFlows != null) { - for (var value : invokeFlows.getValues()) { + for (var value : invokeFlows) { worklist.add(value); } } @@ -302,24 +286,12 @@ public TypeFlow[] getParameters() { return parameters; } - public void addNodeFlow(PointsToAnalysis bb, Node node, TypeFlow input) { - if (bb.strengthenGraalGraphs()) { - addNodeFlow(new EncodedNodeReference(node), input); - } else { - addMiscEntryFlow(input); - } - } - - public void addNodeFlow(EncodedNodeReference key, TypeFlow flow) { + public void addNodeFlow(Node node, TypeFlow flow) { assert flow != null && !(flow instanceof AllInstantiatedTypeFlow) : flow; if (nodeFlows == null) { nodeFlows = EconomicMap.create(); } - nodeFlows.put(key, flow); - } - - public Collection> getMiscFlows() { - return miscEntryFlows == null ? Collections.emptyList() : miscEntryFlows; + nodeFlows.put(new EncodedNodeReference(node), flow); } public EconomicMap> getNodeFlows() { @@ -342,58 +314,15 @@ public FormalReturnTypeFlow getReturnFlow() { return this.returnFlow; } - public EconomicMap getInvokes() { - return invokeFlows == null ? EconomicMap.emptyMap() : invokeFlows; + public List getInvokes() { + return invokeFlows == null ? List.of() : invokeFlows; } - public EconomicMap getInstanceOfFlows() { - return instanceOfFlows == null ? EconomicMap.emptyMap() : instanceOfFlows; - } - - void addInstanceOf(Object key, InstanceOfTypeFlow instanceOf) { - if (instanceOfFlows == null) { - instanceOfFlows = EconomicMap.create(); - } - doAddFlow(key, instanceOf, instanceOfFlows); - } - - void addInvoke(Object key, InvokeTypeFlow invokeTypeFlow) { + void addInvoke(InvokeTypeFlow invokeTypeFlow) { if (invokeFlows == null) { - invokeFlows = EconomicMap.create(); - } - doAddFlow(key, invokeTypeFlow, invokeFlows); - } - - private > void doAddFlow(Object key, T flow, EconomicMap map) { - assert map == instanceOfFlows || map == invokeFlows : "Keys of these maps must not be overlapping"; - Object uniqueKey = key; - if ((nonUniqueBcis != null && nonUniqueBcis.contains(key)) || removeNonUnique(key, instanceOfFlows) || removeNonUnique(key, invokeFlows)) { - uniqueKey = new Object(); - } - map.put(uniqueKey, flow); - } - - private > boolean removeNonUnique(Object key, EconomicMap map) { - if (map == null) { - return false; - } - T oldFlow = map.removeKey(key); - if (oldFlow != null) { - /* - * This can happen when Graal inlines jsr/ret routines and the inlined nodes share the - * same bci. Or for some invokes where the bytecode parser needs to insert a type check - * before the invoke. Remove the old bci->flow pairing and replace it with a - * uniqueKey->flow pairing. - */ - map.put(new Object(), oldFlow); - if (nonUniqueBcis == null) { - nonUniqueBcis = EconomicSet.create(); - } - nonUniqueBcis.add(key); - return true; - } else { - return false; + invokeFlows = new ArrayList<>(); } + invokeFlows.add(invokeTypeFlow); } public boolean isLinearized() { @@ -415,7 +344,7 @@ public List allNonStubCallers(PointsToAnalysis bb) { List callers = new ArrayList<>(); for (AnalysisMethod caller : method.getCallers()) { for (MethodFlowsGraph callerFlowGraph : PointsToAnalysis.assertPointsToAnalysisMethod(caller).getTypeFlow().getFlows()) { - for (InvokeTypeFlow callerInvoke : callerFlowGraph.getInvokes().getValues()) { + for (InvokeTypeFlow callerInvoke : callerFlowGraph.getInvokes()) { InvokeTypeFlow invoke = callerInvoke; if (InvokeTypeFlow.isContextInsensitiveVirtualInvoke(callerInvoke)) { /* The invoke has been replaced by the context insensitive one. */ @@ -445,7 +374,7 @@ public List allNonStubCallers(PointsToAnalysis bb) { * @return the InvokeTypeFlow object belonging to the caller that linked to this callee. */ public InvokeTypeFlow invokeFlow(MethodFlowsGraph callerFlowGraph, PointsToAnalysis bb) { - for (InvokeTypeFlow callerInvoke : callerFlowGraph.getInvokes().getValues()) { + for (InvokeTypeFlow callerInvoke : callerFlowGraph.getInvokes()) { for (MethodFlowsGraph calleeFlowGraph : callerInvoke.getAllNonStubCalleesFlows(bb)) { // 'this' method graph was found among the callees of an invoke flow in the caller // method clone, hence we register return it @@ -495,8 +424,6 @@ final void removeInternalFlows(PointsToAnalysis bb) { miscEntryFlows = null; nodeFlows = null; - nonUniqueBcis = null; - instanceOfFlows = null; invokeFlows = null; } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodFlowsGraphClone.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodFlowsGraphClone.java index b2785f3257a8..a1cdc3db97e9 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodFlowsGraphClone.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodFlowsGraphClone.java @@ -89,7 +89,6 @@ private void cloneOriginalFlowsHelper(PointsToAnalysis bb, boolean isReclone) { } nodeFlows = lookupClonesOf(bb, originalFlowsGraph.nodeFlows); - instanceOfFlows = lookupClonesOf(bb, originalFlowsGraph.instanceOfFlows); miscEntryFlows = lookupClonesOf(bb, originalFlowsGraph.miscEntryFlows); invokeFlows = lookupClonesOf(bb, originalFlowsGraph.invokeFlows); diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlow.java index b00c56d1dca9..99e18d8c206b 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlow.java @@ -30,8 +30,6 @@ import java.util.Collections; import java.util.List; -import org.graalvm.collections.EconomicMap; - import com.oracle.graal.pointsto.PointsToAnalysis; import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException; import com.oracle.graal.pointsto.flow.builder.TypeFlowGraphBuilder; @@ -228,9 +226,9 @@ public Collection getFlows() { return flowsGraph == null ? Collections.emptyList() : List.of(flowsGraph); } - public EconomicMap getInvokes() { + public List getInvokes() { ensureFlowsGraphSealed(); - return flowsGraph == null ? EconomicMap.emptyMap() : flowsGraph.getInvokes(); + return flowsGraph == null ? List.of() : flowsGraph.getInvokes(); } public TypeFlow getParameter(int idx) { 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 609b4de64ea3..50f129be8ca6 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 @@ -24,7 +24,6 @@ */ package com.oracle.graal.pointsto.flow; -import static jdk.vm.ci.common.JVMCIError.guarantee; import static jdk.vm.ci.common.JVMCIError.shouldNotReachHere; import java.lang.reflect.Modifier; @@ -61,7 +60,6 @@ import com.oracle.graal.pointsto.nodes.UnsafePartitionLoadNode; import com.oracle.graal.pointsto.nodes.UnsafePartitionStoreNode; import com.oracle.graal.pointsto.phases.InlineBeforeAnalysis; -import com.oracle.graal.pointsto.results.StaticAnalysisResultsBuilder; import com.oracle.graal.pointsto.results.StrengthenGraphs; import com.oracle.graal.pointsto.typestate.TypeState; import com.oracle.graal.pointsto.util.AnalysisError; @@ -196,36 +194,26 @@ private boolean parse(Object reason, boolean forceReparse) { graph = InlineBeforeAnalysis.decodeGraph(bb, method, analysisParsedGraph); try (DebugContext.Scope s = graph.getDebug().scope("MethodTypeFlowBuilder", graph)) { - if (!bb.strengthenGraalGraphs()) { - /* - * Register used types and fields before canonicalization can optimize them. When - * parsing graphs again for compilation, we need to have all types, methods, fields - * of the original graph registered properly. - */ - registerUsedElements(bb, graph, false); - } CanonicalizerPhase canonicalizerPhase = CanonicalizerPhase.create(); canonicalizerPhase.apply(graph, bb.getProviders(method)); - if (bb.strengthenGraalGraphs()) { + if (PointstoOptions.ConditionalEliminationBeforeAnalysis.getValue(bb.getOptions())) { /* * Removing unnecessary conditions before the static analysis runs reduces the size * of the type flow graph. For example, this removes redundant null checks: the * bytecode parser emits explicit null checks before e.g., all method calls, field * access, array accesses; many of those dominate each other. */ - if (PointstoOptions.ConditionalEliminationBeforeAnalysis.getValue(bb.getOptions())) { - new IterativeConditionalEliminationPhase(canonicalizerPhase, false).apply(graph, bb.getProviders(method)); - } - if (PointstoOptions.EscapeAnalysisBeforeAnalysis.getValue(bb.getOptions())) { - if (method.isOriginalMethod()) { - /* - * Deoptimization Targets cannot have virtual objects in frame states. - * - * Also, more work is needed to enable PEA in Runtime Compiled Methods. - */ - new BoxNodeIdentityPhase().apply(graph, bb.getProviders(method)); - new PartialEscapePhase(false, canonicalizerPhase, bb.getOptions()).apply(graph, bb.getProviders(method)); - } + new IterativeConditionalEliminationPhase(canonicalizerPhase, false).apply(graph, bb.getProviders(method)); + } + if (PointstoOptions.EscapeAnalysisBeforeAnalysis.getValue(bb.getOptions())) { + if (method.isOriginalMethod()) { + /* + * Deoptimization Targets cannot have virtual objects in frame states. + * + * Also, more work is needed to enable PEA in Runtime Compiled Methods. + */ + new BoxNodeIdentityPhase().apply(graph, bb.getProviders(method)); + new PartialEscapePhase(false, canonicalizerPhase, bb.getOptions()).apply(graph, bb.getProviders(method)); } } @@ -392,7 +380,7 @@ protected static boolean ignoreInstanceOfType(PointsToAnalysis bb, AnalysisType if (bb.getHostVM().ignoreInstanceOfTypeDisallowed()) { return false; } - if (type == null || !bb.strengthenGraalGraphs()) { + if (type == null) { return false; } if (type.isArray()) { @@ -517,9 +505,7 @@ private void createTypeFlow() { }); typeFlowGraphBuilder.checkFormalParameterBuilder(paramBuilder); typeFlows.add(node, paramBuilder); - if (bb.strengthenGraalGraphs()) { - typeFlowGraphBuilder.registerSinkBuilder(paramBuilder); - } + typeFlowGraphBuilder.registerSinkBuilder(paramBuilder); } } else if (n instanceof BoxNode) { BoxNode node = (BoxNode) n; @@ -628,16 +614,7 @@ protected void apply(boolean forceReparse, Object reason) { insertPlaceholderParamAndReturnFlows(); } - /* - * When we intend to strengthen Graal graphs, then the graph needs to be preserved. Type - * flow nodes references Graal IR nodes directly as their source position. - * - * When we create separate StaticAnalysisResults objects, then Graal graphs are not needed - * after static analysis. - */ - if (bb.strengthenGraalGraphs()) { - method.setAnalyzedGraph(GraphEncoder.encodeSingleGraph(graph, AnalysisParsedGraph.HOST_ARCHITECTURE, flowsGraph.getNodeFlows().getKeys())); - } + method.setAnalyzedGraph(GraphEncoder.encodeSingleGraph(graph, AnalysisParsedGraph.HOST_ARCHITECTURE, flowsGraph.getNodeFlows().getKeys())); } /** @@ -761,12 +738,10 @@ public TypeFlowsOfNodes clone() { */ class NodeIterator extends PostOrderNodeIterator { - private final HashMap> instanceOfFlows; private TypeFlowBuilder returnBuilder; NodeIterator(FixedNode start, TypeFlowsOfNodes typeFlows) { super(start, typeFlows); - instanceOfFlows = new HashMap<>(); returnBuilder = null; } @@ -801,24 +776,6 @@ private TypeFlowBuilder uniqueReturnFlowBuilder(ReturnNode node) { return returnBuilder; } - private TypeFlowBuilder uniqueInstanceOfFlow(InstanceOfNode node, AnalysisType declaredType) { - /* - * This happens during method parsing, which is single threaded, so there is no need for - * synchronization. - */ - Object key = StaticAnalysisResultsBuilder.uniqueKey(node); - return instanceOfFlows.computeIfAbsent(key, (bciKey) -> { - TypeFlowBuilder instanceOfBuilder = TypeFlowBuilder.create(bb, node, InstanceOfTypeFlow.class, () -> { - InstanceOfTypeFlow instanceOf = new InstanceOfTypeFlow(AbstractAnalysisEngine.sourcePosition(node), declaredType); - flowsGraph.addInstanceOf(key, instanceOf); - return instanceOf; - }); - /* InstanceOf must not be removed as it is reported by the analysis results. */ - typeFlowGraphBuilder.registerSinkBuilder(instanceOfBuilder); - return instanceOfBuilder; - }); - } - private void handleCondition(ValueNode source, LogicNode condition, boolean isTrue) { if (condition instanceof IsNullNode) { IsNullNode nullCheck = (IsNullNode) condition; @@ -826,13 +783,11 @@ private void handleCondition(ValueNode source, LogicNode condition, boolean isTr TypeFlowBuilder inputBuilder = state.lookup(object); TypeFlowBuilder nullCheckBuilder = TypeFlowBuilder.create(bb, source, NullCheckTypeFlow.class, () -> { NullCheckTypeFlow nullCheckFlow = new NullCheckTypeFlow(AbstractAnalysisEngine.sourcePosition(source), inputBuilder.get().getDeclaredType(), !isTrue); - flowsGraph.addNodeFlow(bb, source, nullCheckFlow); + flowsGraph.addNodeFlow(source, nullCheckFlow); return nullCheckFlow; }); nullCheckBuilder.addUseDependency(inputBuilder); - if (bb.strengthenGraalGraphs()) { - typeFlowGraphBuilder.registerSinkBuilder(nullCheckBuilder); - } + typeFlowGraphBuilder.registerSinkBuilder(nullCheckBuilder); state.update(object, nullCheckBuilder); } else if (condition instanceof InstanceOfNode) { @@ -840,45 +795,13 @@ private void handleCondition(ValueNode source, LogicNode condition, boolean isTr ValueNode object = instanceOf.getValue(); TypeReference typeReference = instanceOf.type(); AnalysisType type = (AnalysisType) instanceOf.type().getType(); - - /* - * It is possible that the instanceof is processed multiple times, because the same - * InstanceOfNode can be used by multiple conditions and is processed once for each - * branch of an if statement, so we have to make sure that its associated type flow - * is unique. - */ - TypeFlowBuilder objectBuilder = state.lookup(object); - BytecodePosition instanceOfPosition = AbstractAnalysisEngine.sourcePosition(instanceOf); - if (!bb.strengthenGraalGraphs() && instanceOfPosition.getBCI() >= 0) { - /* - * An InstanceOf with negative BCI is not useful. This can happen for example - * for instanceof bytecodes for exception unwind. However, the filtering below - * is still useful for other further operations in the exception handler. - * - * When strengthenGraalGraphs is true, then there is never a need for an - * InstanceOfTypeFlow. The information is taken from the FilterTypeFlow instead, - * i.e., when the filtered type flow of either the true or false successor is - * empty, then that branch is unreachable and the instanceOf will be removed. - */ - TypeFlowBuilder instanceOfBuilder = uniqueInstanceOfFlow(instanceOf, type); - instanceOfBuilder.addUseDependency(objectBuilder); - } - - /* - * Note that we create the filter flow with the original objectFlow as the input and - * not with the instanceOfFlow. When the same InstanceOfNode is used by multiple - * conditions, the type state of instanceOfFlow is less precise than the type state - * of objectFlow (which is context sensitive for exactly our condition). - */ TypeFlowBuilder filterBuilder = TypeFlowBuilder.create(bb, source, FilterTypeFlow.class, () -> { FilterTypeFlow filterFlow = new FilterTypeFlow(AbstractAnalysisEngine.sourcePosition(source), type, typeReference.isExact(), isTrue, !isTrue ^ instanceOf.allowsNull()); - flowsGraph.addNodeFlow(bb, source, filterFlow); + flowsGraph.addNodeFlow(source, filterFlow); return filterFlow; }); - filterBuilder.addUseDependency(objectBuilder); - if (bb.strengthenGraalGraphs()) { - typeFlowGraphBuilder.registerSinkBuilder(filterBuilder); - } + filterBuilder.addUseDependency(state.lookup(object)); + typeFlowGraphBuilder.registerSinkBuilder(filterBuilder); state.update(object, filterBuilder); } } @@ -1052,21 +975,19 @@ protected void node(FixedNode n) { loadFieldBuilder = TypeFlowBuilder.create(bb, node, LoadStaticFieldTypeFlow.class, () -> { FieldTypeFlow fieldFlow = field.getStaticFieldFlow(); LoadStaticFieldTypeFlow loadFieldFLow = new LoadStaticFieldTypeFlow(loadLocation, field, fieldFlow); - flowsGraph.addNodeFlow(bb, node, loadFieldFLow); + flowsGraph.addNodeFlow(node, loadFieldFLow); return loadFieldFLow; }); } else { TypeFlowBuilder objectBuilder = state.lookup(node.object()); loadFieldBuilder = TypeFlowBuilder.create(bb, node, LoadInstanceFieldTypeFlow.class, () -> { LoadInstanceFieldTypeFlow loadFieldFLow = new LoadInstanceFieldTypeFlow(loadLocation, field, objectBuilder.get()); - flowsGraph.addNodeFlow(bb, node, loadFieldFLow); + flowsGraph.addNodeFlow(node, loadFieldFLow); return loadFieldFLow; }); loadFieldBuilder.addObserverDependency(objectBuilder); } - if (bb.strengthenGraalGraphs()) { - typeFlowGraphBuilder.registerSinkBuilder(loadFieldBuilder); - } + typeFlowGraphBuilder.registerSinkBuilder(loadFieldBuilder); state.add(node, loadFieldBuilder); } if (node.object() != null) { @@ -1087,13 +1008,10 @@ protected void node(FixedNode n) { TypeFlowBuilder loadIndexedBuilder = TypeFlowBuilder.create(bb, node, LoadIndexedTypeFlow.class, () -> { LoadIndexedTypeFlow loadIndexedFlow = new LoadIndexedTypeFlow(AbstractAnalysisEngine.sourcePosition(node), arrayType, arrayBuilder.get()); - flowsGraph.addNodeFlow(bb, node, loadIndexedFlow); + flowsGraph.addNodeFlow(node, loadIndexedFlow); return loadIndexedFlow; }); - - if (bb.strengthenGraalGraphs()) { - typeFlowGraphBuilder.registerSinkBuilder(loadIndexedBuilder); - } + typeFlowGraphBuilder.registerSinkBuilder(loadIndexedBuilder); loadIndexedBuilder.addObserverDependency(arrayBuilder); state.add(node, loadIndexedBuilder); } @@ -1317,10 +1235,6 @@ protected void node(FixedNode n) { } else if (n instanceof InvokeNode || n instanceof InvokeWithExceptionNode) { Invoke invoke = (Invoke) n; if (invoke.callTarget() instanceof MethodCallTargetNode target) { - guarantee(bb.strengthenGraalGraphs() || invoke.stateAfter().outerFrameState() == null, - "Outer FrameState of %s must be null, but was %s. A non-null outer FrameState indicates that a method inlining has happened, but inlining should only happen after analysis.", - invoke.stateAfter(), invoke.stateAfter().outerFrameState()); - var arguments = target.arguments(); processMethodInvocation(state, invoke, target.invokeKind(), (PointsToAnalysisMethod) target.targetMethod(), arguments); @@ -1588,10 +1502,8 @@ protected void processMethodInvocation(TypeFlowsOfNodes state, ValueNode invoke, } } - flowsGraph.addInvoke(StaticAnalysisResultsBuilder.uniqueKey(invoke), invokeFlow); - if (bb.strengthenGraalGraphs()) { - flowsGraph.addNodeFlow(bb, invoke, invokeFlow); - } + flowsGraph.addInvoke(invokeFlow); + flowsGraph.addNodeFlow(invoke, invokeFlow); /* * Directly add the invoke as an observer of the receiver flow. There's no need to use @@ -1642,9 +1554,7 @@ protected void processMethodInvocation(TypeFlowsOfNodes state, ValueNode invoke, actualReturnBuilder = filterBuilder; } - if (bb.strengthenGraalGraphs()) { - typeFlowGraphBuilder.registerSinkBuilder(actualReturnBuilder); - } + typeFlowGraphBuilder.registerSinkBuilder(actualReturnBuilder); if (installResult) { /* * Some MacroInvokable nodes may have an optimized result, but we still need process diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/TypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/TypeFlow.java index a9bea2414183..e7cf0ce16796 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/TypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/TypeFlow.java @@ -28,21 +28,19 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; -import jdk.graal.compiler.graph.Node; - import com.oracle.graal.pointsto.PointsToAnalysis; import com.oracle.graal.pointsto.api.PointstoOptions; import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.meta.PointsToAnalysisMethod; -import com.oracle.graal.pointsto.results.StaticAnalysisResultsBuilder; +import com.oracle.graal.pointsto.results.StrengthenGraphs; import com.oracle.graal.pointsto.typestate.PointsToStats; import com.oracle.graal.pointsto.typestate.TypeState; -import com.oracle.graal.pointsto.typestate.TypeStateUtils; import com.oracle.graal.pointsto.util.AnalysisError; import com.oracle.graal.pointsto.util.ConcurrentLightHashSet; import com.oracle.svm.util.ClassUtil; +import jdk.graal.compiler.graph.Node; import jdk.vm.ci.code.BytecodePosition; @SuppressWarnings("rawtypes") @@ -96,9 +94,8 @@ public abstract class TypeFlow { * individual type flows to subscribe themselves directly to the type flows of their declared * types if they need further updates. *

- * When static analysis results are built in - * {@link StaticAnalysisResultsBuilder#makeOrApplyResults} the type state is considered only if - * the type flow was not marked as saturated. + * When static analysis results are built in {@link StrengthenGraphs#applyResults} the type + * state is considered only if the type flow was not marked as saturated. *

* The initial value is false, i.e., the flow is initially not saturated. */ @@ -252,12 +249,6 @@ public boolean isAllInstantiated() { return this instanceof AllInstantiatedTypeFlow; } - public void setState(PointsToAnalysis bb, TypeState state) { - assert !bb.extendedAsserts() || this instanceof InstanceOfTypeFlow || - state.verifyDeclaredType(bb, declaredType) : "declaredType: " + declaredType.toJavaName(true) + " state: " + state; - this.state = state; - } - public void setSlot(int slot) { this.slot = slot; } @@ -326,8 +317,6 @@ public boolean addState(PointsToAnalysis bb, TypeState add, boolean postFlow) { PointsToStats.registerTypeFlowSuccessfulUpdate(bb, this, add); - assert checkTypeState(bb, before, after); - if (checkSaturated(bb, after)) { onSaturated(bb); } else if (postFlow) { @@ -336,42 +325,6 @@ public boolean addState(PointsToAnalysis bb, TypeState add, boolean postFlow) { return true; } - - private boolean checkTypeState(PointsToAnalysis bb, TypeState before, TypeState after) { - if (!bb.extendedAsserts()) { - return true; - } - - if (bb.analysisPolicy().relaxTypeFlowConstraints()) { - return true; - } - - if (this instanceof InstanceOfTypeFlow || this instanceof FilterTypeFlow) { - /* - * The type state of an InstanceOfTypeFlow doesn't contain only types assignable from - * its declared type. The InstanceOfTypeFlow keeps track of all the types discovered - * during analysis and there is always a corresponding filter type flow that implements - * the filter operation based on the declared type. - * - * Similarly, since a FilterTypeFlow implements complex logic, i.e., the filter can be - * either inclusive or exclusive and it can filter exact types or complete type - * hierarchies, the types in its type state are not necessary assignable from its - * declared type. - */ - return true; - } - assert after.verifyDeclaredType(bb, declaredType) : String.format("The type state of %s contains types that are not assignable from its declared type %s. " + - "%nState before: %s. %nState after: %s", format(false, true), declaredType.toJavaName(true), formatState(bb, before), formatState(bb, after)); - return true; - } - - private static String formatState(PointsToAnalysis bb, TypeState typeState) { - if (TypeStateUtils.closeToAllInstantiated(bb, typeState)) { - return "close to AllInstantiated"; - } - return typeState.toString(); - } - // manage uses public boolean addUse(PointsToAnalysis bb, TypeFlow use) { 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 a9268a680894..659a2889035f 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 @@ -44,15 +44,6 @@ import java.util.function.Consumer; import java.util.stream.Collectors; -import jdk.graal.compiler.debug.DebugContext; -import jdk.graal.compiler.graph.NodeSourcePosition; -import jdk.graal.compiler.java.BytecodeParser.BytecodeParserError; -import jdk.graal.compiler.java.StableMethodNameFormatter; -import jdk.graal.compiler.nodes.EncodedGraph; -import jdk.graal.compiler.nodes.EncodedGraph.EncodedNodeReference; -import jdk.graal.compiler.nodes.GraphDecoder; -import jdk.graal.compiler.nodes.StructuredGraph; -import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugin; import org.graalvm.nativeimage.hosted.Feature.DuringAnalysisAccess; import com.oracle.graal.pointsto.BigBang; @@ -64,12 +55,20 @@ import com.oracle.graal.pointsto.infrastructure.WrappedJavaMethod; import com.oracle.graal.pointsto.infrastructure.WrappedSignature; import com.oracle.graal.pointsto.reports.ReportUtils; -import com.oracle.graal.pointsto.results.StaticAnalysisResults; import com.oracle.graal.pointsto.util.AnalysisError; import com.oracle.graal.pointsto.util.AtomicUtils; import com.oracle.graal.pointsto.util.ConcurrentLightHashSet; import com.oracle.svm.common.meta.MultiMethod; +import jdk.graal.compiler.debug.DebugContext; +import jdk.graal.compiler.graph.NodeSourcePosition; +import jdk.graal.compiler.java.BytecodeParser.BytecodeParserError; +import jdk.graal.compiler.java.StableMethodNameFormatter; +import jdk.graal.compiler.nodes.EncodedGraph; +import jdk.graal.compiler.nodes.EncodedGraph.EncodedNodeReference; +import jdk.graal.compiler.nodes.GraphDecoder; +import jdk.graal.compiler.nodes.StructuredGraph; +import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugin; import jdk.vm.ci.code.BytecodePosition; import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.ConstantPool; @@ -734,11 +733,7 @@ public StackTraceElement asStackTraceElement(int bci) { @Override public ProfilingInfo getProfilingInfo(boolean includeNormal, boolean includeOSR) { - /* - * This is also the profiling information used when parsing methods for static analysis, so - * it needs to be conservative. - */ - return StaticAnalysisResults.NO_RESULTS; + return null; } @Override diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/PointsToAnalysisMethod.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/PointsToAnalysisMethod.java index 4000c3253af7..ec94979ef130 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/PointsToAnalysisMethod.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/PointsToAnalysisMethod.java @@ -146,7 +146,7 @@ public List getInvokeLocations() { @Override public Iterable getInvokes() { - return getTypeFlow().getInvokes().getValues(); + return getTypeFlow().getInvokes(); } /** diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysis.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysis.java index 16c3a4676d6d..4e186c2155e9 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysis.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysis.java @@ -30,7 +30,6 @@ import com.oracle.svm.util.ClassUtil; import jdk.graal.compiler.debug.DebugContext; -import jdk.graal.compiler.nodes.GraphDecoder; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.options.Option; import jdk.graal.compiler.options.OptionKey; @@ -70,20 +69,8 @@ public static StructuredGraph decodeGraph(BigBang bb, AnalysisMethod method, Ana .build(); try (DebugContext.Scope s = debug.scope("InlineBeforeAnalysis", result)) { - - if (bb.strengthenGraalGraphs()) { - InlineBeforeAnalysisGraphDecoder decoder = bb.getHostVM().createInlineBeforeAnalysisGraphDecoder(bb, method, result); - decoder.decode(method); - } else { - /* - * No inlining, so faithfully reconstruct the encoded graph without any - * optimizations. We could skip the encoding in this case, but since inlining before - * analysis is planned to be the default it is not worth optimizing for this case. - */ - GraphDecoder decoder = new GraphDecoder(AnalysisParsedGraph.HOST_ARCHITECTURE, result); - decoder.decode(analysisParsedGraph.getEncodedGraph()); - } - + InlineBeforeAnalysisGraphDecoder decoder = bb.getHostVM().createInlineBeforeAnalysisGraphDecoder(bb, method, result); + decoder.decode(method); debug.dump(DebugContext.BASIC_LEVEL, result, "InlineBeforeAnalysis after decode"); return result; } catch (Throwable ex) { diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/StatisticsPrinter.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/StatisticsPrinter.java index fec93403cdc0..fb20b23148f4 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/StatisticsPrinter.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/StatisticsPrinter.java @@ -31,14 +31,11 @@ import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.PointsToAnalysis; -import com.oracle.graal.pointsto.flow.InstanceOfTypeFlow; import com.oracle.graal.pointsto.flow.MethodFlowsGraph; import com.oracle.graal.pointsto.flow.MethodTypeFlow; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.AnalysisType; -import com.oracle.graal.pointsto.results.StaticAnalysisResultsBuilder; -import com.oracle.graal.pointsto.typestate.TypeState; public final class StatisticsPrinter { @@ -189,26 +186,6 @@ private static long[] getTypeCheckStats(BigBang bb) { continue; } MethodFlowsGraph originalFlows = methodFlow.getMethodFlowsGraph(); - - var cursor = originalFlows.getInstanceOfFlows().getEntries(); - while (cursor.advance()) { - if (StaticAnalysisResultsBuilder.isValidBci(cursor.getKey())) { - totalFilters++; - InstanceOfTypeFlow originalInstanceOf = cursor.getValue(); - - boolean isSaturated = methodFlow.isSaturated(pta, originalInstanceOf); - TypeState instanceOfTypeState = methodFlow.foldTypeFlow(pta, originalInstanceOf); - if (!isSaturated && instanceOfTypeState.typesCount() < 2) { - totalRemovableFilters++; - } - if (!runtimeMethod) { - appTotalFilters++; - if (!isSaturated && instanceOfTypeState.typesCount() < 2) { - appTotalRemovableFilters++; - } - } - } - } } return new long[]{totalFilters, totalRemovableFilters, appTotalFilters, appTotalRemovableFilters}; diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/AbstractAnalysisResultsBuilder.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/AbstractAnalysisResultsBuilder.java deleted file mode 100644 index 27c60b236312..000000000000 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/AbstractAnalysisResultsBuilder.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.pointsto.results; - -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.stream.Stream; - -import com.oracle.graal.pointsto.BigBang; -import com.oracle.graal.pointsto.api.PointstoOptions; -import com.oracle.graal.pointsto.infrastructure.Universe; -import com.oracle.graal.pointsto.meta.AnalysisField; -import com.oracle.graal.pointsto.meta.AnalysisMethod; -import com.oracle.graal.pointsto.typestate.TypeState; - -import jdk.vm.ci.meta.JavaMethodProfile; -import jdk.vm.ci.meta.JavaTypeProfile; -import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.ResolvedJavaType; -import jdk.vm.ci.meta.TriState; - -public abstract class AbstractAnalysisResultsBuilder { - - protected final BigBang bb; - - /** - * The universe used to convert analysis metadata to hosted metadata, or {@code null} if no - * conversion should be performed. - */ - protected final Universe converter; - - /* Caches for JavaTypeProfile with 0, 1, or more types. */ - private final JavaTypeProfile[] types0; - private final JavaTypeProfile[] types1Null; - private final JavaTypeProfile[] types1NonNull; - private final Map types; - - /* Caches for JavaMethodProfile with 0, 1, or more types. */ - private final JavaMethodProfile[] methods0; - private final JavaMethodProfile[] methods1; - private final Map methods; - - protected AbstractAnalysisResultsBuilder(BigBang bb, Universe converter) { - this.bb = bb; - this.converter = converter; - - types0 = new JavaTypeProfile[2]; - types1Null = new JavaTypeProfile[bb.getUniverse().getNextTypeId()]; - types1NonNull = new JavaTypeProfile[bb.getUniverse().getNextTypeId()]; - types = new HashMap<>(); - - methods0 = new JavaMethodProfile[1]; - methods1 = new JavaMethodProfile[bb.getUniverse().getNextMethodId()]; - methods = new HashMap<>(); - } - - public BigBang getBigBang() { - return bb; - } - - public abstract StaticAnalysisResults makeOrApplyResults(AnalysisMethod method); - - public abstract JavaTypeProfile makeTypeProfile(AnalysisField field); - - protected JavaTypeProfile makeTypeProfile(TypeState typeState) { - if (typeState == null || PointstoOptions.AnalysisSizeCutoff.getValue(bb.getOptions()) != -1 && - typeState.typesCount() > PointstoOptions.AnalysisSizeCutoff.getValue(bb.getOptions())) { - return null; - } - - if (typeState.isEmpty()) { - synchronized (types0) { - return cachedTypeProfile(types0, 0, typeState); - } - } else if (typeState.isNull()) { - synchronized (types0) { - return cachedTypeProfile(types0, 1, typeState); - } - } else if (typeState.exactType() != null) { - if (typeState.canBeNull()) { - synchronized (types1Null) { - return cachedTypeProfile(types1Null, typeState.exactType().getId(), typeState); - } - } else { - synchronized (types1NonNull) { - return cachedTypeProfile(types1NonNull, typeState.exactType().getId(), typeState); - } - } - } - synchronized (types) { - JavaTypeProfile created = createTypeProfile(typeState); - types.putIfAbsent(created, created); - return created; - } - } - - private JavaTypeProfile cachedTypeProfile(JavaTypeProfile[] cache, int cacheIdx, TypeState typeState) { - JavaTypeProfile result = cache[cacheIdx]; - if (result == null) { - result = createTypeProfile(typeState); - cache[cacheIdx] = result; - } - return result; - } - - private JavaTypeProfile createTypeProfile(TypeState typeState) { - double probability = 1d / typeState.typesCount(); - - Stream stream = typeState.typesStream(bb); - if (converter != null) { - stream = stream.map(converter::lookup).sorted(converter.hostVM().getTypeComparator()); - } - JavaTypeProfile.ProfiledType[] pitems = stream - .map(type -> new JavaTypeProfile.ProfiledType(type, probability)) - .toArray(JavaTypeProfile.ProfiledType[]::new); - - return new JavaTypeProfile(TriState.get(typeState.canBeNull()), 0, pitems); - } - - protected JavaMethodProfile makeMethodProfile(Collection callees) { - if (PointstoOptions.AnalysisSizeCutoff.getValue(bb.getOptions()) != -1 && callees.size() > PointstoOptions.AnalysisSizeCutoff.getValue(bb.getOptions())) { - return null; - } - if (callees.isEmpty()) { - synchronized (methods0) { - return cachedMethodProfile(methods0, 0, callees); - } - } else if (callees.size() == 1) { - synchronized (methods1) { - return cachedMethodProfile(methods1, callees.iterator().next().getId(), callees); - } - } - synchronized (methods) { - JavaMethodProfile created = createMethodProfile(callees); - methods.putIfAbsent(created, created); - return created; - } - } - - private JavaMethodProfile cachedMethodProfile(JavaMethodProfile[] cache, int cacheIdx, Collection callees) { - JavaMethodProfile result = cache[cacheIdx]; - if (result == null) { - result = createMethodProfile(callees); - cache[cacheIdx] = result; - } - return result; - } - - private JavaMethodProfile createMethodProfile(Collection callees) { - JavaMethodProfile.ProfiledMethod[] pitems = new JavaMethodProfile.ProfiledMethod[callees.size()]; - double probability = 1d / pitems.length; - - int idx = 0; - for (AnalysisMethod aMethod : callees) { - ResolvedJavaMethod convertedMethod = converter == null ? aMethod : converter.lookup(aMethod); - pitems[idx++] = new JavaMethodProfile.ProfiledMethod(convertedMethod, probability); - } - return new JavaMethodProfile(0, pitems); - } -} diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/DefaultResultsBuilder.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/DefaultResultsBuilder.java deleted file mode 100644 index 11556d91affd..000000000000 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/DefaultResultsBuilder.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.pointsto.results; - -import com.oracle.graal.pointsto.BigBang; -import com.oracle.graal.pointsto.infrastructure.Universe; -import com.oracle.graal.pointsto.meta.AnalysisField; -import com.oracle.graal.pointsto.meta.AnalysisMethod; -import jdk.vm.ci.meta.JavaTypeProfile; -import jdk.vm.ci.meta.TriState; - -/** - * Implementation of the ResultsBuilder providing no feedback for optimizations. Used in - * Reachability Analysis. - */ -public class DefaultResultsBuilder extends AbstractAnalysisResultsBuilder { - public DefaultResultsBuilder(BigBang bb, Universe converter) { - super(bb, converter); - } - - @Override - public StaticAnalysisResults makeOrApplyResults(AnalysisMethod method) { - return StaticAnalysisResults.NO_RESULTS; - } - - @Override - public JavaTypeProfile makeTypeProfile(AnalysisField field) { - return new JavaTypeProfile(TriState.UNKNOWN, 1, new JavaTypeProfile.ProfiledType[0]); - } -} diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StaticAnalysisResults.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StaticAnalysisResults.java deleted file mode 100644 index da061e93f418..000000000000 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StaticAnalysisResults.java +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.pointsto.results; - -import com.oracle.graal.pointsto.util.AnalysisError; - -import jdk.vm.ci.meta.DeoptimizationReason; -import jdk.vm.ci.meta.JavaMethodProfile; -import jdk.vm.ci.meta.JavaTypeProfile; -import jdk.vm.ci.meta.ProfilingInfo; -import jdk.vm.ci.meta.TriState; - -public class StaticAnalysisResults implements ProfilingInfo { - public static final StaticAnalysisResults NO_RESULTS = new StaticAnalysisResults(0, null, null, null); - - public static class BytecodeEntry { - /** The bytecode index of this entry. */ - private final int bci; - - /** Next element of linked list, with higher bci. */ - protected BytecodeEntry next; - - /** The method profile for invocation bytecodes. */ - private final JavaMethodProfile methodProfile; - - /** The type profiles for the return type of invocation bytecodes. */ - private final JavaTypeProfile invokeResultTypeProfile; - - /** - * The type profiles for this method (for all bytecodes that have types, e.g., - * invokevirtual, instanceof, checkcast. - */ - private final JavaTypeProfile typeProfile; - - /** The type profiles for this method - updated only with statically calculated profiles. */ - private final JavaTypeProfile staticTypeProfile; - - public BytecodeEntry(int bci, JavaTypeProfile typeProfile, JavaMethodProfile methodProfile, JavaTypeProfile invokeResultTypeProfile, JavaTypeProfile staticTypeProfile) { - this.bci = bci; - this.methodProfile = methodProfile; - this.invokeResultTypeProfile = invokeResultTypeProfile; - this.typeProfile = typeProfile; - this.staticTypeProfile = staticTypeProfile; - } - - @Override - public String toString() { - return "BytecodeEntry(bci=" + bci + ", typeProfile=" + typeProfile + ", methodProfile=" + methodProfile + ", invokeResultTypeProfile=" + invokeResultTypeProfile + ")"; - } - - } - - /** The bytecode size of the method. */ - private final int codeSize; - - /** The type profiles for method parameters. */ - private final JavaTypeProfile[] parameterTypeProfiles; - - /** The type profile for the method result. */ - private final JavaTypeProfile resultTypeProfile; - - private final BytecodeEntry first; - private BytecodeEntry cache; - - public StaticAnalysisResults(int codeSize, JavaTypeProfile[] parameterTypeProfiles, JavaTypeProfile resultTypeProfile, BytecodeEntry first) { - this.codeSize = codeSize; - this.parameterTypeProfiles = parameterTypeProfiles; - this.resultTypeProfile = resultTypeProfile; - this.first = first; - this.cache = first; - } - - /** - * Returns the type profile for the parameter with the given number, or {@code null} if no type - * profile is available. For non-static methods, the receiver is the parameter with number 0. - */ - public JavaTypeProfile getParameterTypeProfile(int parameter) { - if (parameterTypeProfiles != null && parameter < parameterTypeProfiles.length) { - return parameterTypeProfiles[parameter]; - } else { - return null; - } - } - - /** - * Returns the type profile for values returned by the method, or {@code null} if no type - * profile is available. - */ - public JavaTypeProfile getResultTypeProfile() { - return resultTypeProfile; - } - - private BytecodeEntry lookup(int bci) { - if (first == null) { - return null; - } - BytecodeEntry cur = bci >= cache.bci ? cache : first; - while (cur != null && cur.bci < bci) { - cur = cur.next; - } - if (cur != null) { - cache = cur; - if (cur.bci == bci) { - return cur; - } - } - return null; - } - - @Override - public int getCodeSize() { - return codeSize; - } - - @Override - public double getBranchTakenProbability(int bci) { - /* Static analysis cannot determine branch probabilities. */ - return -1; - } - - @Override - public double[] getSwitchProbabilities(int bci) { - /* Static analysis cannot determine branch probabilities. */ - return null; - } - - @Override - public JavaTypeProfile getTypeProfile(int bci) { - BytecodeEntry entry = lookup(bci); - return entry == null ? null : entry.typeProfile; - } - - public JavaTypeProfile getStaticTypeProfile(int bci) { - BytecodeEntry entry = lookup(bci); - return entry == null ? null : entry.staticTypeProfile; - } - - @Override - public JavaMethodProfile getMethodProfile(int bci) { - BytecodeEntry entry = lookup(bci); - return entry == null ? null : entry.methodProfile; - } - - @Override - public TriState getExceptionSeen(int bci) { - /* - * The design of the Substrate VM exception handling allows to be conservative here and - * always return true. Unnecessary exception edges are removed during compilation. - */ - return TriState.TRUE; - } - - @Override - public TriState getNullSeen(int bci) { - BytecodeEntry entry = lookup(bci); - return entry == null ? TriState.UNKNOWN : entry.typeProfile.getNullSeen(); - } - - @Override - public int getExecutionCount(int bci) { - /* Static analysis cannot determine execution counts. */ - return -1; - } - - @Override - public int getDeoptimizationCount(DeoptimizationReason reason) { - /* Ahead-of-time compiled code does not deoptimize. */ - return 0; - } - - @Override - public boolean setCompilerIRSize(Class irType, int size) { - throw AnalysisError.shouldNotReachHere("unreachable"); - } - - @Override - public int getCompilerIRSize(Class irType) { - throw AnalysisError.shouldNotReachHere("unreachable"); - } - - @Override - public boolean isMature() { - /* - * Static analysis results are definitely correct and do not change, but do not provide - * mature branch probability information. - */ - return false; - } - - @Override - public void setMature() { - /* Nothing to do, results cannot change. */ - } -} diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StaticAnalysisResultsBuilder.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StaticAnalysisResultsBuilder.java deleted file mode 100644 index 34ce34d045bf..000000000000 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StaticAnalysisResultsBuilder.java +++ /dev/null @@ -1,272 +0,0 @@ -/* - * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.pointsto.results; - -import java.util.ArrayList; -import java.util.Comparator; -import java.util.stream.Collectors; -import java.util.stream.StreamSupport; - -import jdk.graal.compiler.graph.Node; -import jdk.graal.compiler.graph.NodeSourcePosition; - -import com.oracle.graal.pointsto.PointsToAnalysis; -import com.oracle.graal.pointsto.api.PointstoOptions; -import com.oracle.graal.pointsto.flow.FormalParamTypeFlow; -import com.oracle.graal.pointsto.flow.InstanceOfTypeFlow; -import com.oracle.graal.pointsto.flow.InvokeTypeFlow; -import com.oracle.graal.pointsto.flow.MethodFlowsGraph; -import com.oracle.graal.pointsto.flow.MethodTypeFlow; -import com.oracle.graal.pointsto.flow.MonitorEnterTypeFlow; -import com.oracle.graal.pointsto.flow.TypeFlow; -import com.oracle.graal.pointsto.infrastructure.Universe; -import com.oracle.graal.pointsto.meta.AnalysisField; -import com.oracle.graal.pointsto.meta.AnalysisMethod; -import com.oracle.graal.pointsto.meta.AnalysisType; -import com.oracle.graal.pointsto.results.StaticAnalysisResults.BytecodeEntry; -import com.oracle.graal.pointsto.typestate.TypeState; -import com.oracle.graal.pointsto.typestate.TypeStateUtils; - -import jdk.vm.ci.meta.JavaMethodProfile; -import jdk.vm.ci.meta.JavaTypeProfile; - -public class StaticAnalysisResultsBuilder extends AbstractAnalysisResultsBuilder { - - public StaticAnalysisResultsBuilder(PointsToAnalysis bb, Universe converter) { - super(bb, converter); - } - - private PointsToAnalysis getAnalysis() { - return ((PointsToAnalysis) bb); - } - - @Override - public StaticAnalysisResults makeOrApplyResults(AnalysisMethod method) { - if (!method.isImplementationInvoked()) { - return StaticAnalysisResults.NO_RESULTS; - } - PointsToAnalysis pta = getAnalysis(); - MethodTypeFlow methodFlow = PointsToAnalysis.assertPointsToAnalysisMethod(method).getTypeFlow(); - if (!methodFlow.flowsGraphCreated()) { - return StaticAnalysisResults.NO_RESULTS; - } - MethodFlowsGraph originalFlows = methodFlow.getMethodFlowsGraph(); - - ArrayList paramProfiles = new ArrayList<>(originalFlows.getParameters().length); - for (int i = 0; i < originalFlows.getParameters().length; i++) { - FormalParamTypeFlow parameter = originalFlows.getParameter(i); - if (parameter == null) { - /* - * The paramater can be `null` at this point if it doesn't have any usages inside - * the method, i.e., its TypeFlowBuilder was never materialized. This is an - * optimization carried out by the TypeFlowGraphBuilder. This means that it will not - * have a corresponding type profile. - */ - continue; - } - if (methodFlow.isSaturated(pta, parameter)) { - /* The parameter type flow is saturated, it's type state doesn't matter. */ - continue; - } - - TypeState paramTypeState = methodFlow.foldTypeFlow(pta, parameter); - JavaTypeProfile paramProfile = makeTypeProfile(paramTypeState); - if (paramProfile != null) { - ensureSize(paramProfiles, i); - paramProfiles.set(i, paramProfile); - } - } - JavaTypeProfile[] parameterTypeProfiles = null; - if (paramProfiles.size() > 0) { - parameterTypeProfiles = paramProfiles.toArray(new JavaTypeProfile[paramProfiles.size()]); - } - - JavaTypeProfile resultTypeProfile = makeTypeProfile(methodFlow.foldTypeFlow(pta, originalFlows.getReturnFlow())); - - ArrayList entries = new ArrayList<>(method.getCodeSize()); - - var instanceOfCursor = originalFlows.getInstanceOfFlows().getEntries(); - while (instanceOfCursor.advance()) { - if (isValidBci(instanceOfCursor.getKey())) { - int bci = (int) instanceOfCursor.getKey(); - InstanceOfTypeFlow originalInstanceOf = instanceOfCursor.getValue(); - - if (methodFlow.isSaturated(pta, originalInstanceOf)) { - /* - * If the instance flow is saturated its exact type state doesn't matter. This - * instanceof cannot be optimized. - */ - continue; - } - - /* Fold the instanceof flows. */ - TypeState instanceOfTypeState = methodFlow.foldTypeFlow(pta, originalInstanceOf); - originalInstanceOf.setState(pta, instanceOfTypeState); - - JavaTypeProfile typeProfile = makeTypeProfile(instanceOfTypeState); - if (typeProfile != null) { - ensureSize(entries, bci); - assert entries.get(bci) == null : "In " + method.format("%h.%n(%p)") + " a profile with bci=" + bci + " already exists: " + entries.get(bci); - entries.set(bci, createBytecodeEntry(method, bci, typeProfile, null, null, typeProfile)); - } - } - } - - var invokesCursor = originalFlows.getInvokes().getEntries(); - while (invokesCursor.advance()) { - if (isValidBci(invokesCursor.getKey())) { - int bci = (int) invokesCursor.getKey(); - InvokeTypeFlow originalInvoke = invokesCursor.getValue(); - - TypeState invokeTypeState = null; - /* If the receiver flow is saturated its exact type state doesn't matter. */ - if (originalInvoke.getTargetMethod().hasReceiver() && !methodFlow.isSaturated(pta, originalInvoke.getReceiver())) { - invokeTypeState = methodFlow.foldTypeFlow(pta, originalInvoke.getReceiver()); - originalInvoke.setState(pta, invokeTypeState); - } - - TypeFlow originalReturn = originalInvoke.getActualReturn(); - TypeState returnTypeState = null; - /* If the return flow is saturated its exact type state doesn't matter. */ - if (originalReturn != null && !methodFlow.isSaturated(pta, originalReturn)) { - returnTypeState = methodFlow.foldTypeFlow(pta, originalReturn); - originalReturn.setState(pta, returnTypeState); - } - - JavaTypeProfile typeProfile = makeTypeProfile(invokeTypeState); - JavaMethodProfile methodProfile = makeMethodProfile(originalInvoke.getOriginalCallees()); - JavaTypeProfile invokeResultTypeProfile = originalReturn == null ? null : makeTypeProfile(returnTypeState); - - if (hasStaticProfiles(typeProfile, methodProfile, invokeResultTypeProfile) || hasRuntimeProfiles()) { - ensureSize(entries, bci); - assert entries.get(bci) == null : "In " + method.format("%h.%n(%p)") + " a profile with bci=" + bci + " already exists: " + entries.get(bci); - entries.set(bci, createBytecodeEntry(method, bci, typeProfile, methodProfile, invokeResultTypeProfile, typeProfile)); - } - } - } - - if (PointstoOptions.PrintSynchronizedAnalysis.getValue(pta.getOptions())) { - originalFlows.getMiscFlows().stream() - .filter(flow -> flow instanceof MonitorEnterTypeFlow) - .map(flow -> (MonitorEnterTypeFlow) flow) - .filter(m -> m.getState().typesCount() > 20) - .sorted(Comparator.comparingInt(m2 -> m2.getState().typesCount())) - .forEach(monitorEnter -> { - TypeState monitorEntryState = monitorEnter.getState(); - String typesString = TypeStateUtils.closeToAllInstantiated(pta, monitorEntryState) ? "close to all instantiated" - : StreamSupport.stream(monitorEntryState.types(pta).spliterator(), false).map(AnalysisType::getName).collect(Collectors.joining(", ")); - StringBuilder strb = new StringBuilder(); - strb.append("Location: "); - String methodName = method.format("%h.%n(%p)"); - int bci = monitorEnter.getLocation().getBCI(); - if (isValidBci(bci)) { - StackTraceElement traceElement = method.asStackTraceElement(bci); - String sourceLocation = traceElement.getFileName() + ":" + traceElement.getLineNumber(); - strb.append("@(").append(methodName).append(":").append(bci).append(")"); - strb.append("=(").append(sourceLocation).append(")"); - } else { - strb.append("@(").append(methodName).append(")"); - } - strb.append("\n"); - strb.append("Synchronized types #: ").append(monitorEntryState.typesCount()).append("\n"); - strb.append("Types: ").append(typesString).append("\n"); - System.out.println(strb); - }); - } - - BytecodeEntry first = null; - for (int i = entries.size() - 1; i >= 0; i--) { - BytecodeEntry cur = entries.get(i); - if (cur != null) { - cur.next = first; - first = cur; - } - } - - return createStaticAnalysisResults(method, parameterTypeProfiles, resultTypeProfile, first); - } - - /** - * This method returns a unique key for the given node, used to store and query invoke and - * instance-of type flows. - * - * Unless the node comes from a substitution, the unique key is the BCI of the node. Every - * newinstance/newarray/newmultiarray/instanceof/checkcast node coming from a substitution - * method cannot have a BCI. If one substitution has multiple nodes of the same type, then the - * BCI would not be unique. In the later case the key is a unique object. - */ - public static Object uniqueKey(Node node) { - NodeSourcePosition position = node.getNodeSourcePosition(); - /* If 'position' has a 'caller' then it is inlined, so the BCI is probably not unique. */ - if (position != null && position.getCaller() == null) { - if (position.getBCI() >= 0) { - return position.getBCI(); - } - } - return new Object(); - } - - /** Check if the key, provided by {@link #uniqueKey(Node)} above is an actual BCI. */ - public static boolean isValidBci(Object key) { - if (key instanceof Integer) { - int bci = (int) key; - return bci >= 0; - } - return false; - } - - protected BytecodeEntry createBytecodeEntry(@SuppressWarnings("unused") AnalysisMethod method, int bci, JavaTypeProfile typeProfile, JavaMethodProfile methodProfile, - JavaTypeProfile invokeResultTypeProfile, JavaTypeProfile staticTypeProfile) { - return new BytecodeEntry(bci, typeProfile, methodProfile, invokeResultTypeProfile, staticTypeProfile); - } - - protected StaticAnalysisResults createStaticAnalysisResults(AnalysisMethod method, JavaTypeProfile[] parameterTypeProfiles, JavaTypeProfile resultTypeProfile, BytecodeEntry first) { - if (parameterTypeProfiles == null && resultTypeProfile == null && first == null) { - return StaticAnalysisResults.NO_RESULTS; - } else { - return new StaticAnalysisResults(method.getCodeSize(), parameterTypeProfiles, resultTypeProfile, first); - } - } - - protected boolean hasRuntimeProfiles() { - return false; - } - - private static boolean hasStaticProfiles(JavaTypeProfile typeProfile, JavaMethodProfile methodProfile, JavaTypeProfile invokeResultTypeProfile) { - return typeProfile != null || methodProfile != null || invokeResultTypeProfile != null; - } - - private static void ensureSize(ArrayList list, int index) { - list.ensureCapacity(index); - while (list.size() <= index) { - list.add(null); - } - } - - @Override - public JavaTypeProfile makeTypeProfile(AnalysisField field) { - return makeTypeProfile(field.getTypeState()); - } -} diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StrengthenGraphs.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StrengthenGraphs.java index 3a6805f553fc..605132dd0f2d 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StrengthenGraphs.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StrengthenGraphs.java @@ -27,12 +27,31 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicLong; import java.util.function.Function; import java.util.function.Supplier; +import java.util.stream.Stream; import org.graalvm.collections.EconomicSet; + +import com.oracle.graal.pointsto.BigBang; +import com.oracle.graal.pointsto.PointsToAnalysis; +import com.oracle.graal.pointsto.api.PointstoOptions; +import com.oracle.graal.pointsto.flow.AnalysisParsedGraph; +import com.oracle.graal.pointsto.flow.InvokeTypeFlow; +import com.oracle.graal.pointsto.flow.MethodFlowsGraph; +import com.oracle.graal.pointsto.flow.MethodTypeFlow; +import com.oracle.graal.pointsto.flow.TypeFlow; +import com.oracle.graal.pointsto.infrastructure.Universe; +import com.oracle.graal.pointsto.meta.AnalysisMethod; +import com.oracle.graal.pointsto.meta.AnalysisType; +import com.oracle.graal.pointsto.meta.PointsToAnalysisMethod; +import com.oracle.graal.pointsto.typestate.TypeState; +import com.oracle.svm.util.ImageBuildStatistics; + import jdk.graal.compiler.core.common.type.AbstractObjectStamp; import jdk.graal.compiler.core.common.type.ObjectStamp; import jdk.graal.compiler.core.common.type.Stamp; @@ -87,27 +106,14 @@ import jdk.graal.compiler.phases.common.CanonicalizerPhase.CustomSimplification; import jdk.graal.compiler.phases.common.inlining.InliningUtil; import jdk.graal.compiler.printer.GraalDebugHandlersFactory; - -import com.oracle.graal.pointsto.PointsToAnalysis; -import com.oracle.graal.pointsto.flow.AnalysisParsedGraph; -import com.oracle.graal.pointsto.flow.InvokeTypeFlow; -import com.oracle.graal.pointsto.flow.MethodFlowsGraph; -import com.oracle.graal.pointsto.flow.MethodTypeFlow; -import com.oracle.graal.pointsto.flow.TypeFlow; -import com.oracle.graal.pointsto.infrastructure.Universe; -import com.oracle.graal.pointsto.meta.AnalysisField; -import com.oracle.graal.pointsto.meta.AnalysisMethod; -import com.oracle.graal.pointsto.meta.AnalysisType; -import com.oracle.graal.pointsto.meta.PointsToAnalysisMethod; -import com.oracle.graal.pointsto.typestate.TypeState; -import com.oracle.svm.util.ImageBuildStatistics; - import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.JavaMethodProfile; import jdk.vm.ci.meta.JavaTypeProfile; +import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.TriState; /** * This class applies static analysis results directly to the {@link StructuredGraph Graal IR} used @@ -126,20 +132,35 @@ * precise stamp. We need to do that indirectly by adding a {@link PiNode} that is anchored using a * {@link ValueAnchorNode}. */ -public abstract class StrengthenGraphs extends AbstractAnalysisResultsBuilder { +public abstract class StrengthenGraphs { public static class Options { @Option(help = "Perform constant folding in StrengthenGraphs")// public static final OptionKey StrengthenGraphWithConstants = new OptionKey<>(true); } + protected final BigBang bb; + /** + * The universe used to convert analysis metadata to hosted metadata, or {@code null} if no + * conversion should be performed. + */ + protected final Universe converter; + + private final Map cachedTypeProfiles = new ConcurrentHashMap<>(); + private final Map cachedMethodProfiles = new ConcurrentHashMap<>(); + + /* Cached option values to avoid repeated option lookup. */ + private final int analysisSizeCutoff; private final boolean strengthenGraphWithConstants; private final StrengthenGraphsCounters beforeCounters; private final StrengthenGraphsCounters afterCounters; - public StrengthenGraphs(PointsToAnalysis bb, Universe converter) { - super(bb, converter); + public StrengthenGraphs(BigBang bb, Universe converter) { + this.bb = bb; + this.converter = converter; + + analysisSizeCutoff = PointstoOptions.AnalysisSizeCutoff.getValue(bb.getOptions()); strengthenGraphWithConstants = Options.StrengthenGraphWithConstants.getValue(bb.getOptions()); if (ImageBuildStatistics.Options.CollectImageBuildStatistics.getValue(bb.getOptions())) { @@ -151,59 +172,37 @@ public StrengthenGraphs(PointsToAnalysis bb, Universe converter) { } } - private PointsToAnalysis getAnalysis() { - return ((PointsToAnalysis) bb); - } - - @Override @SuppressWarnings("try") - public StaticAnalysisResults makeOrApplyResults(AnalysisMethod m) { - if (!m.isImplementationInvoked()) { - return StaticAnalysisResults.NO_RESULTS; + public final void applyResults(AnalysisMethod method) { + var nodeReferences = method instanceof PointsToAnalysisMethod ptaMethod && ptaMethod.getTypeFlow().flowsGraphCreated() + ? ptaMethod.getTypeFlow().getMethodFlowsGraph().getNodeFlows().getKeys() + : null; + var debug = new DebugContext.Builder(bb.getOptions(), new GraalDebugHandlersFactory(bb.getSnippetReflectionProvider())).build(); + var graph = method.decodeAnalyzedGraph(debug, nodeReferences); + if (graph == null) { + return; } - PointsToAnalysisMethod method = PointsToAnalysis.assertPointsToAnalysisMethod(m); - MethodTypeFlow methodTypeFlow = method.getTypeFlow(); - if (!methodTypeFlow.flowsGraphCreated()) { - return StaticAnalysisResults.NO_RESULTS; + + graph.resetDebug(debug); + if (beforeCounters != null) { + beforeCounters.collect(graph); } - DebugContext debug = new DebugContext.Builder(bb.getOptions(), new GraalDebugHandlersFactory(bb.getSnippetReflectionProvider())).build(); - StructuredGraph graph = method.decodeAnalyzedGraph(debug, methodTypeFlow.getMethodFlowsGraph().getNodeFlows().getKeys()); - if (graph != null) { - graph.resetDebug(debug); - if (beforeCounters != null) { - beforeCounters.collect(graph); - } - try (DebugContext.Scope s = debug.scope("StrengthenGraphs", graph); - DebugContext.Activation a = debug.activate()) { - new AnalysisStrengthenGraphsPhase(method, graph).apply(graph, bb.getProviders(method)); - } catch (Throwable ex) { - debug.handle(ex); - } - if (afterCounters != null) { - afterCounters.collect(graph); - } - method.setAnalyzedGraph(GraphEncoder.encodeSingleGraph(graph, AnalysisParsedGraph.HOST_ARCHITECTURE)); + try (var s = debug.scope("StrengthenGraphs", graph); var a = debug.activate()) { + new AnalysisStrengthenGraphsPhase(method, graph).apply(graph, bb.getProviders(method)); + } catch (Throwable ex) { + debug.handle(ex); } - - /* Ensure that the temporarily decoded graph is not kept alive via the node references. */ - var cursor = methodTypeFlow.getMethodFlowsGraph().getNodeFlows().getEntries(); - while (cursor.advance()) { - cursor.getKey().clear(); + if (afterCounters != null) { + afterCounters.collect(graph); } - /* - * All information from the static analysis has been incorporated into the graph. There is - * no benefit in keeping results around anymore. - */ - return StaticAnalysisResults.NO_RESULTS; - } + method.setAnalyzedGraph(GraphEncoder.encodeSingleGraph(graph, AnalysisParsedGraph.HOST_ARCHITECTURE)); - @Override - public JavaTypeProfile makeTypeProfile(AnalysisField field) { - /* - * Since LoadFieldNode are improved directly in this class, there is no need to provide a - * type profile for fields. - */ - return null; + if (nodeReferences != null) { + /* Ensure the temporarily decoded graph is not kept alive via the node references. */ + for (var nodeReference : nodeReferences) { + nodeReference.clear(); + } + } } /* @@ -236,11 +235,11 @@ public JavaTypeProfile makeTypeProfile(AnalysisField field) { protected abstract boolean simplifyDelegate(Node n, SimplifierTool tool); - // Wrapper to clearly identify phase + /* Wrapper to clearly identify phase in IGV graph dumps. */ class AnalysisStrengthenGraphsPhase extends BasePhase { final CanonicalizerPhase phase; - AnalysisStrengthenGraphsPhase(PointsToAnalysisMethod method, StructuredGraph graph) { + AnalysisStrengthenGraphsPhase(AnalysisMethod method, StructuredGraph graph) { phase = CanonicalizerPhase.create().copyWithCustomSimplification(new StrengthenSimplifier(method, graph)); } @@ -276,45 +275,55 @@ class StrengthenSimplifier implements CustomSimplification { /** * For runtime compiled methods, we must be careful to ensure new SubstrateTypes are not - * created due to the optimizations performed during the AnalysisStrengthenGraphsPhase. + * created due to the optimizations performed during the + * {@link AnalysisStrengthenGraphsPhase}. */ private final Function toTargetFunction; - StrengthenSimplifier(PointsToAnalysisMethod method, StructuredGraph graph) { + StrengthenSimplifier(AnalysisMethod method, StructuredGraph graph) { this.graph = graph; - this.methodFlow = method.getTypeFlow(); this.createdPiNodes = new NodeBitMap(graph); - MethodFlowsGraph originalFlows = methodFlow.getMethodFlowsGraph(); - parameterFlows = originalFlows.getParameters(); - nodeFlows = new NodeMap<>(graph); - var cursor = originalFlows.getNodeFlows().getEntries(); - while (cursor.advance()) { - Node node = cursor.getKey().getNode(); - assert nodeFlows.get(node) == null : "overwriting existing entry for " + node; - nodeFlows.put(node, cursor.getValue()); - } + if (method instanceof PointsToAnalysisMethod ptaMethod && ptaMethod.getTypeFlow().flowsGraphCreated()) { + methodFlow = ptaMethod.getTypeFlow(); + MethodFlowsGraph originalFlows = methodFlow.getMethodFlowsGraph(); + parameterFlows = originalFlows.getParameters(); + nodeFlows = new NodeMap<>(graph); + var cursor = originalFlows.getNodeFlows().getEntries(); + while (cursor.advance()) { + Node node = cursor.getKey().getNode(); + assert nodeFlows.get(node) == null : "overwriting existing entry for " + node; + nodeFlows.put(node, cursor.getValue()); + } - this.allowConstantFolding = strengthenGraphWithConstants && bb.getHostVM().allowConstantFolding(method); + allowConstantFolding = strengthenGraphWithConstants && bb.getHostVM().allowConstantFolding(method); - /* - * In deoptimization target methods optimizing the return parameter can make new values - * live across deoptimization entrypoints. - * - * In runtime-compiled methods invokes may be intrinsified during runtime partial - * evaluation and change the behavior of the invoke. This would be a problem if the - * behavior of the method completely changed; however, currently this intrinsification - * is used to improve the stamp of the returned value, but not to alter the semantics. - * Hence, it is preferred to continue to use the return value of the invoke (as opposed - * to the parameter value). - */ - this.allowOptimizeReturnParameter = method.isOriginalMethod(); + /* + * In deoptimization target methods optimizing the return parameter can make new + * values live across deoptimization entrypoints. + * + * In runtime-compiled methods invokes may be intrinsified during runtime partial + * evaluation and change the behavior of the invoke. This would be a problem if the + * behavior of the method completely changed; however, currently this + * intrinsification is used to improve the stamp of the returned value, but not to + * alter the semantics. Hence, it is preferred to continue to use the return value + * of the invoke (as opposed to the parameter value). + */ + allowOptimizeReturnParameter = method.isOriginalMethod() && ((PointsToAnalysis) bb).optimizeReturnedParameter(); + + } else { + methodFlow = null; + parameterFlows = null; + nodeFlows = null; + allowConstantFolding = false; + allowOptimizeReturnParameter = false; + } this.toTargetFunction = bb.getHostVM().getStrengthenGraphsToTargetFunction(method.getMultiMethodKey()); } private TypeFlow getNodeFlow(Node node) { - return nodeFlows.isNew(node) ? null : nodeFlows.get(node); + return nodeFlows == null || nodeFlows.isNew(node) ? null : nodeFlows.get(node); } @Override @@ -340,7 +349,7 @@ public void simplify(Node n, SimplifierTool tool) { if (simplifyDelegate(n, tool)) { // handled elsewhere - } else if (n instanceof ParameterNode) { + } else if (n instanceof ParameterNode && parameterFlows != null) { ParameterNode node = (ParameterNode) n; StartNode anchorPoint = graph.start(); Object newStampOrConstant = strengthenStampFromTypeFlow(node, parameterFlows[node.index()], anchorPoint, tool); @@ -472,11 +481,28 @@ private AnalysisType asConstantNonReachableType(ValueNode value, CoreProviders p } private void handleInvoke(Invoke invoke, SimplifierTool tool) { - PointsToAnalysis pta = getAnalysis(); FixedNode node = invoke.asFixedNode(); MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget(); + if (callTarget.invokeKind().isDirect() && !((AnalysisMethod) callTarget.targetMethod()).isSimplyImplementationInvoked()) { + /* + * This is a direct call to a method that the static analysis did not see as + * invoked. This can happen when the receiver is always null. In most cases, the + * method profile also has a length of 0 and the below code to kill the invoke would + * trigger. But when only running the reachability analysis, there is no detailed + * list of callees. + */ + unreachableInvoke(invoke, tool); + /* Invoke is unreachable, there is no point in improving any types further. */ + return; + } + InvokeTypeFlow invokeFlow = (InvokeTypeFlow) getNodeFlow(node); + if (invokeFlow == null) { + /* No points-to analysis results. */ + return; + } + Collection callees = invokeFlow.getOriginalCallees(); if (callees.isEmpty()) { unreachableInvoke(invoke, tool); @@ -534,8 +560,8 @@ private void handleInvoke(Invoke invoke, SimplifierTool tool) { } else { TypeState receiverTypeState = null; /* If the receiver flow is saturated, its exact type state does not matter. */ - if (invokeFlow.getTargetMethod().hasReceiver() && !methodFlow.isSaturated(pta, invokeFlow.getReceiver())) { - receiverTypeState = methodFlow.foldTypeFlow(pta, invokeFlow.getReceiver()); + if (invokeFlow.getTargetMethod().hasReceiver() && !methodFlow.isSaturated((PointsToAnalysis) bb, invokeFlow.getReceiver())) { + receiverTypeState = methodFlow.foldTypeFlow((PointsToAnalysis) bb, invokeFlow.getReceiver()); } JavaTypeProfile typeProfile = makeTypeProfile(receiverTypeState); @@ -546,7 +572,7 @@ private void handleInvoke(Invoke invoke, SimplifierTool tool) { setInvokeProfiles(invoke, typeProfile, methodProfile); } - if (allowOptimizeReturnParameter && getAnalysis().optimizeReturnedParameter()) { + if (allowOptimizeReturnParameter) { optimizeReturnedParameter(callees, arguments, node, tool); } @@ -638,11 +664,10 @@ private void devirtualizeInvoke(AnalysisMethod singleCallee, Invoke invoke) { } private boolean isUnreachable(Node branch) { - PointsToAnalysis pta = getAnalysis(); TypeFlow branchFlow = getNodeFlow(branch); return branchFlow != null && - !methodFlow.isSaturated(pta, branchFlow) && - methodFlow.foldTypeFlow(pta, branchFlow).isEmpty(); + !methodFlow.isSaturated((PointsToAnalysis) bb, branchFlow) && + methodFlow.foldTypeFlow((PointsToAnalysis) bb, branchFlow).isEmpty(); } private void updateStampInPlace(ValueNode node, Stamp newStamp, SimplifierTool tool) { @@ -704,11 +729,10 @@ private ValueNode insertPi(ValueNode input, Object newStampOrConstant, FixedWith } private Object strengthenStampFromTypeFlow(ValueNode node, TypeFlow nodeFlow, FixedWithNextNode anchorPoint, SimplifierTool tool) { - PointsToAnalysis pta = getAnalysis(); - if (node.getStackKind() != JavaKind.Object) { + if (nodeFlow == null || node.getStackKind() != JavaKind.Object) { return null; } - if (methodFlow.isSaturated(pta, nodeFlow)) { + if (methodFlow.isSaturated((PointsToAnalysis) bb, nodeFlow)) { /* The type flow is saturated, its type state does not matter. */ return null; } @@ -723,7 +747,7 @@ private Object strengthenStampFromTypeFlow(ValueNode node, TypeFlow nodeFlow, */ boolean hasUsages = node.usages().filter(n -> !(n instanceof FrameState)).isNotEmpty(); - TypeState nodeTypeState = methodFlow.foldTypeFlow(pta, nodeFlow); + TypeState nodeTypeState = methodFlow.foldTypeFlow((PointsToAnalysis) bb, nodeFlow); if (hasUsages && allowConstantFolding && !nodeTypeState.canBeNull()) { JavaConstant constantValue = nodeTypeState.asConstant(); @@ -744,7 +768,7 @@ private Object strengthenStampFromTypeFlow(ValueNode node, TypeFlow nodeFlow, * stamp is already more precise than the static analysis results. */ List typeStateTypes = new ArrayList<>(nodeTypeState.typesCount()); - for (AnalysisType typeStateType : nodeTypeState.types(pta)) { + for (AnalysisType typeStateType : nodeTypeState.types(bb)) { if (oldType == null || (oldStamp.isExactType() ? oldType.equals(typeStateType) : oldType.isJavaLangObject() || oldType.isAssignableFrom(typeStateType))) { typeStateTypes.add(typeStateType); } @@ -891,6 +915,50 @@ private Stamp strengthenStamp(Stamp s) { return newStamp; } } + + protected JavaTypeProfile makeTypeProfile(TypeState typeState) { + if (typeState == null || analysisSizeCutoff != -1 && typeState.typesCount() > analysisSizeCutoff) { + return null; + } + var created = createTypeProfile(typeState); + var existing = cachedTypeProfiles.putIfAbsent(created, created); + return existing != null ? existing : created; + } + + private JavaTypeProfile createTypeProfile(TypeState typeState) { + double probability = 1d / typeState.typesCount(); + + Stream stream = typeState.typesStream(bb); + if (converter != null) { + stream = stream.map(converter::lookup).sorted(converter.hostVM().getTypeComparator()); + } + JavaTypeProfile.ProfiledType[] pitems = stream + .map(type -> new JavaTypeProfile.ProfiledType(type, probability)) + .toArray(JavaTypeProfile.ProfiledType[]::new); + + return new JavaTypeProfile(TriState.get(typeState.canBeNull()), 0, pitems); + } + + protected JavaMethodProfile makeMethodProfile(Collection callees) { + if (analysisSizeCutoff != -1 && callees.size() > analysisSizeCutoff) { + return null; + } + var created = createMethodProfile(callees); + var existing = cachedMethodProfiles.putIfAbsent(created, created); + return existing != null ? existing : created; + } + + private JavaMethodProfile createMethodProfile(Collection callees) { + JavaMethodProfile.ProfiledMethod[] pitems = new JavaMethodProfile.ProfiledMethod[callees.size()]; + double probability = 1d / pitems.length; + + int idx = 0; + for (AnalysisMethod aMethod : callees) { + ResolvedJavaMethod convertedMethod = converter == null ? aMethod : converter.lookup(aMethod); + pitems[idx++] = new JavaMethodProfile.ProfiledMethod(convertedMethod, probability); + } + return new JavaMethodProfile(0, pitems); + } } /** diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/PointsToStats.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/PointsToStats.java index b6f6b82f9779..f5ca99aeee69 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/PointsToStats.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/PointsToStats.java @@ -43,9 +43,6 @@ import java.util.function.Function; import java.util.stream.Collectors; -import jdk.graal.compiler.graph.NodeSourcePosition; -import jdk.graal.compiler.nodes.ValueNode; - import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.PointsToAnalysis; import com.oracle.graal.pointsto.flow.ActualReturnTypeFlow; @@ -61,7 +58,6 @@ import com.oracle.graal.pointsto.flow.FormalParamTypeFlow; import com.oracle.graal.pointsto.flow.FormalReturnTypeFlow; import com.oracle.graal.pointsto.flow.FrozenFieldFilterTypeFlow; -import com.oracle.graal.pointsto.flow.InstanceOfTypeFlow; import com.oracle.graal.pointsto.flow.InvokeTypeFlow; import com.oracle.graal.pointsto.flow.LoadFieldTypeFlow.LoadInstanceFieldTypeFlow; import com.oracle.graal.pointsto.flow.LoadFieldTypeFlow.LoadStaticFieldTypeFlow; @@ -85,6 +81,8 @@ import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.svm.util.ClassUtil; +import jdk.graal.compiler.graph.NodeSourcePosition; +import jdk.graal.compiler.nodes.ValueNode; import jdk.vm.ci.code.BytecodePosition; import jdk.vm.ci.common.JVMCIError; import jdk.vm.ci.meta.JavaType; @@ -496,9 +494,6 @@ private static String asString(TypeFlow flow) { } else if (flow instanceof FrozenFieldFilterTypeFlow) { FrozenFieldFilterTypeFlow filter = (FrozenFieldFilterTypeFlow) flow; return "FrozenFieldFilter(" + formatField(filter.getSource()) + ")"; - } else if (flow instanceof InstanceOfTypeFlow) { - InstanceOfTypeFlow instanceOf = (InstanceOfTypeFlow) flow; - return "InstanceOf(" + formatType(instanceOf.getDeclaredType(), true) + ")@" + formatSource(flow); } else if (flow instanceof NewInstanceTypeFlow) { return "NewInstance(" + flow.getDeclaredType().toJavaName(false) + ")@" + formatSource(flow); } else if (flow instanceof DynamicNewInstanceTypeFlow) { diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/TypeState.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/TypeState.java index c63b62233b5e..f0a66342bde8 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/TypeState.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/TypeState.java @@ -122,17 +122,6 @@ public boolean isMerged() { return false; } - public boolean verifyDeclaredType(BigBang bb, AnalysisType declaredType) { - if (declaredType != null) { - for (AnalysisType e : types(bb)) { - if (!declaredType.isAssignableFrom(e)) { - return false; - } - } - } - return true; - } - @Override public int hashCode() { return super.hashCode(); @@ -211,11 +200,6 @@ public static TypeState forUnion(PointsToAnalysis bb, TypeState s1, TypeState s2 } public static TypeState forIntersection(PointsToAnalysis bb, TypeState s1, TypeState s2) { - /* - * All filtered types (s1) must be marked as instantiated to ensures that the filter state - * (s2) has been updated before a type appears in the input, otherwise types can be missed. - */ - assert !bb.extendedAsserts() || checkTypes(bb, s1); if (s1.isEmpty()) { return s1; } else if (s1.isNull()) { @@ -236,11 +220,6 @@ public static TypeState forIntersection(PointsToAnalysis bb, TypeState s1, TypeS } public static TypeState forSubtraction(PointsToAnalysis bb, TypeState s1, TypeState s2) { - /* - * All filtered types (s1) must be marked as instantiated to ensures that the filter state - * (s2) has been updated before a type appears in the input, otherwise types can be missed. - */ - assert !bb.extendedAsserts() || checkTypes(bb, s1); if (s1.isEmpty()) { return s1; } else if (s1.isNull()) { @@ -259,17 +238,6 @@ public static TypeState forSubtraction(PointsToAnalysis bb, TypeState s1, TypeSt return bb.analysisPolicy().doSubtraction(bb, (MultiTypeState) s1, (MultiTypeState) s2); } } - - private static boolean checkTypes(BigBang bb, TypeState state) { - for (AnalysisType type : state.types(bb)) { - if (!type.isInstantiated()) { - System.out.println("Processing a type not yet marked as instantiated: " + type.getName()); - return false; - } - } - return true; - } - } final class EmptyTypeState extends TypeState { 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 2e0e854b4834..954b3ae74853 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 @@ -198,28 +198,10 @@ public void markMethodSpecialInvoked(ReachabilityAnalysisMethod targetMethod, Ob } } + /* Method is overwritten so that other classes in this package can invoke it. */ @Override - public boolean registerTypeAsInHeap(AnalysisType t, Object reason) { - ReachabilityAnalysisType type = (ReachabilityAnalysisType) t; - if (!type.registerAsInHeap(reason)) { - return false; - } - if (type.registerAsInstantiated()) { - schedule(() -> onTypeInstantiated(type, reason)); - } - return true; - } - - @Override - public boolean registerTypeAsAllocated(AnalysisType t, Object reason) { - ReachabilityAnalysisType type = (ReachabilityAnalysisType) t; - if (!type.registerAsAllocated(reason)) { - return false; - } - if (type.registerAsInstantiated()) { - schedule(() -> onTypeInstantiated(type, reason)); - } - return true; + protected void schedule(Runnable task) { + super.schedule(task); } /** @@ -267,7 +249,7 @@ private void onMethodInvoked(ReachabilityAnalysisMethod method, Object reason) { * NUMBER_OF_INVOKED_METHODS_ON_TYPE). and is one of the places that we should try to optimize * in near future. */ - private void onTypeInstantiated(ReachabilityAnalysisType type, Object reason) { + protected void onTypeInstantiated(ReachabilityAnalysisType type, Object reason) { type.forAllSuperTypes(current -> { Set invokedMethods = ((ReachabilityAnalysisType) current).getInvokedVirtualMethods(); for (ReachabilityAnalysisMethod curr : invokedMethods) { diff --git a/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/ReachabilityAnalysisType.java b/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/ReachabilityAnalysisType.java index 652fd97ff27d..fd53209e59cf 100644 --- a/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/ReachabilityAnalysisType.java +++ b/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/ReachabilityAnalysisType.java @@ -62,7 +62,31 @@ public ReachabilityAnalysisType(AnalysisUniverse universe, ResolvedJavaType java super(universe, javaType, storageKind, objectType, cloneableType); } - public boolean registerAsInstantiated() { + @Override + public boolean registerAsInHeap(Object reason) { + if (!super.registerAsInHeap(reason)) { + return false; + } + if (registerAsInstantiated()) { + ReachabilityAnalysisEngine bb = (ReachabilityAnalysisEngine) universe.getBigbang(); + bb.schedule(() -> bb.onTypeInstantiated(this, reason)); + } + return true; + } + + @Override + public boolean registerAsAllocated(Object reason) { + if (!super.registerAsAllocated(reason)) { + return false; + } + if (registerAsInstantiated()) { + ReachabilityAnalysisEngine bb = (ReachabilityAnalysisEngine) universe.getBigbang(); + bb.schedule(() -> bb.onTypeInstantiated(this, reason)); + } + return true; + } + + private boolean registerAsInstantiated() { return AtomicUtils.atomicMark(this, isInstantiatedUpdater); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/replacements/SubstrateGraphKit.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/replacements/SubstrateGraphKit.java index bb824d02a3ba..93581b390642 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/replacements/SubstrateGraphKit.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/replacements/SubstrateGraphKit.java @@ -27,6 +27,19 @@ import java.util.ArrayList; import java.util.List; +import org.graalvm.word.WordBase; + +import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.graal.code.SubstrateCallingConventionKind; +import com.oracle.svm.core.graal.meta.SubstrateLoweringProvider; +import com.oracle.svm.core.graal.nodes.DeoptEntryNode; +import com.oracle.svm.core.nodes.CFunctionCaptureNode; +import com.oracle.svm.core.nodes.CFunctionEpilogueNode; +import com.oracle.svm.core.nodes.CFunctionPrologueNode; +import com.oracle.svm.core.nodes.SubstrateMethodCallTargetNode; +import com.oracle.svm.core.thread.VMThreads.StatusSupport; +import com.oracle.svm.core.util.VMError; + import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; import jdk.graal.compiler.core.common.CompilationIdentifier; import jdk.graal.compiler.core.common.spi.ForeignCallDescriptor; @@ -72,19 +85,6 @@ import jdk.graal.compiler.phases.util.Providers; import jdk.graal.compiler.replacements.GraphKit; import jdk.graal.compiler.word.WordTypes; -import org.graalvm.word.WordBase; - -import com.oracle.svm.core.SubstrateOptions; -import com.oracle.svm.core.graal.code.SubstrateCallingConventionKind; -import com.oracle.svm.core.graal.meta.SubstrateLoweringProvider; -import com.oracle.svm.core.graal.nodes.DeoptEntryNode; -import com.oracle.svm.core.nodes.CFunctionCaptureNode; -import com.oracle.svm.core.nodes.CFunctionEpilogueNode; -import com.oracle.svm.core.nodes.CFunctionPrologueNode; -import com.oracle.svm.core.nodes.SubstrateMethodCallTargetNode; -import com.oracle.svm.core.thread.VMThreads.StatusSupport; -import com.oracle.svm.core.util.VMError; - import jdk.vm.ci.code.BytecodeFrame; import jdk.vm.ci.code.CallingConvention; import jdk.vm.ci.meta.Constant; @@ -122,8 +122,8 @@ public SubstrateGraphKit(DebugContext debug, ResolvedJavaMethod stubMethod, Prov } @Override - protected MethodCallTargetNode createMethodCallTarget(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, StampPair returnStamp, int bci) { - return new SubstrateMethodCallTargetNode(invokeKind, targetMethod, args, returnStamp, null, null, null); + public MethodCallTargetNode createMethodCallTarget(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, StampPair returnStamp, int bci) { + return new SubstrateMethodCallTargetNode(invokeKind, targetMethod, args, returnStamp); } public SubstrateLoweringProvider getLoweringProvider() { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/nodes/SubstrateMethodCallTargetNode.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/nodes/SubstrateMethodCallTargetNode.java index d4f63ee9f734..b3f2db848548 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/nodes/SubstrateMethodCallTargetNode.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/nodes/SubstrateMethodCallTargetNode.java @@ -29,7 +29,6 @@ import jdk.graal.compiler.nodeinfo.NodeInfo; import jdk.graal.compiler.nodes.ValueNode; import jdk.graal.compiler.nodes.java.MethodCallTargetNode; - import jdk.vm.ci.meta.JavaMethodProfile; import jdk.vm.ci.meta.JavaTypeProfile; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -46,11 +45,8 @@ public final class SubstrateMethodCallTargetNode extends MethodCallTargetNode { */ private JavaTypeProfile staticTypeProfile; - public SubstrateMethodCallTargetNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] arguments, StampPair returnStamp, JavaTypeProfile typeProfile, - JavaMethodProfile methodProfile, JavaTypeProfile staticTypeProfile) { - super(TYPE, invokeKind, targetMethod, arguments, returnStamp, typeProfile); - this.methodProfile = methodProfile; - this.staticTypeProfile = staticTypeProfile; + public SubstrateMethodCallTargetNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] arguments, StampPair returnStamp) { + super(TYPE, invokeKind, targetMethod, arguments, returnStamp, null); } public void setProfiles(JavaTypeProfile typeProfile, JavaMethodProfile methodProfile) { diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/LegacyRuntimeCompilationFeature.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/LegacyRuntimeCompilationFeature.java deleted file mode 100644 index c4f7f0826ea2..000000000000 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/LegacyRuntimeCompilationFeature.java +++ /dev/null @@ -1,558 +0,0 @@ -/* - * Copyright (c) 2022, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.svm.graal.hosted; - -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.Deque; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Function; -import java.util.stream.Collectors; - -import jdk.graal.compiler.api.replacements.Fold; -import jdk.graal.compiler.core.common.spi.ConstantFieldProvider; -import jdk.graal.compiler.debug.DebugContext; -import jdk.graal.compiler.graph.Node; -import jdk.graal.compiler.graph.NodeClass; -import jdk.graal.compiler.java.BytecodeParser; -import jdk.graal.compiler.java.GraphBuilderPhase; -import jdk.graal.compiler.loop.phases.ConvertDeoptimizeToGuardPhase; -import jdk.graal.compiler.nodes.CallTargetNode; -import jdk.graal.compiler.nodes.FixedGuardNode; -import jdk.graal.compiler.nodes.FrameState; -import jdk.graal.compiler.nodes.GraphEncoder; -import jdk.graal.compiler.nodes.Invoke; -import jdk.graal.compiler.nodes.LogicConstantNode; -import jdk.graal.compiler.nodes.StructuredGraph; -import jdk.graal.compiler.nodes.ValueNode; -import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; -import jdk.graal.compiler.nodes.graphbuilderconf.IntrinsicContext; -import jdk.graal.compiler.nodes.java.MethodCallTargetNode; -import jdk.graal.compiler.phases.OptimisticOptimizations; -import jdk.graal.compiler.phases.common.CanonicalizerPhase; -import jdk.graal.compiler.phases.common.IterativeConditionalEliminationPhase; -import jdk.graal.compiler.phases.common.inlining.InliningUtil; -import jdk.graal.compiler.phases.util.Providers; -import jdk.graal.compiler.truffle.phases.DeoptimizeOnExceptionPhase; -import jdk.graal.compiler.word.WordTypes; -import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.nativeimage.hosted.Feature; - -import com.oracle.graal.pointsto.BigBang; -import com.oracle.graal.pointsto.flow.InvokeTypeFlow; -import com.oracle.graal.pointsto.infrastructure.GraphProvider; -import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; -import com.oracle.graal.pointsto.meta.AnalysisMethod; -import com.oracle.graal.pointsto.meta.PointsToAnalysisMethod; -import com.oracle.svm.core.config.ConfigurationValues; -import com.oracle.svm.core.util.VMError; -import com.oracle.svm.graal.GraalSupport; -import com.oracle.svm.graal.meta.SubstrateMethod; -import com.oracle.svm.hosted.FeatureImpl; -import com.oracle.svm.hosted.HeapBreakdownProvider; -import com.oracle.svm.hosted.code.DeoptimizationUtils; -import com.oracle.svm.hosted.code.SubstrateCompilationDirectives; -import com.oracle.svm.hosted.meta.HostedMethod; -import com.oracle.svm.hosted.phases.StrengthenStampsPhase; -import com.oracle.svm.hosted.phases.SubstrateGraphBuilderPhase; - -import jdk.vm.ci.meta.DeoptimizationAction; -import jdk.vm.ci.meta.DeoptimizationReason; -import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.ResolvedJavaMethod; - -/** - * Marker for current strategy for supporting RuntimeCompilationFeature. Eventually will be - * supplanted by {@link ParseOnceRuntimeCompilationFeature}. - */ -public class LegacyRuntimeCompilationFeature extends RuntimeCompilationFeature implements Feature { - protected Map runtimeCompiledMethodMap; - protected Set runtimeCompilationCandidates; - - private static final class CallTreeNode extends AbstractCallTreeNode implements RuntimeCompiledMethod, RuntimeCompilationCandidate { - final String sourceReference; - - StructuredGraph graph; - final Set unreachableInvokes; - - CallTreeNode(AnalysisMethod implementationMethod, AnalysisMethod targetMethod, CallTreeNode parent, String sourceReference) { - super(parent, targetMethod, implementationMethod); - this.sourceReference = sourceReference; - this.unreachableInvokes = new HashSet<>(); - } - - @Override - public String getPosition() { - return sourceReference; - } - - @Override - public int getNodeCount() { - return graph == null ? -1 : graph.getNodeCount(); - } - - private StructuredGraph getGraph() { - return graph; - } - - @Override - public AnalysisMethod getMethod() { - return getImplementationMethod(); - } - - @Override - public Collection getInlinedMethods() { - return graph == null ? List.of() : graph.getMethods(); - } - - @Override - public Collection getInvokeTargets() { - if (graph != null) { - return graph.getNodes(MethodCallTargetNode.TYPE).stream().map(CallTargetNode::targetMethod).collect(Collectors.toUnmodifiableList()); - } - return List.of(); - } - - } - - public static class RuntimeGraphBuilderPhase extends SubstrateGraphBuilderPhase { - - RuntimeGraphBuilderPhase(Providers providers, - GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext, WordTypes wordTypes) { - super(providers, graphBuilderConfig, optimisticOpts, initialIntrinsicContext, wordTypes); - } - - @Override - protected BytecodeParser createBytecodeParser(StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method, int entryBCI, IntrinsicContext intrinsicContext) { - return new RuntimeBytecodeParser(this, graph, parent, method, entryBCI, intrinsicContext); - } - } - - public static class RuntimeBytecodeParser extends SubstrateGraphBuilderPhase.SubstrateBytecodeParser { - - RuntimeBytecodeParser(GraphBuilderPhase.Instance graphBuilderInstance, StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method, int entryBCI, - IntrinsicContext intrinsicContext) { - super(graphBuilderInstance, graph, parent, method, entryBCI, intrinsicContext, false); - } - - @Override - protected boolean tryInvocationPlugin(CallTargetNode.InvokeKind invokeKind, ValueNode[] args, ResolvedJavaMethod targetMethod, JavaKind resultType) { - boolean result = super.tryInvocationPlugin(invokeKind, args, targetMethod, resultType); - if (result) { - SubstrateCompilationDirectives.singleton().registerAsDeoptInlininingExclude(targetMethod); - } - return result; - } - - @Override - protected boolean shouldVerifyFrameStates() { - /* - * (GR-46115) Ideally we should verify frame states in methods registered for runtime - * compilations, as well as any other methods that can deoptimize. Because runtime - * compiled methods can pull in almost arbitrary code, this means most frame states - * should be verified. We currently use illegal states as placeholders in many places, - * so this cannot be enabled at the moment. - */ - return false; - } - } - - @Override - public List> getRequiredFeatures() { - return RuntimeCompilationFeature.getRequiredFeaturesHelper(); - } - - @Override - public void afterRegistration(AfterRegistrationAccess access) { - VMError.shouldNotReachHere("GR-48579: dead code that will be deleted later"); - - ImageSingletons.add(RuntimeCompilationFeature.class, this); - } - - @Override - public void duringSetup(DuringSetupAccess c) { - super.duringSetupHelper(c); - } - - @Override - public void beforeAnalysis(BeforeAnalysisAccess c) { - super.beforeAnalysisHelper(c); - - runtimeCompiledMethodMap = new LinkedHashMap<>(); - runtimeCompilationCandidates = new HashSet<>(); - } - - @Override - public void duringAnalysis(DuringAnalysisAccess c) { - FeatureImpl.DuringAnalysisAccessImpl config = (FeatureImpl.DuringAnalysisAccessImpl) c; - - Deque worklist = new ArrayDeque<>(); - worklist.addAll(runtimeCompiledMethodMap.values()); - - while (!worklist.isEmpty()) { - processMethod(worklist.removeFirst(), worklist, config.getBigBang()); - } - - SubstrateMethod[] methodsToCompileArr = new SubstrateMethod[runtimeCompiledMethodMap.size()]; - int idx = 0; - for (CallTreeNode node : runtimeCompiledMethodMap.values()) { - methodsToCompileArr[idx++] = objectReplacer.createMethod(node.getImplementationMethod()); - } - if (GraalSupport.setMethodsToCompile(config, methodsToCompileArr)) { - config.requireAnalysisIteration(); - } - - graphEncoder.finishPrepare(); - AnalysisMetaAccess metaAccess = config.getMetaAccess(); - NodeClass[] nodeClasses = graphEncoder.getNodeClasses(); - for (NodeClass nodeClass : nodeClasses) { - metaAccess.lookupJavaType(nodeClass.getClazz()).registerAsAllocated("All " + NodeClass.class.getName() + " classes are marked as instantiated eagerly."); - } - if (GraalSupport.setGraphEncoding(config, graphEncoder.getEncoding(), graphEncoder.getObjects(), nodeClasses)) { - config.requireAnalysisIteration(); - } - } - - @SuppressWarnings("try") - private void processMethod(CallTreeNode node, Deque worklist, BigBang bb) { - AnalysisMethod method = node.getImplementationMethod(); - assert method.isImplementationInvoked(); - - if (node.graph == null) { - if (method.getAnnotation(Fold.class) != null || method.getAnnotation(Node.NodeIntrinsic.class) != null) { - throw VMError.shouldNotReachHere("Parsing method annotated with @Fold or @NodeIntrinsic: " + method.format("%H.%n(%p)")); - } - if (!method.allowRuntimeCompilation()) { - throw VMError.shouldNotReachHere("Parsing method that is not available for runtime compilation: " + method.format("%H.%n(%p)")); - } - - boolean parse = false; - - DebugContext debug = bb.getDebug(); - StructuredGraph graph = method.buildGraph(debug, method, hostedProviders, GraphProvider.Purpose.PREPARE_RUNTIME_COMPILATION); - if (graph == null) { - if (!method.hasBytecodes()) { - return; - } - parse = true; - graph = new StructuredGraph.Builder(debug.getOptions(), debug, StructuredGraph.AllowAssumptions.YES).method(method) - /* - * Needed for computation of the list of all runtime compilable - * methods in TruffleFeature. - */ - .recordInlinedMethods(true).build(); - } - - try (DebugContext.Scope scope = debug.scope("RuntimeCompile", graph)) { - if (parse) { - RuntimeGraphBuilderPhase builderPhase = new RuntimeGraphBuilderPhase(hostedProviders, graphBuilderConfig, optimisticOpts, null, hostedProviders.getWordTypes()); - builderPhase.apply(graph); - } - - CanonicalizerPhase canonicalizer = CanonicalizerPhase.create(); - canonicalizer.apply(graph, hostedProviders); - if (deoptimizeOnExceptionPredicate != null) { - new DeoptimizeOnExceptionPhase(deoptimizeOnExceptionPredicate).apply(graph); - } - new ConvertDeoptimizeToGuardPhase(canonicalizer).apply(graph, hostedProviders); - - if (DeoptimizationUtils.createGraphInvalidator(graph).get()) { - return; - } - - unwrapImageHeapConstants(graph, hostedProviders.getMetaAccess()); - - graphEncoder.prepare(graph); - node.graph = graph; - assert RuntimeCompilationFeature.verifyNodes(graph); - - } catch (Throwable ex) { - debug.handle(ex); - } - } - - assert node.graph != null; - List callTargets = node.graph.getNodes(MethodCallTargetNode.TYPE).snapshot(); - callTargets.sort(Comparator.comparingInt(t -> t.invoke().bci())); - - for (MethodCallTargetNode targetNode : callTargets) { - AnalysisMethod targetMethod = (AnalysisMethod) targetNode.targetMethod(); - ResolvedJavaMethod callerMethod = targetNode.invoke().stateAfter().getMethod(); - Collection allImplementationMethods; - if (callerMethod instanceof PointsToAnalysisMethod) { - PointsToAnalysisMethod pointToCalledMethod = (PointsToAnalysisMethod) callerMethod; - InvokeTypeFlow invokeFlow = pointToCalledMethod.getTypeFlow().getInvokes().get(targetNode.invoke().bci()); - - if (invokeFlow == null) { - continue; - } - allImplementationMethods = invokeFlow.getOriginalCallees(); - } else { - allImplementationMethods = Arrays.asList(method.getImplementations()); - } - - /* - * Eventually we want to remove all invokes that are unreachable, i.e., have no - * implementation. But the analysis is iterative, and we don't know here if we have - * already reached the fixed point. So we only collect unreachable invokes here, and - * remove them after the analysis has finished. - */ - if (allImplementationMethods.size() == 0) { - node.unreachableInvokes.add(targetNode.invoke()); - } else { - node.unreachableInvokes.remove(targetNode.invoke()); - } - - if (allImplementationMethods.size() > 0) { - /* Sort to make printing order and method discovery order deterministic. */ - List implementationMethods = new ArrayList<>(allImplementationMethods); - implementationMethods.sort(Comparator.comparing(AnalysisMethod::getQualifiedName)); - - String sourceReference = buildSourceReference(targetNode.invoke().stateAfter()); - for (AnalysisMethod implementationMethod : implementationMethods) { - CallTreeNode calleeNode = new CallTreeNode(implementationMethod, targetMethod, node, sourceReference); - boolean added = runtimeCompilationCandidates.add(calleeNode); - if (added) { - calleeNode.linkAsChild(); - } - /* - * Filter out all the implementation methods that have already been processed. - * - * We don't filter out earlier so that different - * combinations are recorded for blocklist checking. - */ - if (runtimeCompiledMethodMap.containsKey(implementationMethod)) { - continue; - } - if (runtimeCompilationCandidatePredicate.allowRuntimeCompilation(implementationMethod)) { - assert !runtimeCompiledMethodMap.containsKey(implementationMethod); - runtimeCompiledMethodMap.put(implementationMethod, calleeNode); - worklist.add(calleeNode); - objectReplacer.createMethod(implementationMethod); - } - - /* - * We must compile all methods which may be called. It may be the case that a - * call target does not reach the compile queue by default, e.g. if it is - * inlined at image generation but not at runtime compilation. - */ - SubstrateCompilationDirectives.singleton().registerForcedCompilation(implementationMethod); - } - } - } - } - - @Override - protected AbstractCallTreeNode getCallTreeNode(RuntimeCompilationCandidate candidate) { - assert candidate != null; - return (CallTreeNode) candidate; - } - - @Override - protected CallTreeNode getCallTreeNode(RuntimeCompiledMethod method) { - assert method != null; - return (CallTreeNode) method; - } - - @Override - protected AbstractCallTreeNode getCallTreeNode(ResolvedJavaMethod method) { - AnalysisMethod aMethod; - if (method instanceof HostedMethod) { - aMethod = ((HostedMethod) method).getWrapped(); - } else { - aMethod = (AnalysisMethod) method; - } - var result = runtimeCompiledMethodMap.get(aMethod); - assert result != null; - return result; - } - - @Override - public Collection getRuntimeCompiledMethods() { - return Collections.unmodifiableCollection(runtimeCompiledMethodMap.values()); - } - - @Override - public Collection getAllRuntimeCompilationCandidates() { - return runtimeCompilationCandidates; - } - - private static String buildSourceReference(FrameState startState) { - StringBuilder sourceReferenceBuilder = new StringBuilder(); - for (FrameState state = startState; state != null; state = state.outerFrameState()) { - if (sourceReferenceBuilder.length() > 0) { - sourceReferenceBuilder.append(" -> "); - } - sourceReferenceBuilder.append(state.getCode().asStackTraceElement(state.bci).toString()); - } - return sourceReferenceBuilder.toString(); - } - - @Override - public void afterAnalysis(AfterAnalysisAccess access) { - super.afterAnalysisHelper(); - } - - @Override - @SuppressWarnings("try") - public void beforeCompilation(BeforeCompilationAccess c) { - super.beforeCompilationHelper(); - - FeatureImpl.CompilationAccessImpl config = (FeatureImpl.CompilationAccessImpl) c; - - /* - * Start fresh with a new GraphEncoder, since we are going to optimize all graphs now that - * the static analysis results are available. - */ - graphEncoder = new GraphEncoder(ConfigurationValues.getTarget().arch); - - StrengthenStampsPhase strengthenStamps = new RuntimeStrengthenStampsPhase(config.getUniverse(), objectReplacer); - CanonicalizerPhase canonicalizer = CanonicalizerPhase.create(); - IterativeConditionalEliminationPhase conditionalElimination = new IterativeConditionalEliminationPhase(canonicalizer, true); - ConvertDeoptimizeToGuardPhase convertDeoptimizeToGuard = new ConvertDeoptimizeToGuardPhase(canonicalizer); - - for (CallTreeNode node : runtimeCompiledMethodMap.values()) { - StructuredGraph graph = node.getGraph(); - if (graph != null) { - DebugContext debug = graph.getDebug(); - try (DebugContext.Scope scope = debug.scope("RuntimeOptimize", graph)) { - removeUnreachableInvokes(node); - strengthenStamps.apply(graph); - canonicalizer.apply(graph, hostedProviders); - - conditionalElimination.apply(graph, hostedProviders); - - /* - * ConvertDeoptimizeToGuardPhase was already executed after parsing, but - * optimizations applied in between can provide new potential. - */ - convertDeoptimizeToGuard.apply(graph, hostedProviders); - - unwrapImageHeapConstants(graph, hostedProviders.getMetaAccess()); - - graphEncoder.prepare(graph); - assert RuntimeCompilationFeature.verifyNodes(graph); - } catch (Throwable ex) { - debug.handle(ex); - } - } - } - - graphEncoder.finishPrepare(); - - for (CallTreeNode node : runtimeCompiledMethodMap.values()) { - CallTreeNode callTreeNode = node; - if (callTreeNode.graph != null) { - DeoptimizationUtils.registerDeoptEntries(callTreeNode.graph, callTreeNode.getLevel() == 0, m -> m); - - long startOffset = graphEncoder.encode(callTreeNode.graph); - objectReplacer.createMethod(callTreeNode.getImplementationMethod()).setEncodedGraphStartOffset(startOffset); - /* We do not need the graph anymore, let the GC do it's work. */ - callTreeNode.graph = null; - } - } - - HeapBreakdownProvider.singleton().setGraphEncodingByteLength(graphEncoder.getEncoding().length); - GraalSupport.setGraphEncoding(config, graphEncoder.getEncoding(), graphEncoder.getObjects(), graphEncoder.getNodeClasses()); - - objectReplacer.setMethodsImplementations(); - - /* All the temporary data structures used during encoding are no longer necessary. */ - graphEncoder = null; - } - - private static void removeUnreachableInvokes(CallTreeNode node) { - for (Invoke invoke : node.unreachableInvokes) { - if (!invoke.asNode().isAlive()) { - continue; - } - - if (invoke.callTarget().invokeKind().hasReceiver()) { - InliningUtil.nonNullReceiver(invoke); - } - FixedGuardNode guard = new FixedGuardNode(LogicConstantNode.forBoolean(true, node.graph), DeoptimizationReason.UnreachedCode, DeoptimizationAction.None, true); - node.graph.addBeforeFixed(invoke.asFixedNode(), node.graph.add(guard)); - } - } - - @Override - public void afterCompilation(AfterCompilationAccess a) { - super.afterCompilationHelper(a); - } - - @Override - public void beforeHeapLayout(BeforeHeapLayoutAccess a) { - super.beforeHeapLayoutHelper(a); - } - - @Override - public void afterHeapLayout(AfterHeapLayoutAccess a) { - super.afterHeapLayoutHelper(a); - } - - @Override - public SubstrateMethod prepareMethodForRuntimeCompilation(ResolvedJavaMethod method, FeatureImpl.BeforeAnalysisAccessImpl config) { - AnalysisMethod aMethod = (AnalysisMethod) method; - SubstrateMethod sMethod = objectReplacer.createMethod(aMethod); - - if (!runtimeCompiledMethodMap.containsKey(aMethod)) { - runtimeCompiledMethodMap.put(aMethod, new CallTreeNode(aMethod, aMethod, null, "")); - config.registerAsRoot(aMethod, true, "Runtime compilation, registered in " + LegacyRuntimeCompilationFeature.class); - } - - return sMethod; - } - - @Override - protected void requireFrameInformationForMethodHelper(AnalysisMethod aMethod, FeatureImpl.BeforeAnalysisAccessImpl config, boolean registerAsRoot) { - SubstrateCompilationDirectives.singleton().registerFrameInformationRequired(aMethod, aMethod); - if (registerAsRoot) { - config.registerAsRoot(aMethod, true, "Frame information required, registered in " + LegacyRuntimeCompilationFeature.class); - } - } - - @Override - public void initializeAnalysisProviders(BigBang bb, Function generator) { - /* - * No action is needed for the legacy implementation. - */ - } - - @Override - public void registerAllowInliningPredicate(AllowInliningPredicate predicate) { - /* - * No action is needed for the legacy implementation. - */ - } - -} diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/ParseOnceRuntimeCompilationFeature.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/ParseOnceRuntimeCompilationFeature.java index 028ea5647f85..3f9569a6f375 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/ParseOnceRuntimeCompilationFeature.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/ParseOnceRuntimeCompilationFeature.java @@ -99,7 +99,6 @@ import com.oracle.svm.hosted.phases.InlineBeforeAnalysisPolicyUtils; import com.oracle.svm.hosted.phases.InlineBeforeAnalysisPolicyUtils.AccumulativeInlineScope; import com.oracle.svm.hosted.phases.InlineBeforeAnalysisPolicyUtils.AlwaysInlineScope; -import com.oracle.svm.hosted.phases.StrengthenStampsPhase; import jdk.graal.compiler.core.common.PermanentBailoutException; import jdk.graal.compiler.core.common.spi.ConstantFieldProvider; @@ -710,12 +709,7 @@ public void onCompileQueueCreation(BigBang bb, HostedUniverse hUniverse, Compile protected PhaseSuite getAfterParseSuite() { PhaseSuite suite = super.getAfterParseSuite(); if (Options.RemoveUnneededDeoptSupport.getValue()) { - var iterator = suite.findPhase(StrengthenStampsPhase.class); - if (iterator == null) { - suite.prependPhase(new RemoveUnneededDeoptSupport()); - } else { - iterator.add(new RemoveUnneededDeoptSupport()); - } + suite.prependPhase(new RemoveUnneededDeoptSupport()); } return suite; diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/RuntimeCompilationFeature.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/RuntimeCompilationFeature.java index 1453aad39e1b..56ce06ee608b 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/RuntimeCompilationFeature.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/RuntimeCompilationFeature.java @@ -40,26 +40,6 @@ import java.util.function.Predicate; import java.util.stream.Collectors; -import jdk.graal.compiler.api.runtime.GraalRuntime; -import jdk.graal.compiler.core.common.spi.ConstantFieldProvider; -import jdk.graal.compiler.core.common.spi.MetaAccessExtensionProvider; -import jdk.graal.compiler.debug.DebugContext; -import jdk.graal.compiler.graph.Node; -import jdk.graal.compiler.graph.NodeClass; -import jdk.graal.compiler.lir.phases.LIRSuites; -import jdk.graal.compiler.nodes.ConstantNode; -import jdk.graal.compiler.nodes.GraphEncoder; -import jdk.graal.compiler.nodes.StructuredGraph; -import jdk.graal.compiler.nodes.extended.BytecodeExceptionNode; -import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; -import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.BytecodeExceptionMode; -import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext; -import jdk.graal.compiler.options.Option; -import jdk.graal.compiler.options.OptionStability; -import jdk.graal.compiler.phases.OptimisticOptimizations; -import jdk.graal.compiler.phases.tiers.Suites; -import jdk.graal.compiler.phases.util.Providers; -import jdk.graal.compiler.word.WordTypes; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.hosted.Feature; import org.graalvm.nativeimage.hosted.Feature.AfterCompilationAccess; @@ -71,7 +51,6 @@ import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.heap.ImageHeapConstant; -import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.AnalysisType; @@ -113,17 +92,33 @@ import com.oracle.svm.hosted.ProgressReporter; import com.oracle.svm.hosted.analysis.Inflation; import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport; -import com.oracle.svm.hosted.meta.HostedField; import com.oracle.svm.hosted.meta.HostedMetaAccess; -import com.oracle.svm.hosted.meta.HostedType; import com.oracle.svm.hosted.meta.HostedUniverse; -import com.oracle.svm.hosted.phases.StrengthenStampsPhase; import com.oracle.svm.hosted.phases.SubstrateClassInitializationPlugin; +import jdk.graal.compiler.api.runtime.GraalRuntime; +import jdk.graal.compiler.core.common.spi.ConstantFieldProvider; +import jdk.graal.compiler.core.common.spi.MetaAccessExtensionProvider; +import jdk.graal.compiler.debug.DebugContext; +import jdk.graal.compiler.graph.Node; +import jdk.graal.compiler.graph.NodeClass; +import jdk.graal.compiler.lir.phases.LIRSuites; +import jdk.graal.compiler.nodes.ConstantNode; +import jdk.graal.compiler.nodes.GraphEncoder; +import jdk.graal.compiler.nodes.StructuredGraph; +import jdk.graal.compiler.nodes.extended.BytecodeExceptionNode; +import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; +import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.BytecodeExceptionMode; +import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext; +import jdk.graal.compiler.options.Option; +import jdk.graal.compiler.options.OptionStability; +import jdk.graal.compiler.phases.OptimisticOptimizations; +import jdk.graal.compiler.phases.tiers.Suites; +import jdk.graal.compiler.phases.util.Providers; +import jdk.graal.compiler.word.WordTypes; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.MetaAccessProvider; -import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; @@ -691,56 +686,6 @@ public static void unwrapImageHeapConstants(StructuredGraph graph, MetaAccessPro } } -/** - * The graphs for runtime compilation use the analysis universe, but we want to incorporate static - * analysis results from the hosted universe. So we temporarily convert metadata objects to the - * hosted universe, and the final type back to the analysis universe. - */ -class RuntimeStrengthenStampsPhase extends StrengthenStampsPhase { - - private final HostedUniverse hUniverse; - private final GraalGraphObjectReplacer objectReplacer; - - RuntimeStrengthenStampsPhase(HostedUniverse hUniverse, GraalGraphObjectReplacer objectReplacer) { - this.hUniverse = hUniverse; - this.objectReplacer = objectReplacer; - } - - @Override - protected HostedType toHosted(ResolvedJavaType type) { - if (type == null) { - return null; - } - assert type instanceof AnalysisType; - return hUniverse.lookup(type); - } - - @Override - protected HostedField toHosted(ResolvedJavaField field) { - if (field == null) { - return null; - } - assert field instanceof AnalysisField; - return hUniverse.lookup(field); - } - - @Override - protected ResolvedJavaType toTarget(ResolvedJavaType type) { - AnalysisType result = ((HostedType) type).getWrapped(); - - if (!objectReplacer.typeCreated(result)) { - /* - * The SubstrateType has not been created during analysis. We cannot crate new types at - * this point, because it can make objects reachable that the static analysis has not - * seen. - */ - return null; - } - - return result; - } -} - /** * Same behavior as {@link SubstrateMetaAccessExtensionProvider}, but operating on * {@link AnalysisType} instead of {@link SharedType} since parsing of graphs for runtime diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ExceptionSynthesizer.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ExceptionSynthesizer.java index 898e5b42028e..e26470b3b3ce 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ExceptionSynthesizer.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ExceptionSynthesizer.java @@ -30,6 +30,12 @@ import java.util.HashMap; import java.util.Map; +import com.oracle.svm.core.graal.nodes.LoweredDeadEndNode; +import com.oracle.svm.core.nodes.SubstrateMethodCallTargetNode; +import com.oracle.svm.core.snippets.ImplicitExceptions; +import com.oracle.svm.core.util.VMError; +import com.oracle.svm.util.ClassUtil; + import jdk.graal.compiler.core.common.type.StampFactory; import jdk.graal.compiler.core.common.type.StampPair; import jdk.graal.compiler.nodes.CallTargetNode.InvokeKind; @@ -38,13 +44,6 @@ import jdk.graal.compiler.nodes.ValueNode; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext; import jdk.graal.compiler.nodes.java.MethodCallTargetNode; - -import com.oracle.svm.core.graal.nodes.LoweredDeadEndNode; -import com.oracle.svm.core.nodes.SubstrateMethodCallTargetNode; -import com.oracle.svm.core.snippets.ImplicitExceptions; -import com.oracle.svm.core.util.VMError; -import com.oracle.svm.util.ClassUtil; - import jdk.vm.ci.meta.ResolvedJavaMethod; public final class ExceptionSynthesizer { @@ -122,7 +121,7 @@ public static void throwException(GraphBuilderContext b, Method throwExceptionMe assert exceptionMethod.isStatic(); StampPair returnStamp = StampFactory.forDeclaredType(b.getGraph().getAssumptions(), exceptionMethod.getSignature().getReturnType(null), false); - MethodCallTargetNode callTarget = b.add(new SubstrateMethodCallTargetNode(InvokeKind.Static, exceptionMethod, new ValueNode[]{messageNode}, returnStamp, null, null, null)); + MethodCallTargetNode callTarget = b.add(new SubstrateMethodCallTargetNode(InvokeKind.Static, exceptionMethod, new ValueNode[]{messageNode}, returnStamp)); InvokeWithExceptionNode invoke = b.append(new InvokeWithExceptionNode(callTarget, null, b.bci())); b.setStateAfterSkipVerification(invoke); /* The invoked method always throws an exception, i.e., never returns. */ diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java index 769a01f4c27a..3d951fc34d69 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java @@ -31,12 +31,6 @@ import java.util.Optional; import java.util.Set; -import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; -import jdk.graal.compiler.core.common.CompressEncoding; -import jdk.graal.compiler.core.common.spi.MetaAccessExtensionProvider; -import jdk.graal.compiler.debug.DebugContext; -import jdk.graal.compiler.nodes.StructuredGraph; -import jdk.graal.compiler.options.OptionValues; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; @@ -48,9 +42,7 @@ import com.oracle.graal.pointsto.meta.AnalysisMetaAccessExtensionProvider; import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.meta.PointsToAnalysisMethod; -import com.oracle.graal.pointsto.results.AbstractAnalysisResultsBuilder; -import com.oracle.graal.pointsto.results.DefaultResultsBuilder; -import com.oracle.graal.pointsto.results.StaticAnalysisResultsBuilder; +import com.oracle.graal.pointsto.results.StrengthenGraphs; import com.oracle.objectfile.ObjectFile; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.SubstrateTargetDescription; @@ -76,6 +68,12 @@ import com.oracle.svm.hosted.meta.HostedUniverse; import com.oracle.svm.hosted.substitute.UnsafeAutomaticSubstitutionProcessor; +import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; +import jdk.graal.compiler.core.common.CompressEncoding; +import jdk.graal.compiler.core.common.spi.MetaAccessExtensionProvider; +import jdk.graal.compiler.debug.DebugContext; +import jdk.graal.compiler.nodes.StructuredGraph; +import jdk.graal.compiler.options.OptionValues; import jdk.internal.ValueBased; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.MetaAccessProvider; @@ -217,17 +215,8 @@ public void findAllFieldsForLayout(HostedUniverse universe, @SuppressWarnings("u } } - public AbstractAnalysisResultsBuilder createStaticAnalysisResultsBuilder(Inflation bb, HostedUniverse universe) { - if (bb instanceof PointsToAnalysis) { - PointsToAnalysis pta = (PointsToAnalysis) bb; - if (SubstrateOptions.parseOnce()) { - return new SubstrateStrengthenGraphs(pta, universe); - } else { - return new StaticAnalysisResultsBuilder(pta, universe); - } - } else { - return new DefaultResultsBuilder(bb, universe); - } + public StrengthenGraphs createStrengthenGraphs(Inflation bb, HostedUniverse universe) { + return new SubstrateStrengthenGraphs(bb, universe); } public void collectMonitorFieldInfo(BigBang bb, HostedUniverse hUniverse, Set immutableTypes) { 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 27ec6d7a79ea..371f33b84c04 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 @@ -590,7 +590,7 @@ protected void doRun(Map entryPoints, JavaMainSupport j BeforeUniverseBuildingAccessImpl beforeUniverseBuildingConfig = new BeforeUniverseBuildingAccessImpl(featureHandler, loader, debug, hMetaAccess); featureHandler.forEachFeature(feature -> feature.beforeUniverseBuilding(beforeUniverseBuildingConfig)); - new UniverseBuilder(aUniverse, bb.getMetaAccess(), hUniverse, hMetaAccess, HostedConfiguration.instance().createStaticAnalysisResultsBuilder(bb, hUniverse), + new UniverseBuilder(aUniverse, bb.getMetaAccess(), hUniverse, hMetaAccess, HostedConfiguration.instance().createStrengthenGraphs(bb, hUniverse), bb.getUnsupportedFeatures()).build(debug); BuildPhaseProvider.markHostedUniverseBuilt(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SubstrateStrengthenGraphs.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SubstrateStrengthenGraphs.java index 39d166d7126d..8e0e1d571573 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SubstrateStrengthenGraphs.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SubstrateStrengthenGraphs.java @@ -26,17 +26,6 @@ import java.util.function.Supplier; -import jdk.graal.compiler.graph.Node; -import jdk.graal.compiler.nodes.ConstantNode; -import jdk.graal.compiler.nodes.DeoptimizeNode; -import jdk.graal.compiler.nodes.FixedNode; -import jdk.graal.compiler.nodes.Invoke; -import jdk.graal.compiler.nodes.StructuredGraph; -import jdk.graal.compiler.nodes.extended.ForeignCallNode; -import jdk.graal.compiler.nodes.spi.CoreProviders; -import jdk.graal.compiler.nodes.spi.SimplifierTool; - -import com.oracle.graal.pointsto.PointsToAnalysis; import com.oracle.graal.pointsto.infrastructure.Universe; import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.results.StrengthenGraphs; @@ -48,9 +37,19 @@ import com.oracle.svm.core.snippets.SnippetRuntime; import com.oracle.svm.core.util.HostedStringDeduplication; import com.oracle.svm.core.util.VMError; +import com.oracle.svm.hosted.analysis.Inflation; import com.oracle.svm.hosted.code.SubstrateCompilationDirectives; import com.oracle.svm.hosted.meta.HostedType; +import jdk.graal.compiler.graph.Node; +import jdk.graal.compiler.nodes.ConstantNode; +import jdk.graal.compiler.nodes.DeoptimizeNode; +import jdk.graal.compiler.nodes.FixedNode; +import jdk.graal.compiler.nodes.Invoke; +import jdk.graal.compiler.nodes.StructuredGraph; +import jdk.graal.compiler.nodes.extended.ForeignCallNode; +import jdk.graal.compiler.nodes.spi.CoreProviders; +import jdk.graal.compiler.nodes.spi.SimplifierTool; import jdk.vm.ci.meta.DeoptimizationAction; import jdk.vm.ci.meta.DeoptimizationReason; import jdk.vm.ci.meta.JavaMethodProfile; @@ -58,7 +57,7 @@ public class SubstrateStrengthenGraphs extends StrengthenGraphs { - public SubstrateStrengthenGraphs(PointsToAnalysis bb, Universe converter) { + public SubstrateStrengthenGraphs(Inflation bb, Universe converter) { super(bb, converter); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImagePointsToAnalysis.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImagePointsToAnalysis.java index 063263b7ef68..f984e4946e65 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImagePointsToAnalysis.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImagePointsToAnalysis.java @@ -39,7 +39,6 @@ import com.oracle.graal.pointsto.meta.AnalysisUniverse; import com.oracle.graal.pointsto.meta.PointsToAnalysisMethod; import com.oracle.graal.pointsto.util.TimerCollection; -import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.hosted.HostedConfiguration; import com.oracle.svm.hosted.SVMHost; import com.oracle.svm.hosted.code.IncompatibleClassChangeFallbackMethod; @@ -67,8 +66,7 @@ public NativeImagePointsToAnalysis(OptionValues options, AnalysisUniverse univer ConstantReflectionProvider constantReflectionProvider, WordTypes wordTypes, AnnotationSubstitutionProcessor annotationSubstitutionProcessor, UnsupportedFeatures unsupportedFeatures, DebugContext debugContext, TimerCollection timerCollection) { - super(options, universe, universe.hostVM(), metaAccess, snippetReflectionProvider, constantReflectionProvider, wordTypes, unsupportedFeatures, debugContext, timerCollection, - SubstrateOptions.parseOnce()); + super(options, universe, universe.hostVM(), metaAccess, snippetReflectionProvider, constantReflectionProvider, wordTypes, unsupportedFeatures, debugContext, timerCollection); this.annotationSubstitutionProcessor = annotationSubstitutionProcessor; dynamicHubInitializer = new DynamicHubInitializer(this); 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 7d013ac2f524..788139e03492 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 @@ -31,7 +31,6 @@ import com.oracle.graal.pointsto.util.TimerCollection; import com.oracle.graal.reachability.ReachabilityAnalysisEngine; import com.oracle.graal.reachability.ReachabilityMethodProcessingHandler; -import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.hosted.SVMHost; import com.oracle.svm.hosted.substitute.AnnotationSubstitutionProcessor; @@ -45,7 +44,6 @@ public class NativeImageReachabilityAnalysisEngine extends ReachabilityAnalysisE private final AnnotationSubstitutionProcessor annotationSubstitutionProcessor; private final DynamicHubInitializer dynamicHubInitializer; - private final boolean strengthenGraalGraphs; private final CustomTypeFieldHandler unknownFieldHandler; @SuppressWarnings("this-escape") @@ -55,7 +53,6 @@ public NativeImageReachabilityAnalysisEngine(OptionValues options, AnalysisUnive super(options, universe, universe.hostVM(), metaAccess, snippetReflectionProvider, constantReflectionProvider, wordTypes, new SubstrateUnsupportedFeatures(), debugContext, timerCollection, reachabilityMethodProcessingHandler); this.annotationSubstitutionProcessor = annotationSubstitutionProcessor; - this.strengthenGraalGraphs = SubstrateOptions.parseOnce(); this.dynamicHubInitializer = new DynamicHubInitializer(this); this.unknownFieldHandler = new CustomTypeFieldHandler(this, metaAccess) { @Override @@ -69,11 +66,6 @@ protected void injectFieldTypes(AnalysisField aField, AnalysisType... declaredTy }; } - @Override - public boolean strengthenGraalGraphs() { - return strengthenGraalGraphs; - } - @Override public AnnotationSubstitutionProcessor getAnnotationSubstitutionProcessor() { return annotationSubstitutionProcessor; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java index c4b40ef74f42..f37a653b7585 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java @@ -39,6 +39,47 @@ import java.util.concurrent.ConcurrentMap; import org.graalvm.collections.EconomicMap; +import org.graalvm.nativeimage.ImageSingletons; + +import com.oracle.graal.pointsto.api.PointstoOptions; +import com.oracle.graal.pointsto.flow.AnalysisParsedGraph; +import com.oracle.graal.pointsto.infrastructure.GraphProvider.Purpose; +import com.oracle.graal.pointsto.meta.HostedProviders; +import com.oracle.graal.pointsto.phases.SubstrateIntrinsicGraphBuilder; +import com.oracle.graal.pointsto.util.CompletionExecutor; +import com.oracle.graal.pointsto.util.CompletionExecutor.DebugContextRunnable; +import com.oracle.svm.common.meta.MultiMethod; +import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.SubstrateOptions.OptimizationLevel; +import com.oracle.svm.core.Uninterruptible; +import com.oracle.svm.core.deopt.DeoptTest; +import com.oracle.svm.core.deopt.Specialize; +import com.oracle.svm.core.graal.code.SubstrateBackend; +import com.oracle.svm.core.graal.meta.RuntimeConfiguration; +import com.oracle.svm.core.graal.meta.SubstrateForeignCallLinkage; +import com.oracle.svm.core.graal.meta.SubstrateForeignCallsProvider; +import com.oracle.svm.core.graal.nodes.DeoptEntryNode; +import com.oracle.svm.core.graal.phases.DeadStoreRemovalPhase; +import com.oracle.svm.core.graal.phases.OptimizeExceptionPathsPhase; +import com.oracle.svm.core.heap.RestrictHeapAccess; +import com.oracle.svm.core.heap.RestrictHeapAccessCallees; +import com.oracle.svm.core.meta.MethodPointer; +import com.oracle.svm.core.meta.SubstrateMethodPointerConstant; +import com.oracle.svm.core.util.InterruptImageBuilding; +import com.oracle.svm.core.util.VMError; +import com.oracle.svm.hosted.FeatureHandler; +import com.oracle.svm.hosted.NativeImageGenerator; +import com.oracle.svm.hosted.NativeImageOptions; +import com.oracle.svm.hosted.ProgressReporter; +import com.oracle.svm.hosted.diagnostic.HostedHeapDumpFeature; +import com.oracle.svm.hosted.meta.HostedMethod; +import com.oracle.svm.hosted.meta.HostedUniverse; +import com.oracle.svm.hosted.phases.HostedGraphBuilderPhase; +import com.oracle.svm.hosted.phases.ImageBuildStatisticsCounterPhase; +import com.oracle.svm.hosted.phases.ImplicitAssertionsPhase; +import com.oracle.svm.hosted.substitute.DeletedMethod; +import com.oracle.svm.util.ImageBuildStatistics; + import jdk.graal.compiler.api.replacements.Fold; import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; import jdk.graal.compiler.asm.Assembler; @@ -97,49 +138,6 @@ import jdk.graal.compiler.phases.util.Providers; import jdk.graal.compiler.replacements.PEGraphDecoder; import jdk.graal.compiler.replacements.nodes.MacroInvokable; -import org.graalvm.nativeimage.ImageSingletons; - -import com.oracle.graal.pointsto.api.PointstoOptions; -import com.oracle.graal.pointsto.flow.AnalysisParsedGraph; -import com.oracle.graal.pointsto.infrastructure.GraphProvider.Purpose; -import com.oracle.graal.pointsto.meta.HostedProviders; -import com.oracle.graal.pointsto.phases.SubstrateIntrinsicGraphBuilder; -import com.oracle.graal.pointsto.util.CompletionExecutor; -import com.oracle.graal.pointsto.util.CompletionExecutor.DebugContextRunnable; -import com.oracle.svm.common.meta.MultiMethod; -import com.oracle.svm.core.SubstrateOptions; -import com.oracle.svm.core.SubstrateOptions.OptimizationLevel; -import com.oracle.svm.core.Uninterruptible; -import com.oracle.svm.core.deopt.DeoptTest; -import com.oracle.svm.core.deopt.Specialize; -import com.oracle.svm.core.graal.code.SubstrateBackend; -import com.oracle.svm.core.graal.meta.RuntimeConfiguration; -import com.oracle.svm.core.graal.meta.SubstrateForeignCallLinkage; -import com.oracle.svm.core.graal.meta.SubstrateForeignCallsProvider; -import com.oracle.svm.core.graal.nodes.DeoptEntryNode; -import com.oracle.svm.core.graal.phases.DeadStoreRemovalPhase; -import com.oracle.svm.core.graal.phases.OptimizeExceptionPathsPhase; -import com.oracle.svm.core.heap.RestrictHeapAccess; -import com.oracle.svm.core.heap.RestrictHeapAccessCallees; -import com.oracle.svm.core.meta.MethodPointer; -import com.oracle.svm.core.meta.SubstrateMethodPointerConstant; -import com.oracle.svm.core.util.InterruptImageBuilding; -import com.oracle.svm.core.util.VMError; -import com.oracle.svm.hosted.FeatureHandler; -import com.oracle.svm.hosted.NativeImageGenerator; -import com.oracle.svm.hosted.NativeImageOptions; -import com.oracle.svm.hosted.ProgressReporter; -import com.oracle.svm.hosted.diagnostic.HostedHeapDumpFeature; -import com.oracle.svm.hosted.meta.HostedMethod; -import com.oracle.svm.hosted.meta.HostedUniverse; -import com.oracle.svm.hosted.phases.DevirtualizeCallsPhase; -import com.oracle.svm.hosted.phases.HostedGraphBuilderPhase; -import com.oracle.svm.hosted.phases.ImageBuildStatisticsCounterPhase; -import com.oracle.svm.hosted.phases.ImplicitAssertionsPhase; -import com.oracle.svm.hosted.phases.StrengthenStampsPhase; -import com.oracle.svm.hosted.substitute.DeletedMethod; -import com.oracle.svm.util.ImageBuildStatistics; - import jdk.vm.ci.code.Register; import jdk.vm.ci.code.site.Call; import jdk.vm.ci.code.site.ConstantReference; @@ -497,11 +495,7 @@ protected PhaseSuite afterParseCanonicalization() { PhaseSuite phaseSuite = new PhaseSuite<>(); phaseSuite.appendPhase(new ImplicitAssertionsPhase()); phaseSuite.appendPhase(new DeadStoreRemovalPhase()); - phaseSuite.appendPhase(new DevirtualizeCallsPhase()); phaseSuite.appendPhase(CanonicalizerPhase.create()); - if (!PointstoOptions.UseExperimentalReachabilityAnalysis.getValue(universe.hostVM().options())) { - phaseSuite.appendPhase(new StrengthenStampsPhase()); - } phaseSuite.appendPhase(CanonicalizerPhase.create()); phaseSuite.appendPhase(new OptimizeExceptionPathsPhase()); if (ImageBuildStatistics.Options.CollectImageBuildStatistics.getValue(universe.hostVM().options())) { @@ -1303,7 +1297,7 @@ private CompilationResult defaultCompileFunction(DebugContext debug, HostedMetho CompilationResult result = backend.newCompilationResult(compilationIdentifier, method.getQualifiedName()); try (Indent indent = debug.logAndIndent("compile %s", method)) { - GraalCompiler.compileGraph(graph, method, backend.getProviders(), backend, null, getOptimisticOpts(), method.getProfilingInfo(), suites, lirSuites, result, + GraalCompiler.compileGraph(graph, method, backend.getProviders(), backend, null, getOptimisticOpts(), null, suites, lirSuites, result, new HostedCompilationResultBuilderFactory(), false); } graph.getOptimizationLog().emit((m) -> m.format(StableMethodNameFormatter.METHOD_FORMAT)); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/dashboard/PointsToJsonObject.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/dashboard/PointsToJsonObject.java index 64c61424a9d2..9e2c8358d5d6 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/dashboard/PointsToJsonObject.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/dashboard/PointsToJsonObject.java @@ -36,8 +36,6 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import jdk.graal.compiler.graphio.GraphOutput; -import jdk.graal.compiler.graphio.GraphStructure; import org.graalvm.nativeimage.hosted.Feature.OnAnalysisExitAccess; import com.oracle.graal.pointsto.BigBang; @@ -58,7 +56,6 @@ import com.oracle.graal.pointsto.flow.FormalParamTypeFlow; import com.oracle.graal.pointsto.flow.FormalReceiverTypeFlow; import com.oracle.graal.pointsto.flow.FormalReturnTypeFlow; -import com.oracle.graal.pointsto.flow.InstanceOfTypeFlow; import com.oracle.graal.pointsto.flow.InvokeTypeFlow; import com.oracle.graal.pointsto.flow.LoadFieldTypeFlow; import com.oracle.graal.pointsto.flow.MergeTypeFlow; @@ -85,6 +82,8 @@ import com.oracle.svm.hosted.dashboard.ToJson.JsonString; import com.oracle.svm.hosted.dashboard.ToJson.JsonValue; +import jdk.graal.compiler.graphio.GraphOutput; +import jdk.graal.compiler.graphio.GraphStructure; import jdk.vm.ci.code.BytecodePosition; /** @@ -421,7 +420,6 @@ public static class DashboardTypeFlowNames { names.put(CloneTypeFlow.class, "clone"); names.put(FilterTypeFlow.class, "filter"); names.put(FormalReceiverTypeFlow.class, "formalReceiver"); - names.put(InstanceOfTypeFlow.class, "instanceOf"); names.put(OffsetLoadTypeFlow.LoadIndexedTypeFlow.class, "loadIndexed"); names.put(MergeTypeFlow.class, "merge"); names.put(MonitorEnterTypeFlow.class, "monitorEnter"); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedField.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedField.java index 2737b32b2a43..f397d729b7a2 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedField.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedField.java @@ -33,7 +33,6 @@ import com.oracle.svm.hosted.ameta.ReadableJavaField; import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.JavaTypeProfile; /** * Store the compile-time information for a field in the Substrate VM, such as the field offset. @@ -47,15 +46,12 @@ public class HostedField extends HostedElement implements OriginalFieldProvider, protected int location; - private final JavaTypeProfile typeProfile; - static final int LOC_UNMATERIALIZED_STATIC_CONSTANT = -10; - public HostedField(AnalysisField wrapped, HostedType holder, HostedType type, JavaTypeProfile typeProfile) { + public HostedField(AnalysisField wrapped, HostedType holder, HostedType type) { this.wrapped = wrapped; this.holder = holder; this.type = type; - this.typeProfile = typeProfile; this.location = LOC_UNINITIALIZED; } @@ -64,10 +60,6 @@ public AnalysisField getWrapped() { return wrapped; } - public JavaTypeProfile getFieldTypeProfile() { - return typeProfile; - } - protected void setLocation(int location) { assert this.location == LOC_UNINITIALIZED; assert location >= 0; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java index 2aa9216c2718..130d135f3f11 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java @@ -39,11 +39,6 @@ import java.util.function.Function; import org.graalvm.collections.Pair; -import jdk.graal.compiler.api.replacements.Snippet; -import jdk.graal.compiler.debug.DebugContext; -import jdk.graal.compiler.debug.JavaMethodContext; -import jdk.graal.compiler.java.StableMethodNameFormatter; -import jdk.graal.compiler.nodes.StructuredGraph; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @@ -54,7 +49,6 @@ import com.oracle.graal.pointsto.infrastructure.WrappedJavaMethod; import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.HostedProviders; -import com.oracle.graal.pointsto.results.StaticAnalysisResults; import com.oracle.svm.common.meta.MultiMethod; import com.oracle.svm.core.AlwaysInline; import com.oracle.svm.core.SubstrateUtil; @@ -76,6 +70,11 @@ import com.oracle.svm.hosted.code.CompilationInfo; import com.oracle.svm.hosted.code.SubstrateCompilationDirectives; +import jdk.graal.compiler.api.replacements.Snippet; +import jdk.graal.compiler.debug.DebugContext; +import jdk.graal.compiler.debug.JavaMethodContext; +import jdk.graal.compiler.java.StableMethodNameFormatter; +import jdk.graal.compiler.nodes.StructuredGraph; import jdk.internal.vm.annotation.ForceInline; import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.ConstantPool; @@ -85,6 +84,7 @@ import jdk.vm.ci.meta.LineNumberTable; import jdk.vm.ci.meta.Local; import jdk.vm.ci.meta.LocalVariableTable; +import jdk.vm.ci.meta.ProfilingInfo; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; import jdk.vm.ci.meta.Signature; @@ -100,7 +100,6 @@ public final class HostedMethod extends HostedElement implements SharedMethod, W private final Signature signature; private final ConstantPool constantPool; private final ExceptionHandler[] handlers; - StaticAnalysisResults staticAnalysisResults; int vtableIndex = -1; /** @@ -256,7 +255,6 @@ public String getUniqueShortName() { */ public void clear() { compilationInfo.clear(); - staticAnalysisResults = null; } @Override @@ -456,13 +454,8 @@ public StackTraceElement asStackTraceElement(int bci) { } @Override - public StaticAnalysisResults getProfilingInfo() { - return staticAnalysisResults; - } - - @Override - public StaticAnalysisResults getProfilingInfo(boolean includeNormal, boolean includeOSR) { - return staticAnalysisResults; + public ProfilingInfo getProfilingInfo(boolean includeNormal, boolean includeOSR) { + return null; } @Override @@ -576,7 +569,6 @@ public HostedMethod getOrCreateMultiMethod(MultiMethodKey key) { return (HostedMethod) multiMethodMap.computeIfAbsent(key, (k) -> { HostedMethod newMultiMethod = create0(wrapped, holder, signature, constantPool, handlers, k, multiMethodMap, localVariableTable); - newMultiMethod.staticAnalysisResults = staticAnalysisResults; newMultiMethod.implementations = implementations; newMultiMethod.vtableIndex = vtableIndex; return newMultiMethod; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java index 963fe2772af8..f4e596e8e248 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java @@ -45,9 +45,6 @@ import java.util.stream.Collectors; import org.graalvm.collections.Pair; -import jdk.graal.compiler.core.common.NumUtil; -import jdk.graal.compiler.debug.DebugContext; -import jdk.graal.compiler.debug.Indent; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.c.function.CEntryPointLiteral; import org.graalvm.nativeimage.c.function.CFunction; @@ -62,7 +59,7 @@ import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.meta.AnalysisUniverse; -import com.oracle.graal.pointsto.results.AbstractAnalysisResultsBuilder; +import com.oracle.graal.pointsto.results.StrengthenGraphs; import com.oracle.svm.common.meta.MultiMethod; import com.oracle.svm.core.FunctionPointerHolder; import com.oracle.svm.core.InvalidMethodPointerHandler; @@ -103,6 +100,9 @@ import com.oracle.svm.hosted.substitute.DeletedMethod; import com.oracle.svm.util.ReflectionUtil; +import jdk.graal.compiler.core.common.NumUtil; +import jdk.graal.compiler.debug.DebugContext; +import jdk.graal.compiler.debug.Indent; import jdk.internal.vm.annotation.Contended; import jdk.vm.ci.meta.ConstantPool; import jdk.vm.ci.meta.ExceptionHandler; @@ -117,17 +117,17 @@ public class UniverseBuilder { private final AnalysisMetaAccess aMetaAccess; private final HostedUniverse hUniverse; private final HostedMetaAccess hMetaAccess; - private AbstractAnalysisResultsBuilder staticAnalysisResultsBuilder; + private StrengthenGraphs strengthenGraphs; private final UnsupportedFeatures unsupportedFeatures; private TypeCheckBuilder typeCheckBuilder; public UniverseBuilder(AnalysisUniverse aUniverse, AnalysisMetaAccess aMetaAccess, HostedUniverse hUniverse, HostedMetaAccess hMetaAccess, - AbstractAnalysisResultsBuilder staticAnalysisResultsBuilder, UnsupportedFeatures unsupportedFeatures) { + StrengthenGraphs strengthenGraphs, UnsupportedFeatures unsupportedFeatures) { this.aUniverse = aUniverse; this.aMetaAccess = aMetaAccess; this.hUniverse = hUniverse; this.hMetaAccess = hMetaAccess; - this.staticAnalysisResultsBuilder = staticAnalysisResultsBuilder; + this.strengthenGraphs = strengthenGraphs; this.unsupportedFeatures = unsupportedFeatures; } @@ -183,7 +183,7 @@ public void build(DebugContext debug) { typeCheckBuilder.calculateIDs(); collectDeclaredMethods(); - collectMonitorFieldInfo(staticAnalysisResultsBuilder.getBigBang()); + collectMonitorFieldInfo(aUniverse.getBigbang()); ForkJoinTask profilingInformationBuildTask = ForkJoinTask.adapt(this::buildProfilingInformation).fork(); @@ -363,7 +363,7 @@ private void makeField(AnalysisField aField) { */ HostedType type = lookupType(aField.getType()); - HostedField hField = new HostedField(aField, holder, type, staticAnalysisResultsBuilder.makeTypeProfile(aField)); + HostedField hField = new HostedField(aField, holder, type); assert !hUniverse.fields.containsKey(aField); hUniverse.fields.put(aField, hField); } @@ -375,11 +375,11 @@ private void buildProfilingInformation() { assert method.isOriginalMethod(); for (MultiMethod multiMethod : method.getAllMultiMethods()) { HostedMethod hMethod = (HostedMethod) multiMethod; - hMethod.staticAnalysisResults = staticAnalysisResultsBuilder.makeOrApplyResults(hMethod.getWrapped()); + strengthenGraphs.applyResults(hMethod.getWrapped()); } }); - staticAnalysisResultsBuilder = null; + strengthenGraphs = null; } /** diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/methodhandles/MethodHandleFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/methodhandles/MethodHandleFeature.java index affb067d166b..09bf5d6d23c1 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/methodhandles/MethodHandleFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/methodhandles/MethodHandleFeature.java @@ -37,7 +37,6 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.function.Supplier; -import jdk.graal.compiler.serviceprovider.JavaVersionUtil; import org.graalvm.nativeimage.hosted.RuntimeReflection; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; @@ -53,6 +52,7 @@ import com.oracle.svm.hosted.FeatureImpl.DuringSetupAccessImpl; import com.oracle.svm.util.ReflectionUtil; +import jdk.graal.compiler.serviceprovider.JavaVersionUtil; import sun.invoke.util.ValueConversions; import sun.invoke.util.Wrapper; @@ -417,6 +417,6 @@ private static void scanBoundMethodHandle(DuringAnalysisAccess a, Class bmhSu @Override public void afterAnalysis(AfterAnalysisAccess access) { - assert substitutionProcessor.checkAllTypeNames(); + assert substitutionProcessor == null || substitutionProcessor.checkAllTypeNames(); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/DevirtualizeCallsPhase.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/DevirtualizeCallsPhase.java deleted file mode 100644 index ce882d97ef81..000000000000 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/DevirtualizeCallsPhase.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.svm.hosted.phases; - -import static com.oracle.svm.core.graal.snippets.DeoptHostedSnippets.AnalysisSpeculation; -import static com.oracle.svm.core.graal.snippets.DeoptHostedSnippets.AnalysisSpeculationReason; - -import jdk.graal.compiler.core.common.type.Stamp; -import jdk.graal.compiler.core.common.type.StampFactory; -import jdk.graal.compiler.core.common.type.TypeReference; -import jdk.graal.compiler.debug.DebugContext; -import jdk.graal.compiler.nodes.CallTargetNode.InvokeKind; -import jdk.graal.compiler.nodes.FixedGuardNode; -import jdk.graal.compiler.nodes.Invoke; -import jdk.graal.compiler.nodes.LogicConstantNode; -import jdk.graal.compiler.nodes.PiNode; -import jdk.graal.compiler.nodes.StructuredGraph; -import jdk.graal.compiler.nodes.ValueNode; -import jdk.graal.compiler.nodes.extended.ValueAnchorNode; -import jdk.graal.compiler.phases.Phase; -import jdk.graal.compiler.phases.common.inlining.InliningUtil; - -import com.oracle.svm.core.SubstrateOptions; -import com.oracle.svm.core.nodes.SubstrateMethodCallTargetNode; -import com.oracle.svm.hosted.meta.HostedMethod; -import com.oracle.svm.util.ImageBuildStatistics; - -import jdk.vm.ci.meta.DeoptimizationAction; -import jdk.vm.ci.meta.DeoptimizationReason; -import jdk.vm.ci.meta.JavaMethodProfile; - -/** - * Devirtualize invokes based on Static Analysis results. - *

- * Specifically, if the Static Analysis determined that: - *

    - *
  • Invoke has no callees, it gets removed. - *
  • Indirect invoke has a single callee, it gets converted to a special invoke. - *
- */ -public class DevirtualizeCallsPhase extends Phase { - - @Override - protected void run(StructuredGraph graph) { - for (Invoke invoke : graph.getInvokes()) { - if (invoke.callTarget() instanceof SubstrateMethodCallTargetNode) { - SubstrateMethodCallTargetNode callTarget = (SubstrateMethodCallTargetNode) invoke.callTarget(); - - if (callTarget.invokeKind().isDirect() && !((HostedMethod) callTarget.targetMethod()).getWrapped().isSimplyImplementationInvoked()) { - /* - * This is a direct call to a method that the static analysis did not see as - * invoked. This can happen when the receiver is always null. In most cases, the - * method profile also has a length of 0 and the below code to kill the invoke - * would trigger. But not all methods have profiles, for example methods with - * manually constructed graphs. - */ - unreachableInvoke(graph, invoke, callTarget); - continue; - } - - JavaMethodProfile methodProfile = callTarget.getMethodProfile(); - if (methodProfile != null) { - if (methodProfile.getMethods().length == 0) { - unreachableInvoke(graph, invoke, callTarget); - } else if (methodProfile.getMethods().length == 1) { - if (callTarget.invokeKind().isIndirect()) { - singleCallee((HostedMethod) methodProfile.getMethods()[0].getMethod(), graph, invoke, callTarget); - } - } - } - } - } - } - - private final boolean parseOnce = SubstrateOptions.parseOnce(); - - private void unreachableInvoke(StructuredGraph graph, Invoke invoke, SubstrateMethodCallTargetNode callTarget) { - assert !parseOnce : "Must be done by StrengthenGraphs"; - - /* - * The invoke has no callee, i.e., it is unreachable. We just insert a always-failing guard - * before the invoke and let dead code elimination remove the invoke and everything after - * the invoke. - */ - if (!callTarget.isStatic()) { - InliningUtil.nonNullReceiver(invoke); - } - HostedMethod targetMethod = (HostedMethod) callTarget.targetMethod(); - String message = String.format("The call to %s is not reachable when called from %s.%n", targetMethod.format("%H.%n(%P)"), graph.method().format("%H.%n(%P)")); - AnalysisSpeculation speculation = new AnalysisSpeculation(new AnalysisSpeculationReason(message)); - FixedGuardNode node = new FixedGuardNode(LogicConstantNode.forBoolean(true, graph), DeoptimizationReason.UnreachedCode, DeoptimizationAction.None, speculation, true); - graph.addBeforeFixed(invoke.asFixedNode(), graph.add(node)); - graph.getDebug().dump(DebugContext.VERY_DETAILED_LEVEL, graph, "After dead invoke %s", invoke); - } - - private void singleCallee(HostedMethod singleCallee, StructuredGraph graph, Invoke invoke, SubstrateMethodCallTargetNode callTarget) { - assert !parseOnce : "Must be done by StrengthenGraphs"; - - if (ImageBuildStatistics.Options.CollectImageBuildStatistics.getValue(graph.getOptions())) { - /* Detect devirtualization of the invoke. */ - ImageBuildStatistics.counters().incDevirtualizedInvokeCounter(); - } - - /* - * The invoke has only one callee, i.e., the call can be devirtualized to this callee. This - * allows later inlining of the callee. - * - * We have to be careful to guard the improvement of the receiver type that is implied by - * the devirtualization: The callee assumes that the receiver type is the type that declares - * the callee. While this is true for all parts of the callee, it does not necessarily hold - * for all parts of the caller. So we need to ensure that after a possible inlining no parts - * of the callee float out to parts of the caller where the receiver type assumption does - * not hold. Since we do not know where in the caller a possible type check is performed, we - * anchor the receiver to the place of the original invoke. - */ - ValueAnchorNode anchor = graph.add(new ValueAnchorNode(null)); - graph.addBeforeFixed(invoke.asFixedNode(), anchor); - Stamp anchoredReceiverStamp = StampFactory.object(TypeReference.createWithoutAssumptions(singleCallee.getDeclaringClass())); - ValueNode anchoredReceiver = graph.unique(new PiNode(invoke.getReceiver(), anchoredReceiverStamp, anchor)); - invoke.callTarget().replaceFirstInput(invoke.getReceiver(), anchoredReceiver); - - assert callTarget.invokeKind() == InvokeKind.Virtual || callTarget.invokeKind() == InvokeKind.Interface; - callTarget.setInvokeKind(InvokeKind.Special); - callTarget.setTargetMethod(singleCallee); - } -} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/HostedGraphBuilderPhase.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/HostedGraphBuilderPhase.java index ab13b7a20dbe..7e6597ee0712 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/HostedGraphBuilderPhase.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/HostedGraphBuilderPhase.java @@ -24,6 +24,10 @@ */ package com.oracle.svm.hosted.phases; +import com.oracle.svm.core.nodes.SubstrateMethodCallTargetNode; +import com.oracle.svm.hosted.meta.HostedMethod; +import com.oracle.svm.hosted.phases.SubstrateGraphBuilderPhase.SubstrateBytecodeParser; + import jdk.graal.compiler.core.common.type.StampPair; import jdk.graal.compiler.java.BytecodeParser; import jdk.graal.compiler.java.FrameStateBuilder; @@ -38,12 +42,6 @@ import jdk.graal.compiler.nodes.spi.CoreProviders; import jdk.graal.compiler.phases.OptimisticOptimizations; import jdk.graal.compiler.word.WordTypes; - -import com.oracle.graal.pointsto.results.StaticAnalysisResults; -import com.oracle.svm.core.nodes.SubstrateMethodCallTargetNode; -import com.oracle.svm.hosted.meta.HostedMethod; -import com.oracle.svm.hosted.phases.SubstrateGraphBuilderPhase.SubstrateBytecodeParser; - import jdk.vm.ci.meta.JavaTypeProfile; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -93,9 +91,7 @@ protected void build(FixedWithNextNode startInstruction, FrameStateBuilder start @Override public MethodCallTargetNode createMethodCallTarget(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, StampPair returnStamp, JavaTypeProfile profile) { - StaticAnalysisResults staticAnalysisResults = getMethod().getProfilingInfo(); - return new SubstrateMethodCallTargetNode(invokeKind, targetMethod, args, returnStamp, - staticAnalysisResults.getTypeProfile(bci()), staticAnalysisResults.getMethodProfile(bci()), staticAnalysisResults.getStaticTypeProfile(bci())); + return new SubstrateMethodCallTargetNode(invokeKind, targetMethod, args, returnStamp); } } 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 f5fdb77473df..2df926b43b03 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 @@ -28,11 +28,19 @@ import java.util.Arrays; import java.util.List; +import com.oracle.graal.pointsto.infrastructure.GraphProvider; +import com.oracle.graal.pointsto.meta.HostedProviders; +import com.oracle.svm.core.c.BoxedRelocatedPointer; +import com.oracle.svm.core.classinitialization.EnsureClassInitializedNode; +import com.oracle.svm.core.graal.code.SubstrateCompilationIdentifier; +import com.oracle.svm.core.graal.replacements.SubstrateGraphKit; +import com.oracle.svm.core.util.VMError; +import com.oracle.svm.hosted.code.SubstrateCompilationDirectives; + import jdk.graal.compiler.core.common.type.StampFactory; import jdk.graal.compiler.core.common.type.StampPair; import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.nodes.AbstractMergeNode; -import jdk.graal.compiler.nodes.CallTargetNode.InvokeKind; import jdk.graal.compiler.nodes.ConstantNode; import jdk.graal.compiler.nodes.IfNode; import jdk.graal.compiler.nodes.LogicNode; @@ -47,21 +55,7 @@ import jdk.graal.compiler.nodes.extended.BytecodeExceptionNode; import jdk.graal.compiler.nodes.extended.GuardingNode; import jdk.graal.compiler.nodes.java.LoadFieldNode; -import jdk.graal.compiler.nodes.java.MethodCallTargetNode; import jdk.graal.compiler.nodes.type.StampTool; - -import com.oracle.graal.pointsto.infrastructure.GraphProvider; -import com.oracle.graal.pointsto.meta.HostedProviders; -import com.oracle.graal.pointsto.results.StaticAnalysisResults; -import com.oracle.svm.core.c.BoxedRelocatedPointer; -import com.oracle.svm.core.classinitialization.EnsureClassInitializedNode; -import com.oracle.svm.core.graal.code.SubstrateCompilationIdentifier; -import com.oracle.svm.core.graal.replacements.SubstrateGraphKit; -import com.oracle.svm.core.nodes.SubstrateMethodCallTargetNode; -import com.oracle.svm.core.util.VMError; -import com.oracle.svm.hosted.code.SubstrateCompilationDirectives; -import com.oracle.svm.hosted.meta.HostedMethod; - import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -74,18 +68,6 @@ public HostedGraphKit(DebugContext debug, HostedProviders providers, ResolvedJav SubstrateCompilationDirectives.isRuntimeCompiledMethod(method)); } - @Override - protected MethodCallTargetNode createMethodCallTarget(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, StampPair returnStamp, int bci) { - ResolvedJavaMethod method = graph.method(); - if (method instanceof HostedMethod) { - StaticAnalysisResults profilingInfo = ((HostedMethod) method).getProfilingInfo(); - return new SubstrateMethodCallTargetNode(invokeKind, targetMethod, args, returnStamp, - profilingInfo.getTypeProfile(bci), profilingInfo.getMethodProfile(bci), profilingInfo.getStaticTypeProfile(bci)); - } else { - return super.createMethodCallTarget(invokeKind, targetMethod, args, returnStamp, bci); - } - } - public void emitEnsureInitializedCall(ResolvedJavaType type) { if (EnsureClassInitializedNode.needsRuntimeInitialization(graph.method().getDeclaringClass(), type)) { ValueNode hub = createConstant(getConstantReflection().asJavaClass(type), JavaKind.Object); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java index 88b90c98dc78..66fdd7f21d9d 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java @@ -31,6 +31,32 @@ import java.util.Arrays; import java.util.List; +import com.oracle.graal.pointsto.constraints.TypeInstantiationException; +import com.oracle.graal.pointsto.constraints.UnresolvedElementException; +import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException; +import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; +import com.oracle.graal.pointsto.infrastructure.UniverseMetaAccess; +import com.oracle.svm.common.meta.MultiMethod; +import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.SubstrateUtil; +import com.oracle.svm.core.deopt.DeoptimizationSupport; +import com.oracle.svm.core.graal.nodes.DeoptEntryBeginNode; +import com.oracle.svm.core.graal.nodes.DeoptEntryNode; +import com.oracle.svm.core.graal.nodes.DeoptEntrySupport; +import com.oracle.svm.core.graal.nodes.DeoptProxyAnchorNode; +import com.oracle.svm.core.graal.nodes.LoweredDeadEndNode; +import com.oracle.svm.core.nodes.SubstrateMethodCallTargetNode; +import com.oracle.svm.core.util.UserError; +import com.oracle.svm.core.util.UserError.UserException; +import com.oracle.svm.core.util.VMError; +import com.oracle.svm.hosted.ExceptionSynthesizer; +import com.oracle.svm.hosted.LinkAtBuildTimeSupport; +import com.oracle.svm.hosted.code.FactoryMethodSupport; +import com.oracle.svm.hosted.code.SubstrateCompilationDirectives; +import com.oracle.svm.hosted.meta.HostedMethod; +import com.oracle.svm.hosted.nodes.DeoptProxyNode; +import com.oracle.svm.util.ReflectionUtil; + import jdk.graal.compiler.api.replacements.Fold; import jdk.graal.compiler.core.common.calc.Condition; import jdk.graal.compiler.core.common.type.StampPair; @@ -65,33 +91,6 @@ import jdk.graal.compiler.phases.OptimisticOptimizations; import jdk.graal.compiler.replacements.SnippetTemplate; import jdk.graal.compiler.word.WordTypes; - -import com.oracle.graal.pointsto.constraints.TypeInstantiationException; -import com.oracle.graal.pointsto.constraints.UnresolvedElementException; -import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException; -import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; -import com.oracle.graal.pointsto.infrastructure.UniverseMetaAccess; -import com.oracle.svm.common.meta.MultiMethod; -import com.oracle.svm.core.SubstrateOptions; -import com.oracle.svm.core.SubstrateUtil; -import com.oracle.svm.core.deopt.DeoptimizationSupport; -import com.oracle.svm.core.graal.nodes.DeoptEntryBeginNode; -import com.oracle.svm.core.graal.nodes.DeoptEntryNode; -import com.oracle.svm.core.graal.nodes.DeoptEntrySupport; -import com.oracle.svm.core.graal.nodes.DeoptProxyAnchorNode; -import com.oracle.svm.core.graal.nodes.LoweredDeadEndNode; -import com.oracle.svm.core.nodes.SubstrateMethodCallTargetNode; -import com.oracle.svm.core.util.UserError; -import com.oracle.svm.core.util.UserError.UserException; -import com.oracle.svm.core.util.VMError; -import com.oracle.svm.hosted.ExceptionSynthesizer; -import com.oracle.svm.hosted.LinkAtBuildTimeSupport; -import com.oracle.svm.hosted.code.FactoryMethodSupport; -import com.oracle.svm.hosted.code.SubstrateCompilationDirectives; -import com.oracle.svm.hosted.meta.HostedMethod; -import com.oracle.svm.hosted.nodes.DeoptProxyNode; -import com.oracle.svm.util.ReflectionUtil; - import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaField; import jdk.vm.ci.meta.JavaKind; @@ -580,7 +579,7 @@ public MethodCallTargetNode createMethodCallTarget(InvokeKind invokeKind, Resolv checkWordType(args[i + (isStatic ? 0 : 1)], targetMethod.getSignature().getParameterType(i, null), "call argument"); } - return new SubstrateMethodCallTargetNode(invokeKind, targetMethod, args, returnStamp, profile, null, profile); + return new SubstrateMethodCallTargetNode(invokeKind, targetMethod, args, returnStamp); } @Override diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/StrengthenStampsPhase.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/StrengthenStampsPhase.java deleted file mode 100644 index b7e81d5fa3be..000000000000 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/StrengthenStampsPhase.java +++ /dev/null @@ -1,272 +0,0 @@ -/* - * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.svm.hosted.phases; - -import jdk.graal.compiler.core.common.type.AbstractObjectStamp; -import jdk.graal.compiler.core.common.type.ObjectStamp; -import jdk.graal.compiler.core.common.type.Stamp; -import jdk.graal.compiler.core.common.type.StampFactory; -import jdk.graal.compiler.core.common.type.TypeReference; -import jdk.graal.compiler.graph.Node; -import jdk.graal.compiler.nodes.FixedGuardNode; -import jdk.graal.compiler.nodes.FixedWithNextNode; -import jdk.graal.compiler.nodes.InvokeWithExceptionNode; -import jdk.graal.compiler.nodes.LogicConstantNode; -import jdk.graal.compiler.nodes.NodeView; -import jdk.graal.compiler.nodes.ParameterNode; -import jdk.graal.compiler.nodes.PhiNode; -import jdk.graal.compiler.nodes.PiNode; -import jdk.graal.compiler.nodes.StructuredGraph; -import jdk.graal.compiler.nodes.ValueNode; -import jdk.graal.compiler.nodes.java.InstanceOfNode; -import jdk.graal.compiler.nodes.java.LoadFieldNode; -import jdk.graal.compiler.nodes.spi.LimitedValueProxy; -import jdk.graal.compiler.phases.Phase; - -import com.oracle.svm.core.SubstrateOptions; -import com.oracle.svm.hosted.meta.HostedField; -import com.oracle.svm.hosted.meta.HostedType; - -import jdk.vm.ci.meta.DeoptimizationAction; -import jdk.vm.ci.meta.DeoptimizationReason; -import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.JavaTypeProfile; -import jdk.vm.ci.meta.JavaTypeProfile.ProfiledType; -import jdk.vm.ci.meta.ResolvedJavaField; -import jdk.vm.ci.meta.ResolvedJavaType; -import jdk.vm.ci.meta.TriState; - -/** - * Strengthens the stamp of nodes based on the static analysis result. The canonicalizer then - * propagates the improved stamp through the method and, for example, removes null-checks when the - * new stamp states that a value is non-null. - */ -public class StrengthenStampsPhase extends Phase { - - @Override - protected void run(StructuredGraph graph) { - for (Node n : graph.getNodes()) { - if (n instanceof ValueNode && !(n instanceof LimitedValueProxy) && !(n instanceof PhiNode)) { - /* - * The stamp of proxy nodes and phi nodes is inferred automatically, so we do not - * need to improve them. - */ - ValueNode node = (ValueNode) n; - - /* - * First ask the node to improve the stamp itself, to incorporate already improved - * input stamps. - */ - node.inferStamp(); - - Stamp newStamp = strengthen(node.stamp(NodeView.DEFAULT)); - if (newStamp != null) { - assert !parseOnce : "Must be done by StrengthenGraphs"; - node.setStamp(newStamp); - } - } - - if (n instanceof LoadFieldNode) { - LoadFieldNode node = (LoadFieldNode) n; - updateStamp(node, toHosted(node.field()).getFieldTypeProfile()); - - } else if (n instanceof InstanceOfNode) { - InstanceOfNode node = (InstanceOfNode) n; - ObjectStamp newStamp = (ObjectStamp) strengthen(node.getCheckedStamp()); - if (newStamp != null) { - assert !parseOnce : "Must be done by StrengthenGraphs"; - node.replaceAndDelete(graph.addOrUniqueWithInputs(InstanceOfNode.createHelper(newStamp, node.getValue(), node.profile(), node.getAnchor()))); - } - - } else if (n instanceof PiNode) { - PiNode node = (PiNode) n; - Stamp newStamp = strengthen(node.piStamp()); - if (newStamp != null) { - assert !parseOnce : "Must be done by StrengthenGraphs"; - node.strengthenPiStamp(newStamp); - } - } - } - } - - private Stamp strengthen(Stamp s) { - if (!(s instanceof AbstractObjectStamp)) { - return null; - } - - AbstractObjectStamp stamp = (AbstractObjectStamp) s; - HostedType originalType = toHosted(stamp.type()); - if (originalType == null) { - return null; - } - - HostedType strengthenType = originalType.getStrengthenStampType(); - if (originalType.equals(strengthenType)) { - /* Nothing to strengthen. */ - return null; - } - - Stamp newStamp; - if (strengthenType == null) { - if (stamp.nonNull()) { - /* We must be in dead code. */ - newStamp = StampFactory.empty(JavaKind.Object); - } else { - /* The type its subtypes are not instantiated, the only possible value is null. */ - newStamp = StampFactory.alwaysNull(); - } - - } else { - if (stamp.isExactType()) { - /* We must be in dead code. */ - newStamp = StampFactory.empty(JavaKind.Object); - } else { - ResolvedJavaType targetType = toTarget(strengthenType); - if (targetType == null) { - return null; - } - TypeReference typeRef = TypeReference.createTrustedWithoutAssumptions(targetType); - newStamp = StampFactory.object(typeRef, stamp.nonNull()); - } - } - return newStamp; - } - - private final boolean parseOnce = SubstrateOptions.parseOnce(); - - private void updateStamp(ValueNode node, JavaTypeProfile typeProfile) { - if (node.getStackKind() != JavaKind.Object) { - return; - } - - if (typeProfile != null) { - Stamp newStamp = strengthenStamp(node, typeProfile); - if (!newStamp.equals(node.stamp(NodeView.DEFAULT))) { - assert !parseOnce : "Must be done by StrengthenGraphs"; - node.getDebug().log("STAMP UPDATE method %s node %s old %s new %s%n", node.graph().method().format("%H.%n(%p)"), node, node.stamp(NodeView.DEFAULT), newStamp); - node.setStamp(newStamp); - } - } - } - - private Stamp strengthenStamp(ValueNode node, JavaTypeProfile typeProfile) { - ObjectStamp oldStamp = (ObjectStamp) node.stamp(NodeView.DEFAULT); - HostedType oldType = toHosted(oldStamp.type()); - - if (oldStamp.alwaysNull()) { - /* We cannot make that more precise. */ - return oldStamp; - } - - boolean nonNull = oldStamp.nonNull() || typeProfile.getNullSeen() == TriState.FALSE; - ProfiledType[] exactTypes = typeProfile.getTypes(); - - if (exactTypes.length == 1) { - ResolvedJavaType exactType = exactTypes[0].getType(); - - assert oldType == null || oldType.isAssignableFrom(exactType); - if (!oldStamp.isExactType() || !exactType.equals(oldType) || nonNull != oldStamp.nonNull()) { - ResolvedJavaType targetType = toTarget(exactType); - if (targetType == null) { - return oldStamp; - } - TypeReference typeRef = TypeReference.createExactTrusted(targetType); - return nonNull ? StampFactory.objectNonNull(typeRef) : StampFactory.object(typeRef); - } else { - return oldStamp; - } - - } - - if (exactTypes.length == 0) { - if (!nonNull) { - return StampFactory.alwaysNull(); - } else { - /* - * The code after the node is unreachable. We just insert a always-failing guard - * after the node and let dead code elimination remove everything after the node. - */ - StructuredGraph graph = node.graph(); - FixedWithNextNode insertionPoint; - if (node instanceof ParameterNode) { - /* The whole method is unreachable. */ - insertionPoint = graph.start(); - } else if (node instanceof InvokeWithExceptionNode) { - /* The invoked method never returns normally (but can throw an exception). */ - insertionPoint = ((InvokeWithExceptionNode) node).next(); - } else { - insertionPoint = (FixedWithNextNode) node; - } - graph.addAfterFixed(insertionPoint, graph.add(new FixedGuardNode(LogicConstantNode.forBoolean(true, graph), DeoptimizationReason.UnreachedCode, DeoptimizationAction.None, true))); - return oldStamp; - } - } - - ResolvedJavaType baseType; - if (oldStamp.isExactType()) { - /* Base type cannot be more precise. */ - baseType = oldType; - } else { - assert exactTypes.length > 1; - assert oldType == null || oldType.isAssignableFrom(exactTypes[0].getType()); - baseType = exactTypes[0].getType(); - for (int i = 1; i < exactTypes.length; i++) { - assert oldType == null || oldType.isAssignableFrom(exactTypes[i].getType()); - baseType = baseType.findLeastCommonAncestor(exactTypes[i].getType()); - } - - if (oldType != null && !oldType.isAssignableFrom(baseType)) { - /* - * When the original stamp is an interface type, we do not want to weaken that type - * with the common base class of all implementation types (which could even be - * java.lang.Object). - */ - baseType = oldType; - } - } - - if (!baseType.equals(oldType) || nonNull != oldStamp.nonNull()) { - ResolvedJavaType targetType = toTarget(baseType); - if (targetType == null) { - return oldStamp; - } - TypeReference typeRef = TypeReference.createTrustedWithoutAssumptions(targetType); - return nonNull ? StampFactory.objectNonNull(typeRef) : StampFactory.object(typeRef); - } - return oldStamp; - } - - protected HostedType toHosted(ResolvedJavaType type) { - return (HostedType) type; - } - - protected HostedField toHosted(ResolvedJavaField field) { - return (HostedField) field; - } - - protected ResolvedJavaType toTarget(ResolvedJavaType type) { - return type; - } -}