use of org.graalvm.compiler.nodes.Invoke in project graal by oracle.
the class InliningData method doInline.
@SuppressWarnings("try")
private void doInline(CallsiteHolderExplorable callerCallsiteHolder, MethodInvocation calleeInvocation) {
StructuredGraph callerGraph = callerCallsiteHolder.graph();
InlineInfo calleeInfo = calleeInvocation.callee();
try {
try (DebugContext.Scope scope = debug.scope("doInline", callerGraph)) {
EconomicSet<Node> canonicalizedNodes = EconomicSet.create(Equivalence.IDENTITY);
canonicalizedNodes.addAll(calleeInfo.invoke().asNode().usages());
EconomicSet<Node> parameterUsages = calleeInfo.inline(new Providers(context));
canonicalizedNodes.addAll(parameterUsages);
counterInliningRuns.increment(debug);
debug.dump(DebugContext.DETAILED_LEVEL, callerGraph, "after %s", calleeInfo);
Graph.Mark markBeforeCanonicalization = callerGraph.getMark();
canonicalizer.applyIncremental(callerGraph, context, canonicalizedNodes);
// process invokes that are possibly created during canonicalization
for (Node newNode : callerGraph.getNewNodes(markBeforeCanonicalization)) {
if (newNode instanceof Invoke) {
callerCallsiteHolder.pushInvoke((Invoke) newNode);
}
}
callerCallsiteHolder.computeProbabilities();
counterInliningPerformed.increment(debug);
}
} catch (BailoutException bailout) {
throw bailout;
} catch (AssertionError | RuntimeException e) {
throw new GraalError(e).addContext(calleeInfo.toString());
} catch (GraalError e) {
throw e.addContext(calleeInfo.toString());
} catch (Throwable e) {
throw debug.handle(e);
}
}
use of org.graalvm.compiler.nodes.Invoke in project graal by oracle.
the class InliningData method processNextInvoke.
/**
* This method picks one of the callsites belonging to the current
* {@link CallsiteHolderExplorable}. Provided the callsite qualifies to be analyzed for
* inlining, this method prepares a new stack top in {@link InliningData} for such callsite,
* which comprises:
* <ul>
* <li>preparing a summary of feasible targets, ie preparing an {@link InlineInfo}</li>
* <li>based on it, preparing the stack top proper which consists of:</li>
* <ul>
* <li>one {@link MethodInvocation}</li>
* <li>a {@link CallsiteHolder} for each feasible target</li>
* </ul>
* </ul>
*
* <p>
* The thus prepared "stack top" is needed by {@link #moveForward()} to explore the space of
* inlining decisions (each decision one of: backtracking, delving, inlining).
* </p>
*
* <p>
* The {@link InlineInfo} used to get things rolling is kept around in the
* {@link MethodInvocation}, it will be needed in case of inlining, see
* {@link InlineInfo#inline(Providers)}
* </p>
*/
private void processNextInvoke() {
CallsiteHolderExplorable callsiteHolder = (CallsiteHolderExplorable) currentGraph();
Invoke invoke = callsiteHolder.popInvoke();
InlineInfo info = getInlineInfo(invoke);
if (info != null) {
info.populateInlinableElements(context, currentGraph().graph(), canonicalizer, rootGraph.getOptions());
double invokeProbability = callsiteHolder.invokeProbability(invoke);
double invokeRelevance = callsiteHolder.invokeRelevance(invoke);
MethodInvocation methodInvocation = new MethodInvocation(info, invokeProbability, invokeRelevance, freshlyInstantiatedArguments(invoke, callsiteHolder.getFixedParams()));
pushInvocationAndGraphs(methodInvocation);
}
}
use of org.graalvm.compiler.nodes.Invoke in project graal by oracle.
the class ArrayCopyIntrinsificationTest method getCode.
@Override
protected InstalledCode getCode(ResolvedJavaMethod method, StructuredGraph g, boolean forceCompile, boolean installAsDefault, OptionValues options) {
StructuredGraph graph = g == null ? parseForCompile(method) : g;
int nodeCount = graph.getNodeCount();
InstalledCode result = super.getCode(method, graph, forceCompile, installAsDefault, options);
boolean graphWasProcessed = nodeCount != graph.getNodeCount();
if (graphWasProcessed) {
if (mustIntrinsify) {
for (Node node : graph.getNodes()) {
if (node instanceof Invoke) {
Invoke invoke = (Invoke) node;
Assert.assertTrue(invoke.callTarget() instanceof DirectCallTargetNode);
LoweredCallTargetNode directCall = (LoweredCallTargetNode) invoke.callTarget();
JavaMethod callee = directCall.targetMethod();
if (callee.getDeclaringClass().equals(getMetaAccess().lookupJavaType(System.class)) && callee.getName().equals("arraycopy")) {
// A partial snippet (e.g., ArrayCopySnippets.checkcastArraycopy) may
// call the original arraycopy method
} else {
Assert.assertTrue(callee.toString(), callee.getName().equals("<init>"));
Assert.assertTrue(getMetaAccess().lookupJavaType(ArrayIndexOutOfBoundsException.class).equals(callee.getDeclaringClass()) || getMetaAccess().lookupJavaType(NullPointerException.class).equals(callee.getDeclaringClass()));
}
}
}
} else {
boolean found = false;
for (Node node : graph.getNodes()) {
if (node instanceof Invoke) {
Invoke invoke = (Invoke) node;
LoweredCallTargetNode directCall = (LoweredCallTargetNode) invoke.callTarget();
JavaMethod callee = directCall.targetMethod();
if (callee.getDeclaringClass().equals(getMetaAccess().lookupJavaType(System.class)) && callee.getName().equals("arraycopy")) {
found = true;
} else {
fail("found invoke to some method other than arraycopy: " + callee);
}
}
}
Assert.assertTrue("did not find invoke to arraycopy", found);
}
}
return result;
}
use of org.graalvm.compiler.nodes.Invoke in project graal by oracle.
the class IntrinsifyMethodHandlesInvocationPlugin method processInvokeWithMethodHandle.
@SuppressWarnings("try")
private void processInvokeWithMethodHandle(GraphBuilderContext b, BytecodeProvider bytecodeProvider, ResolvedJavaMethod methodHandleMethod, ValueNode[] methodHandleArguments) {
Plugins graphBuilderPlugins = new Plugins(((ReplacementsImpl) originalProviders.getReplacements()).getGraphBuilderPlugins());
registerInvocationPlugins(graphBuilderPlugins.getInvocationPlugins(), bytecodeProvider);
graphBuilderPlugins.prependParameterPlugin(new MethodHandlesParameterPlugin(methodHandleArguments));
graphBuilderPlugins.clearInlineInvokePlugins();
graphBuilderPlugins.prependInlineInvokePlugin(new MethodHandlesInlineInvokePlugin());
graphBuilderPlugins.prependNodePlugin(new MethodHandlePlugin(originalProviders.getConstantReflection().getMethodHandleAccess(), false));
/* We do all the word type rewriting because parameters to the lambda can be word types. */
SnippetReflectionProvider originalSnippetReflection = GraalAccess.getOriginalSnippetReflection();
WordOperationPlugin wordOperationPlugin = new WordOperationPlugin(originalSnippetReflection, new WordTypes(originalProviders.getMetaAccess(), FrameAccess.getWordKind()));
graphBuilderPlugins.appendInlineInvokePlugin(wordOperationPlugin);
graphBuilderPlugins.appendTypePlugin(wordOperationPlugin);
graphBuilderPlugins.appendTypePlugin(new TrustedInterfaceTypePlugin());
graphBuilderPlugins.appendNodePlugin(wordOperationPlugin);
GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getSnippetDefault(graphBuilderPlugins);
GraphBuilderPhase.Instance graphBuilder = new GraphBuilderPhase.Instance(originalProviders.getMetaAccess(), originalProviders.getStampProvider(), originalProviders.getConstantReflection(), originalProviders.getConstantFieldProvider(), graphBuilderConfig, OptimisticOptimizations.NONE, null);
DebugContext debug = b.getDebug();
StructuredGraph graph = new StructuredGraph.Builder(b.getOptions(), debug).method(toOriginal(methodHandleMethod)).build();
try (DebugContext.Scope s = debug.scope("IntrinsifyMethodHandles", graph)) {
graphBuilder.apply(graph);
/*
* We do not care about the improved type information from Pi nodes, so we just delete
* them to simplify our graph.
*/
for (PiNode pi : graph.getNodes(PiNode.TYPE)) {
pi.replaceAndDelete(pi.object());
}
/*
* Support for MethodHandle that adapt the input type to a more generic type, i.e., a
* MethodHandle that does a dynamic type check on a parameter.
*/
for (UnaryOpLogicNode node : graph.getNodes().filter(UnaryOpLogicNode.class).filter(v -> v instanceof IsNullNode || v instanceof InstanceOfNode)) {
ValueNode value = node.getValue();
if (value instanceof ParameterNode) {
/*
* We just assume that the InstanceOfNode or IsNullNode are used in an If and
* the true-successor is actually the branch we want. If that assumption is
* wrong, nothing bad happens - we will just continue to report the invocation
* as unsupported because the updated stamp for the parameter will not simplify
* the graph.
*/
if (node instanceof InstanceOfNode) {
InstanceOfNode inst = (InstanceOfNode) node;
TypeReference typeRef = inst.type();
value.setStamp(new ObjectStamp(typeRef.getType(), typeRef.isExact(), !inst.allowsNull(), false));
} else {
assert node instanceof IsNullNode;
ResolvedJavaType type = value.stamp(NodeView.DEFAULT).javaType(originalProviders.getMetaAccess());
value.setStamp(new ObjectStamp(type, false, /* non-null */
true, false));
}
}
}
/*
* The canonicalizer converts unsafe field accesses for get/set method handles back to
* high-level field load and store nodes.
*/
new CanonicalizerPhase().apply(graph, new PhaseContext(originalProviders));
for (FixedGuardNode guard : graph.getNodes(FixedGuardNode.TYPE)) {
if (guard.next() instanceof AccessFieldNode && guard.condition() instanceof IsNullNode && guard.isNegated() && ((IsNullNode) guard.condition()).getValue() == ((AccessFieldNode) guard.next()).object()) {
/*
* Method handles to load and stores fields have null checks. Remove them, since
* the null check is implicitly done by the field access.
*/
GraphUtil.removeFixedWithUnusedInputs(guard);
}
}
debug.dump(DebugContext.VERY_DETAILED_LEVEL, graph, "Final intrinisfication graph");
/*
* After parsing (and recursive inlining during parsing), the graph must contain only
* one invocation (and therefore only one MethodCallTargetNode), plus the parameters,
* constants, start, and return nodes.
*/
Node singleFunctionality = null;
ReturnNode singleReturn = null;
for (Node node : graph.getNodes()) {
if (node == graph.start() || node instanceof ParameterNode || node instanceof ConstantNode || node instanceof FrameState) {
/* Ignore the allowed framework around the nodes we care about. */
continue;
} else if (node instanceof Invoke) {
/* We check the MethodCallTargetNode, so we can ignore the invoke. */
continue;
} else if ((node instanceof MethodCallTargetNode || node instanceof LoadFieldNode || node instanceof StoreFieldNode) && singleFunctionality == null) {
singleFunctionality = node;
continue;
} else if (node instanceof ReturnNode && singleReturn == null) {
singleReturn = (ReturnNode) node;
continue;
}
throw new UnsupportedFeatureException("Invoke with MethodHandle argument could not be reduced to at most a single call: " + methodHandleMethod.format("%H.%n(%p)"));
}
if (singleFunctionality instanceof MethodCallTargetNode) {
MethodCallTargetNode singleCallTarget = (MethodCallTargetNode) singleFunctionality;
assert singleReturn.result() == null || singleReturn.result() == singleCallTarget.invoke();
/*
* Replace the originalTarget with the replacementTarget. Note that the
* replacementTarget node belongs to a different graph than originalTarget, so we
* need to match parameter back to the original graph and allocate a new
* MethodCallTargetNode for the original graph.
*/
ValueNode[] replacedArguments = new ValueNode[singleCallTarget.arguments().size()];
for (int i = 0; i < replacedArguments.length; i++) {
replacedArguments[i] = lookup(b, methodHandleArguments, singleCallTarget.arguments().get(i));
}
b.handleReplacedInvoke(singleCallTarget.invokeKind(), lookup(singleCallTarget.targetMethod()), replacedArguments, false);
} else if (singleFunctionality instanceof LoadFieldNode) {
LoadFieldNode fieldLoad = (LoadFieldNode) singleFunctionality;
b.addPush(b.getInvokeReturnType().getJavaKind(), LoadFieldNode.create(null, lookup(b, methodHandleArguments, fieldLoad.object()), lookup(fieldLoad.field())));
} else if (singleFunctionality instanceof StoreFieldNode) {
StoreFieldNode fieldStore = (StoreFieldNode) singleFunctionality;
b.add(new StoreFieldNode(lookup(b, methodHandleArguments, fieldStore.object()), lookup(fieldStore.field()), lookup(b, methodHandleArguments, fieldStore.value())));
} else if (singleReturn.result() != null) {
/* Replace the invocation with he constant result. */
JavaConstant constantResult = singleReturn.result().asJavaConstant();
assert b.getInvokeReturnType().getJavaKind() == constantResult.getJavaKind();
b.addPush(constantResult.getJavaKind(), ConstantNode.forConstant(lookup(constantResult), universeProviders.getMetaAccess()));
} else {
/* No invoke and no return value, so nothing to do. */
assert b.getInvokeReturnType().getJavaKind() == JavaKind.Void;
}
} catch (Throwable ex) {
throw debug.handle(ex);
}
}
use of org.graalvm.compiler.nodes.Invoke in project graal by oracle.
the class DevirtualizeCallsPhase method run.
@Override
protected void run(StructuredGraph graph) {
for (Invoke invoke : graph.getInvokes()) {
if (invoke.callTarget() instanceof SubstrateMethodCallTargetNode) {
SubstrateMethodCallTargetNode callTarget = (SubstrateMethodCallTargetNode) invoke.callTarget();
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);
}
}
}
}
}
}
Aggregations