Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[GR-29145] Strengthen graphs with constants propagated through static analysis. #5454

Merged
merged 3 commits into from
Dec 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ protected final StructuredGraph getGraph(DebugContext debug, CompilationIdentifi
ResolvedJavaMethod getAndClearObjectResult = foreignCallSnippets.getAndClearObjectResult.getMethod();
ResolvedJavaMethod verifyObject = foreignCallSnippets.verifyObject.getMethod();
ResolvedJavaMethod thisMethod = getGraphMethod();
GraphKit kit = new GraphKit(debug, thisMethod, providers, wordTypes, providers.getGraphBuilderPlugins(), compilationId, toString(), false, true);
HotSpotGraphKit kit = new HotSpotGraphKit(debug, thisMethod, providers, wordTypes, providers.getGraphBuilderPlugins(), compilationId, toString(), false, true);
StructuredGraph graph = kit.getGraph();
graph.getGraphState().forceDisableFrameStateVerification();
ReadRegisterNode thread = kit.append(new ReadRegisterNode(providers.getRegisters().getThreadRegister(), wordTypes.getWordKind(), true, false));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* Copyright (c) 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 org.graalvm.compiler.hotspot.stubs;

import static jdk.vm.ci.services.Services.IS_IN_NATIVE_IMAGE;
import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_AFTER_PARSING;

import org.graalvm.compiler.core.common.CompilationIdentifier;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.java.GraphBuilderPhase;
import org.graalvm.compiler.nodes.Invoke;
import org.graalvm.compiler.nodes.InvokeNode;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext;
import org.graalvm.compiler.phases.OptimisticOptimizations;
import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
import org.graalvm.compiler.phases.common.inlining.InliningUtil;
import org.graalvm.compiler.phases.util.Providers;
import org.graalvm.compiler.replacements.GraphKit;
import org.graalvm.compiler.word.WordTypes;

import jdk.vm.ci.meta.ResolvedJavaMethod;

/**
* HotSpot-specific extensions for manually building a graph.
*
* The support for inlining calls is here and not in the base class because the
* {@link GraphBuilderPhase} is VM specific, i.e., for other VMs a subclass of
* {@link GraphBuilderPhase} might be necessary for correct parsing.
*/
public class HotSpotGraphKit extends GraphKit {

public HotSpotGraphKit(DebugContext debug, ResolvedJavaMethod stubMethod, Providers providers, WordTypes wordTypes, Plugins graphBuilderPlugins, CompilationIdentifier compilationId, String name,
boolean trackNodeSourcePosition, boolean recordInlinedMethods) {
super(debug, stubMethod, providers, wordTypes, graphBuilderPlugins, compilationId, name, trackNodeSourcePosition, recordInlinedMethods);
}

/**
* Recursively {@linkplain #inlineAsIntrinsic inlines} all invocations currently in the graph.
* The graph of the inlined method is processed in the same manner as for snippets and method
* substitutions (e.g. intrinsics).
*/
public void inlineInvokesAsIntrinsics(String reason, String phase) {
while (!graph.getNodes().filter(InvokeNode.class).isEmpty()) {
for (InvokeNode invoke : graph.getNodes().filter(InvokeNode.class).snapshot()) {
inlineAsIntrinsic(invoke, reason, phase);
}
}

// Clean up all code that is now dead after inlining.
new DeadCodeEliminationPhase().apply(graph);
}

/**
* Inlines a given invocation to a method. The graph of the inlined method is processed in the
* same manner as for snippets and method substitutions (e.g. intrinsics).
*/
public void inlineAsIntrinsic(Invoke invoke, String reason, String phase) {
assert invoke instanceof Node;
Node invokeNode = (Node) invoke;
ResolvedJavaMethod method = invoke.callTarget().targetMethod();

Plugins plugins = new Plugins(graphBuilderPlugins);
GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(plugins);

StructuredGraph calleeGraph;
if (IS_IN_NATIVE_IMAGE) {
calleeGraph = getReplacements().getSnippet(method, null, null, null, false, null, invokeNode.getOptions());
} else {
calleeGraph = new StructuredGraph.Builder(invokeNode.getOptions(), invokeNode.getDebug()).method(method).trackNodeSourcePosition(
invokeNode.graph().trackNodeSourcePosition()).setIsSubstitution(true).build();
IntrinsicContext initialReplacementContext = new IntrinsicContext(method, method, getReplacements().getDefaultReplacementBytecodeProvider(), INLINE_AFTER_PARSING);
GraphBuilderPhase.Instance instance = createGraphBuilderInstance(config, OptimisticOptimizations.NONE, initialReplacementContext);
instance.apply(calleeGraph);
}
new DeadCodeEliminationPhase().apply(calleeGraph);

InliningUtil.inline(invoke, calleeGraph, false, method, reason, phase);
}

protected GraphBuilderPhase.Instance createGraphBuilderInstance(GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts,
IntrinsicContext initialIntrinsicContext) {
/* There is no HotSpot-specific subclass of GraphBuilderPhase yet. */
return new GraphBuilderPhase.Instance(getProviders(), graphBuilderConfig, optimisticOpts, initialIntrinsicContext);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
import static jdk.vm.ci.code.BytecodeFrame.UNKNOWN_BCI;
import static jdk.vm.ci.services.Services.IS_IN_NATIVE_IMAGE;
import static org.graalvm.compiler.nodes.CallTargetNode.InvokeKind.Static;
import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_AFTER_PARSING;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
Expand All @@ -42,7 +41,6 @@
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.graph.Graph;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.graph.Node.ValueNumberable;
import org.graalvm.compiler.graph.NodeSourcePosition;
import org.graalvm.compiler.java.FrameStateBuilder;
Expand All @@ -56,7 +54,6 @@
import org.graalvm.compiler.nodes.FixedNode;
import org.graalvm.compiler.nodes.FixedWithNextNode;
import org.graalvm.compiler.nodes.IfNode;
import org.graalvm.compiler.nodes.Invoke;
import org.graalvm.compiler.nodes.InvokeNode;
import org.graalvm.compiler.nodes.InvokeWithExceptionNode;
import org.graalvm.compiler.nodes.LogicNode;
Expand All @@ -72,14 +69,10 @@
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderTool;
import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext;
import org.graalvm.compiler.nodes.java.ExceptionObjectNode;
import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
import org.graalvm.compiler.nodes.spi.CoreProvidersDelegate;
import org.graalvm.compiler.nodes.type.StampTool;
import org.graalvm.compiler.phases.OptimisticOptimizations;
import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
import org.graalvm.compiler.phases.common.inlining.InliningUtil;
import org.graalvm.compiler.phases.util.Providers;
import org.graalvm.compiler.word.WordTypes;

Expand All @@ -95,7 +88,7 @@
* subsystems that employ manual graph creation (as opposed to {@linkplain GraphBuilderPhase
* bytecode parsing} based graph creation).
*/
public class GraphKit extends CoreProvidersDelegate implements GraphBuilderTool {
public abstract class GraphKit extends CoreProvidersDelegate implements GraphBuilderTool {

protected final StructuredGraph graph;
protected final WordTypes wordTypes;
Expand Down Expand Up @@ -350,74 +343,6 @@ public boolean checkArgs(ResolvedJavaMethod method, ValueNode... args) {
return true;
}

/**
* Recursively {@linkplain #inlineAsIntrinsic inlines} all invocations currently in the graph.
* The graph of the inlined method is processed in the same manner as for snippets and method
* substitutions (e.g. intrinsics).
*/
public void inlineInvokesAsIntrinsics(String reason, String phase) {
while (!graph.getNodes().filter(InvokeNode.class).isEmpty()) {
for (InvokeNode invoke : graph.getNodes().filter(InvokeNode.class).snapshot()) {
inlineAsIntrinsic(invoke, reason, phase);
}
}

// Clean up all code that is now dead after inlining.
new DeadCodeEliminationPhase().apply(graph);
}

/**
* Inlines a given invocation to a method. The graph of the inlined method is processed in the
* same manner as for snippets and method substitutions (e.g. intrinsics).
*/
public void inlineAsIntrinsic(Invoke invoke, String reason, String phase) {
assert invoke instanceof Node;
Node invokeNode = (Node) invoke;
ResolvedJavaMethod method = invoke.callTarget().targetMethod();

Plugins plugins = new Plugins(graphBuilderPlugins);
GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(plugins);

StructuredGraph calleeGraph;
if (IS_IN_NATIVE_IMAGE) {
calleeGraph = getReplacements().getSnippet(method, null, null, null, false, null, invokeNode.getOptions());
} else {
calleeGraph = new StructuredGraph.Builder(invokeNode.getOptions(), invokeNode.getDebug()).method(method).trackNodeSourcePosition(
invokeNode.graph().trackNodeSourcePosition()).setIsSubstitution(true).build();
IntrinsicContext initialReplacementContext = new IntrinsicContext(method, method, getReplacements().getDefaultReplacementBytecodeProvider(), INLINE_AFTER_PARSING);
GraphBuilderPhase.Instance instance = createGraphBuilderInstance(config, OptimisticOptimizations.NONE, initialReplacementContext);
instance.apply(calleeGraph);
}
new DeadCodeEliminationPhase().apply(calleeGraph);

InliningUtil.inline(invoke, calleeGraph, false, method, reason, phase);
}

public void inline(Invoke invoke, String reason, String phase) {
assert invoke instanceof Node;
Node invokeNode = (Node) invoke;
ResolvedJavaMethod methodToInline = invoke.callTarget().targetMethod();
Plugins plugins = new Plugins(graphBuilderPlugins);
GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins);
StructuredGraph calleeGraph = new StructuredGraph.Builder(invokeNode.getOptions(), invokeNode.getDebug()).method(methodToInline).trackNodeSourcePosition(
invokeNode.graph().trackNodeSourcePosition()).setIsSubstitution(false).build();
/*
* Using null as the intrinsic context makes the ByteCodeParser inline invokes using
* InliningScope instead of IntrinsicScope. This allows exceptions to be a part of the
* inlined method.
*/
GraphBuilderPhase.Instance instance = createGraphBuilderInstance(config, OptimisticOptimizations.NONE, null);
instance.apply(calleeGraph);

new DeadCodeEliminationPhase().apply(calleeGraph);
InliningUtil.inline(invoke, calleeGraph, false, methodToInline, reason, phase);
}

protected GraphBuilderPhase.Instance createGraphBuilderInstance(GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts,
IntrinsicContext initialIntrinsicContext) {
return new GraphBuilderPhase.Instance(getProviders(), graphBuilderConfig, optimisticOpts, initialIntrinsicContext);
}

protected void pushStructure(Structure structure) {
structures.add(structure);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
import com.oracle.graal.pointsto.typestate.SingleTypeState;
import com.oracle.graal.pointsto.typestate.TypeState;

import jdk.vm.ci.meta.JavaConstant;

public class ContextSensitiveSingleTypeState extends SingleTypeState {
/** The objects of this type state. */
protected final AnalysisObject[] objects;
Expand Down Expand Up @@ -145,8 +147,16 @@ public boolean isAllocation() {
}

@Override
public boolean isConstant() {
return objects[0].isConstantContextSensitiveObject();
public JavaConstant asConstant() {
JavaConstant result = null;
for (AnalysisObject object : objects) {
JavaConstant objectConstant = object.asConstant();
if (objectConstant == null || (result != null && !result.equals(objectConstant))) {
return null;
}
result = objectConstant;
}
return result;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,12 +179,8 @@ public final boolean isAllocationContextSensitiveObject() {
return this.kind == AnalysisObjectKind.AllocationContextSensitive;
}

public final boolean isConstantContextSensitiveObject() {
return this.kind == AnalysisObjectKind.ConstantContextSensitive;
}

public final boolean isConstantObject() {
return this.kind == AnalysisObjectKind.ConstantObject;
public JavaConstant asConstant() {
return null;
}

public ArrayElementsTypeStore getArrayElementsTypeStore() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ public ConstantContextSensitiveObject(PointsToAnalysis bb, AnalysisType type, Ja
bb.profileConstantObject(type);
}

public JavaConstant getConstant() {
@Override
public JavaConstant asConstant() {
return constant;
}

Expand Down Expand Up @@ -128,7 +129,7 @@ public boolean isEmptyObjectArrayConstant(PointsToAnalysis bb) {
return false;
}

return AnalysisObject.isEmptyObjectArrayConstant(bb, getConstant());
return AnalysisObject.isEmptyObjectArrayConstant(bb, asConstant());
}

@Override
Expand Down
Loading