Skip to content

Commit

Permalink
[GR-17941] [GR-17937] Allow language-agnostic inlinling on SVM.
Browse files Browse the repository at this point in the history
PullRequest: graal/4310
  • Loading branch information
boris-spas committed Sep 12, 2019
2 parents 0cd7a56 + dad026b commit d40597c
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@
import org.graalvm.compiler.truffle.common.TruffleInliningPlan;
import org.graalvm.compiler.truffle.common.TruffleSourceLanguagePosition;
import org.graalvm.compiler.truffle.compiler.debug.HistogramInlineInvokePlugin;
import org.graalvm.compiler.truffle.compiler.nodes.IsInlinedNode;
import org.graalvm.compiler.truffle.compiler.nodes.TruffleAssumption;
import org.graalvm.compiler.truffle.compiler.nodes.asserts.NeverPartOfCompilationNode;
import org.graalvm.compiler.truffle.compiler.nodes.frame.AllowMaterializeNode;
Expand Down Expand Up @@ -149,6 +150,7 @@ public abstract class PartialEvaluator {
private final InvocationPlugins decodingInvocationPlugins;
private final NodePlugin[] nodePlugins;
private final KnownTruffleTypes knownTruffleTypes;
private final ResolvedJavaMethod callBoundary;

/**
* The instrumentation object is used by the Truffle instrumentation to count executions. The
Expand All @@ -175,6 +177,7 @@ public PartialEvaluator(Providers providers, GraphBuilderConfiguration configFor
this.callInlinedAgnosticMethod = findRequiredMethod(type, methods, "callInlinedAgnostic", "([Ljava/lang/Object;)Ljava/lang/Object;");
this.callIndirectMethod = findRequiredMethod(type, methods, "callIndirect", "(Lcom/oracle/truffle/api/nodes/Node;[Ljava/lang/Object;)Ljava/lang/Object;");
this.callRootMethod = findRequiredMethod(type, methods, "callRoot", "([Ljava/lang/Object;)Ljava/lang/Object;");
this.callBoundary = findRequiredMethod(type, methods, "callBoundary", "([Ljava/lang/Object;)Ljava/lang/Object;");

this.configForParsing = createGraphBuilderConfig(configForRoot, true);
this.decodingInvocationPlugins = createDecodingInvocationPlugins(configForRoot.getPlugins());
Expand Down Expand Up @@ -207,6 +210,20 @@ static ResolvedJavaMethod findRequiredMethod(ResolvedJavaType declaringClass, Re
throw new NoSuchMethodError(declaringClass.toJavaName() + "." + name + descriptor);
}

private static void removeIsInlinedNodes(StructuredGraph graph) {
for (IsInlinedNode isInlinedNode : graph.getNodes(IsInlinedNode.TYPE)) {
isInlinedNode.notInlined();
}
}

public ResolvedJavaMethod getCallDirectMethod() {
return callDirectMethod;
}

public ResolvedJavaMethod getCallBoundary() {
return callBoundary;
}

public Providers getProviders() {
return providers;
}
Expand All @@ -220,7 +237,7 @@ public KnownTruffleTypes getKnownTruffleTypes() {
}

public ResolvedJavaMethod[] getCompilationRootMethods() {
return new ResolvedJavaMethod[]{callRootMethod, callInlinedMethod};
return new ResolvedJavaMethod[]{callRootMethod, callInlinedMethod, callInlinedAgnosticMethod};
}

public ResolvedJavaMethod[] getNeverInlineMethods() {
Expand Down Expand Up @@ -660,6 +677,7 @@ private void agnosticInliningOrGraphPE(CompilableTruffleAST compilable, TruffleI
TruffleMaximumInlineNodeCount.getValue(graph.getOptions()));
doGraphPE(compilable, graph, tierContext, inliningDecision, plugin, EconomicMap.create());
}
removeIsInlinedNodes(graph);
}

protected void applyInstrumentationPhases(StructuredGraph graph, HighTierContext tierContext) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright (c) 2014, 2018, 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.truffle.compiler.nodes;

import org.graalvm.compiler.core.common.type.StampFactory;
import org.graalvm.compiler.graph.IterableNodeType;
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.nodeinfo.NodeCycles;
import org.graalvm.compiler.nodeinfo.NodeInfo;
import org.graalvm.compiler.nodeinfo.NodeSize;
import org.graalvm.compiler.nodes.ConstantNode;
import org.graalvm.compiler.nodes.calc.FloatingNode;

import jdk.vm.ci.meta.JavaKind;

/**
* This node is used by
* {@link org.graalvm.compiler.truffle.compiler.phases.inlining.AgnosticInliningPhase
* language-agnostic inlining} to differentiate between calls that were inlined (and thus do not
* need any special handling code for the call) from those that were not. The
* {@link org.graalvm.compiler.truffle.compiler.PartialEvaluator} removes all instances of this
* class from the graph during the Truffle tier.
*
*/
@NodeInfo(cycles = NodeCycles.CYCLES_0, size = NodeSize.SIZE_0)
public class IsInlinedNode extends FloatingNode implements IterableNodeType {
public static final NodeClass<IsInlinedNode> TYPE = NodeClass.create(IsInlinedNode.class);

protected IsInlinedNode() {
super(TYPE, StampFactory.forKind(JavaKind.Boolean));
}

public static IsInlinedNode create() {
return new IsInlinedNode();
}

public void inlined() {
replaceWith(true);
}

public void notInlined() {
replaceWith(false);
}

private void replaceWith(boolean b) {
replaceAtUsagesAndDelete(graph().unique(ConstantNode.forBoolean(b)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,19 +36,15 @@
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
import org.graalvm.compiler.nodes.spi.CoreProviders;
import org.graalvm.compiler.phases.common.inlining.InliningUtil;
import org.graalvm.compiler.phases.util.Providers;
import org.graalvm.compiler.truffle.common.CallNodeProvider;
import org.graalvm.compiler.truffle.common.CompilableTruffleAST;
import org.graalvm.compiler.truffle.common.TruffleCallNode;
import org.graalvm.compiler.truffle.common.TruffleCompilerRuntime;
import org.graalvm.compiler.truffle.compiler.PartialEvaluator;
import org.graalvm.compiler.truffle.compiler.nodes.IsInlinedNode;

import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.MetaAccessProvider;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaType;
import jdk.vm.ci.meta.SpeculationLog;

final class GraphManager {
Expand All @@ -65,17 +61,13 @@ final class GraphManager {
this.callNodeProvider = callNodeProvider;
}

static ResolvedJavaMethod findRequiredMethod(ResolvedJavaType declaringClass, ResolvedJavaMethod[] methods, String name, String descriptor) {
for (ResolvedJavaMethod method : methods) {
if (method.getName().equals(name) && method.getSignature().toMethodDescriptor().equals(descriptor)) {
return method;
private static void handleInlinedNodes(StructuredGraph ir, UnmodifiableEconomicMap<Node, Node> duplicates) {
for (IsInlinedNode isInlinedNode : ir.getNodes(IsInlinedNode.TYPE)) {
final IsInlinedNode duplicate = (IsInlinedNode) duplicates.get(isInlinedNode);
if (duplicate != null) {
duplicate.inlined();
}
}
throw new NoSuchMethodError(declaringClass.toJavaName() + "." + name + descriptor);
}

boolean contains(CompilableTruffleAST truffleAST) {
return irCache.containsKey(truffleAST);
}

Entry get(CompilableTruffleAST truffleAST) {
Expand All @@ -86,7 +78,7 @@ Entry get(CompilableTruffleAST truffleAST) {
DebugContext debug = rootIR.getDebug();
StructuredGraph.AllowAssumptions allowAssumptions = rootIR.getAssumptions() != null ? StructuredGraph.AllowAssumptions.YES : StructuredGraph.AllowAssumptions.NO;
CompilationIdentifier id = rootIR.compilationId();
final PEAgnosticInlineInvokePlugin plugin = new PEAgnosticInlineInvokePlugin(partialEvaluator.getProviders(), callNodeProvider);
final PEAgnosticInlineInvokePlugin plugin = new PEAgnosticInlineInvokePlugin(callNodeProvider, partialEvaluator.getCallDirectMethod(), partialEvaluator.getCallBoundary());
StructuredGraph graph = partialEvaluator.createGraphForInlining(debug, truffleAST, callNodeProvider, plugin, allowAssumptions, id, log, cancellable,
graphCacheForInlining);
final EconomicMap<TruffleCallNode, Invoke> truffleCallNodeToInvoke = plugin.getTruffleCallNodeToInvoke();
Expand All @@ -97,18 +89,16 @@ Entry get(CompilableTruffleAST truffleAST) {
}

EconomicMap<TruffleCallNode, Invoke> peRoot(CompilableTruffleAST truffleAST) {
final PEAgnosticInlineInvokePlugin plugin = new PEAgnosticInlineInvokePlugin(partialEvaluator.getProviders(), callNodeProvider);
final PEAgnosticInlineInvokePlugin plugin = new PEAgnosticInlineInvokePlugin(callNodeProvider, partialEvaluator.getCallDirectMethod(), partialEvaluator.getCallBoundary());
partialEvaluator.parseRootGraphForInlining(truffleAST, rootIR, callNodeProvider, plugin, graphCacheForInlining);
return plugin.getTruffleCallNodeToInvoke();
}

UnmodifiableEconomicMap<Node, Node> doInline(Invoke invoke, StructuredGraph ir, CompilableTruffleAST truffleAST) {
return InliningUtil.inline(invoke, ir, true, partialEvaluator.inlineRootForCallTargetAgnostic(truffleAST),
final UnmodifiableEconomicMap<Node, Node> duplicates = InliningUtil.inline(invoke, ir, true, partialEvaluator.inlineRootForCallTargetAgnostic(truffleAST),
"cost-benefit analysis", "AgnosticInliningPhase");
}

public CoreProviders getCoreProviders() {
return partialEvaluator.getProviders();
handleInlinedNodes(ir, duplicates);
return duplicates;
}

static class Entry {
Expand All @@ -128,16 +118,11 @@ private static class PEAgnosticInlineInvokePlugin extends PartialEvaluator.PEInl
private final ResolvedJavaMethod callBoundary;
private JavaConstant lastDirectCallNode;

PEAgnosticInlineInvokePlugin(Providers providers, CallNodeProvider callNodeProvider) {
PEAgnosticInlineInvokePlugin(CallNodeProvider callNodeProvider, ResolvedJavaMethod callTargetCallDirect, ResolvedJavaMethod callBoundary) {
this.callTargetCallDirect = callTargetCallDirect;
this.callBoundary = callBoundary;
this.truffleCallNodeToInvoke = EconomicMap.create();
this.callNodeProvider = callNodeProvider;
TruffleCompilerRuntime runtime = TruffleCompilerRuntime.getRuntime();
MetaAccessProvider metaAccess = providers.getMetaAccess();
ResolvedJavaType callTargetType = runtime.resolveType(metaAccess, "org.graalvm.compiler.truffle.runtime.OptimizedCallTarget");
this.callTargetCallDirect = findRequiredMethod(callTargetType, callTargetType.getDeclaredMethods(), "callDirect",
"(Lcom/oracle/truffle/api/nodes/Node;[Ljava/lang/Object;)Ljava/lang/Object;");
this.callBoundary = findRequiredMethod(callTargetType, callTargetType.getDeclaredMethods(), "callBoundary",
"([Ljava/lang/Object;)Ljava/lang/Object;");

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import org.graalvm.compiler.nodes.FixedGuardNode;
import org.graalvm.compiler.nodes.FrameState;
import org.graalvm.compiler.nodes.InvokeNode;
import org.graalvm.compiler.truffle.compiler.nodes.IsInlinedNode;
import org.graalvm.compiler.nodes.LogicConstantNode;
import org.graalvm.compiler.nodes.LogicNode;
import org.graalvm.compiler.nodes.NodeView;
Expand Down Expand Up @@ -401,6 +402,13 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec
return true;
}
});
r.register0("inInlinedCode", new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
b.addPush(JavaKind.Boolean, IsInlinedNode.create());
return true;
}
});
registerUnsafeCast(r, canDelayIntrinsification);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@
import java.util.function.UnaryOperator;

import org.graalvm.compiler.truffle.common.CompilableTruffleAST;
import org.graalvm.compiler.truffle.runtime.OptimizedOSRLoopNode.OSRRootNode;
import org.graalvm.compiler.truffle.common.TruffleCallNode;
import org.graalvm.compiler.truffle.runtime.OptimizedOSRLoopNode.OSRRootNode;
import org.graalvm.options.OptionKey;
import org.graalvm.options.OptionValues;

Expand Down Expand Up @@ -146,6 +146,16 @@ public OptimizedCallTarget(OptimizedCallTarget sourceCallTarget, RootNode rootNo
tvmci.setCallTarget(rootNode, this);
}

/**
* Allows one to specify different behaviour if this call target is inlined (using
* language-agnostic inlining).
*
* @return false unless the call target was inlined into another one.
*/
protected static boolean inInlinedCode() {
return false;
}

public Assumption getNodeRewritingAssumption() {
Assumption assumption = nodeRewritingAssumption;
if (assumption == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ public Object doInvoke(Object[] args) {
* that no longer contains executable code.
*/
long start = address;
if (start != 0) {
if (!inInlinedCode() && start != 0) {
CallBoundaryFunctionPointer target = WordFactory.pointer(start);
return KnownIntrinsics.convertUnknownValue(target.invoke(this, args), Object.class);
} else {
Expand Down

0 comments on commit d40597c

Please sign in to comment.