InliningUtil.java revision 12968:4d8a004e5c6d
198944Sobrien/* 298944Sobrien * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. 398944Sobrien * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 498944Sobrien * 598944Sobrien * This code is free software; you can redistribute it and/or modify it 698944Sobrien * under the terms of the GNU General Public License version 2 only, as 798944Sobrien * published by the Free Software Foundation. 898944Sobrien * 998944Sobrien * This code is distributed in the hope that it will be useful, but WITHOUT 1098944Sobrien * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1198944Sobrien * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1298944Sobrien * version 2 for more details (a copy is included in the LICENSE file that 1398944Sobrien * accompanied this code). 1498944Sobrien * 1598944Sobrien * You should have received a copy of the GNU General Public License version 1698944Sobrien * 2 along with this work; if not, write to the Free Software Foundation, 1798944Sobrien * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1898944Sobrien * 1998944Sobrien * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2098944Sobrien * or visit www.oracle.com if you need additional information or have any 2198944Sobrien * questions. 2298944Sobrien */ 2398944Sobrienpackage org.graalvm.compiler.phases.common.inlining; 24130803Smarcel 2598944Sobrienimport static jdk.vm.ci.meta.DeoptimizationAction.InvalidateReprofile; 2698944Sobrienimport static jdk.vm.ci.meta.DeoptimizationReason.NullCheckException; 2798944Sobrienimport static org.graalvm.compiler.core.common.GraalOptions.HotSpotPrintInlining; 2898944Sobrien 2998944Sobrienimport java.lang.reflect.Constructor; 3098944Sobrienimport java.util.ArrayList; 3198944Sobrienimport java.util.List; 3298944Sobrienimport java.util.function.Function; 3398944Sobrien 3498944Sobrienimport org.graalvm.compiler.api.replacements.MethodSubstitution; 3598944Sobrienimport org.graalvm.compiler.core.common.GraalOptions; 3698944Sobrienimport org.graalvm.compiler.core.common.type.Stamp; 3798944Sobrienimport org.graalvm.compiler.core.common.type.StampFactory; 3898944Sobrienimport org.graalvm.compiler.core.common.type.TypeReference; 3998944Sobrienimport org.graalvm.compiler.core.common.util.Util; 4098944Sobrienimport org.graalvm.compiler.debug.Debug; 4198944Sobrienimport org.graalvm.compiler.debug.Debug.Scope; 4298944Sobrienimport org.graalvm.compiler.debug.Fingerprint; 4398944Sobrienimport org.graalvm.compiler.debug.GraalError; 4498944Sobrienimport org.graalvm.compiler.debug.internal.method.MethodMetricsImpl; 4598944Sobrienimport org.graalvm.compiler.debug.internal.method.MethodMetricsInlineeScopeInfo; 4698944Sobrienimport org.graalvm.compiler.graph.GraalGraphError; 4798944Sobrienimport org.graalvm.compiler.graph.Graph; 4898944Sobrienimport org.graalvm.compiler.graph.Graph.DuplicationReplacement; 4998944Sobrienimport org.graalvm.compiler.graph.Graph.NodeEventScope; 5098944Sobrienimport org.graalvm.compiler.graph.Node; 5198944Sobrienimport org.graalvm.compiler.graph.NodeInputList; 5298944Sobrienimport org.graalvm.compiler.graph.NodeSourcePosition; 53130803Smarcelimport org.graalvm.compiler.graph.NodeWorkList; 5498944Sobrienimport org.graalvm.compiler.nodeinfo.Verbosity; 5598944Sobrienimport org.graalvm.compiler.nodes.AbstractBeginNode; 5698944Sobrienimport org.graalvm.compiler.nodes.AbstractEndNode; 5798944Sobrienimport org.graalvm.compiler.nodes.AbstractMergeNode; 5898944Sobrienimport org.graalvm.compiler.nodes.BeginNode; 5998944Sobrienimport org.graalvm.compiler.nodes.CallTargetNode; 6098944Sobrienimport org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; 6198944Sobrienimport org.graalvm.compiler.nodes.ControlSinkNode; 6298944Sobrienimport org.graalvm.compiler.nodes.DeoptimizeNode; 6398944Sobrienimport org.graalvm.compiler.nodes.EndNode; 6498944Sobrienimport org.graalvm.compiler.nodes.FixedGuardNode; 6598944Sobrienimport org.graalvm.compiler.nodes.FixedNode; 6698944Sobrienimport org.graalvm.compiler.nodes.FixedWithNextNode; 6798944Sobrienimport org.graalvm.compiler.nodes.FrameState; 6898944Sobrienimport org.graalvm.compiler.nodes.Invoke; 6998944Sobrienimport org.graalvm.compiler.nodes.InvokeNode; 7098944Sobrienimport org.graalvm.compiler.nodes.InvokeWithExceptionNode; 7198944Sobrienimport org.graalvm.compiler.nodes.KillingBeginNode; 7298944Sobrienimport org.graalvm.compiler.nodes.LogicNode; 7398944Sobrienimport org.graalvm.compiler.nodes.MergeNode; 7498944Sobrienimport org.graalvm.compiler.nodes.ParameterNode; 7598944Sobrienimport org.graalvm.compiler.nodes.PhiNode; 7698944Sobrienimport org.graalvm.compiler.nodes.PiNode; 7798944Sobrienimport org.graalvm.compiler.nodes.ReturnNode; 7898944Sobrienimport org.graalvm.compiler.nodes.StartNode; 7998944Sobrienimport org.graalvm.compiler.nodes.StateSplit; 8098944Sobrienimport org.graalvm.compiler.nodes.StructuredGraph; 8198944Sobrienimport org.graalvm.compiler.nodes.UnwindNode; 8298944Sobrienimport org.graalvm.compiler.nodes.ValueNode; 8398944Sobrienimport org.graalvm.compiler.nodes.ValuePhiNode; 8498944Sobrienimport org.graalvm.compiler.nodes.calc.IsNullNode; 8598944Sobrienimport org.graalvm.compiler.nodes.extended.ForeignCallNode; 8698944Sobrienimport org.graalvm.compiler.nodes.extended.GuardingNode; 8798944Sobrienimport org.graalvm.compiler.nodes.java.ExceptionObjectNode; 8898944Sobrienimport org.graalvm.compiler.nodes.java.MethodCallTargetNode; 8998944Sobrienimport org.graalvm.compiler.nodes.java.MonitorExitNode; 9098944Sobrienimport org.graalvm.compiler.nodes.java.MonitorIdNode; 9198944Sobrienimport org.graalvm.compiler.nodes.spi.Replacements; 9298944Sobrienimport org.graalvm.compiler.nodes.type.StampTool; 9398944Sobrienimport org.graalvm.compiler.nodes.util.GraphUtil; 9498944Sobrienimport org.graalvm.compiler.phases.common.inlining.info.InlineInfo; 9598944Sobrienimport org.graalvm.compiler.phases.common.util.HashSetNodeEventListener; 9698944Sobrienimport org.graalvm.util.EconomicMap; 9798944Sobrienimport org.graalvm.util.EconomicSet; 9898944Sobrienimport org.graalvm.util.Equivalence; 9998944Sobrienimport org.graalvm.util.UnmodifiableEconomicMap; 10098944Sobrienimport org.graalvm.util.UnmodifiableMapCursor; 10198944Sobrien 10298944Sobrienimport jdk.vm.ci.code.BytecodeFrame; 10398944Sobrienimport jdk.vm.ci.meta.Assumptions; 10498944Sobrienimport jdk.vm.ci.meta.DeoptimizationAction; 10598944Sobrienimport jdk.vm.ci.meta.DeoptimizationReason; 10698944Sobrienimport jdk.vm.ci.meta.JavaConstant; 10798944Sobrienimport jdk.vm.ci.meta.JavaKind; 10898944Sobrienimport jdk.vm.ci.meta.ResolvedJavaMethod; 10998944Sobrienimport jdk.vm.ci.meta.ResolvedJavaType; 11098944Sobrien 11198944Sobrienpublic class InliningUtil { 11298944Sobrien 11398944Sobrien private static final String inliningDecisionsScopeString = "InliningDecisions"; 11498944Sobrien 11598944Sobrien /** 11698944Sobrien * Print a HotSpot-style inlining message to the console. 11798944Sobrien */ 11898944Sobrien private static void printInlining(final InlineInfo info, final int inliningDepth, final boolean success, final String msg, final Object... args) { 11998944Sobrien printInlining(info.methodAt(0), info.invoke(), inliningDepth, success, msg, args); 12098944Sobrien } 12198944Sobrien 12298944Sobrien private static void printInlining(final ResolvedJavaMethod method, final Invoke invoke, final int inliningDepth, final boolean success, final String msg, final Object... args) { 12398944Sobrien if (HotSpotPrintInlining.getValue(invoke.asNode().getOptions())) { 12498944Sobrien Util.printInlining(method, invoke.bci(), inliningDepth, success, msg, args); 12598944Sobrien } 12698944Sobrien } 12798944Sobrien 12898944Sobrien public static void logInlinedMethod(InlineInfo info, int inliningDepth, boolean allowLogging, String msg, Object... args) { 12998944Sobrien logInliningDecision(info, inliningDepth, allowLogging, true, msg, args); 13098944Sobrien } 13198944Sobrien 13298944Sobrien public static void logNotInlinedMethod(InlineInfo info, int inliningDepth, String msg, Object... args) { 13398944Sobrien logInliningDecision(info, inliningDepth, true, false, msg, args); 13498944Sobrien } 13598944Sobrien 13698944Sobrien public static void logInliningDecision(InlineInfo info, int inliningDepth, boolean allowLogging, boolean success, String msg, final Object... args) { 13798944Sobrien if (allowLogging) { 13898944Sobrien printInlining(info, inliningDepth, success, msg, args); 13998944Sobrien if (shouldLogInliningDecision()) { 14098944Sobrien logInliningDecision(methodName(info), success, msg, args); 14198944Sobrien } 142130803Smarcel } 143130803Smarcel } 14498944Sobrien 14598944Sobrien @SuppressWarnings("try") 14698944Sobrien public static void logInliningDecision(final String msg, final Object... args) { 14798944Sobrien try (Scope s = Debug.scope(inliningDecisionsScopeString)) { 14898944Sobrien // Can't use log here since we are varargs 14998944Sobrien if (Debug.isLogEnabled()) { 15098944Sobrien Debug.logv(msg, args); 15198944Sobrien } 15298944Sobrien } 15398944Sobrien } 15498944Sobrien 15598944Sobrien public static void logNotInlinedMethod(Invoke invoke, String msg) { 15698944Sobrien if (shouldLogInliningDecision()) { 15798944Sobrien String methodString = invoke.toString(); 15898944Sobrien if (invoke.callTarget() == null) { 15998944Sobrien methodString += " callTarget=null"; 16098944Sobrien } else { 16198944Sobrien String targetName = invoke.callTarget().targetName(); 16298944Sobrien if (!methodString.endsWith(targetName)) { 16398944Sobrien methodString += " " + targetName; 16498944Sobrien } 16598944Sobrien } 16698944Sobrien logInliningDecision(methodString, false, msg, new Object[0]); 16798944Sobrien } 16898944Sobrien } 16998944Sobrien 17098944Sobrien public static void logNotInlined(Invoke invoke, int inliningDepth, ResolvedJavaMethod method, String msg) { 17198944Sobrien logNotInlinedInvoke(invoke, inliningDepth, method, msg, new Object[0]); 17298944Sobrien } 17398944Sobrien 17498944Sobrien public static void logNotInlinedInvoke(Invoke invoke, int inliningDepth, ResolvedJavaMethod method, String msg, Object... args) { 17598944Sobrien printInlining(method, invoke, inliningDepth, false, msg, args); 17698944Sobrien if (shouldLogInliningDecision()) { 17798944Sobrien String methodString = methodName(method, invoke); 17898944Sobrien logInliningDecision(methodString, false, msg, args); 17998944Sobrien } 18098944Sobrien } 18198944Sobrien 18298944Sobrien private static void logInliningDecision(final String methodString, final boolean success, final String msg, final Object... args) { 18398944Sobrien String inliningMsg = "inlining " + methodString + ": " + msg; 18498944Sobrien if (!success) { 18598944Sobrien inliningMsg = "not " + inliningMsg; 18698944Sobrien } 18798944Sobrien logInliningDecision(inliningMsg, args); 18898944Sobrien } 18998944Sobrien 19098944Sobrien @SuppressWarnings("try") 19198944Sobrien public static boolean shouldLogInliningDecision() { 19298944Sobrien try (Scope s = Debug.scope(inliningDecisionsScopeString)) { 19398944Sobrien return Debug.isLogEnabled(); 19498944Sobrien } 19598944Sobrien } 19698944Sobrien 19798944Sobrien private static String methodName(ResolvedJavaMethod method, Invoke invoke) { 19898944Sobrien if (invoke != null && invoke.stateAfter() != null) { 19998944Sobrien return methodName(invoke.stateAfter(), invoke.bci()) + ": " + method.format("%H.%n(%p):%r") + " (" + method.getCodeSize() + " bytes)"; 20098944Sobrien } else { 20198944Sobrien return method.format("%H.%n(%p):%r") + " (" + method.getCodeSize() + " bytes)"; 20298944Sobrien } 20398944Sobrien } 20498944Sobrien 20598944Sobrien private static String methodName(InlineInfo info) { 20698944Sobrien if (info == null) { 20798944Sobrien return "null"; 20898944Sobrien } else if (info.invoke() != null && info.invoke().stateAfter() != null) { 20998944Sobrien return methodName(info.invoke().stateAfter(), info.invoke().bci()) + ": " + info.toString(); 21098944Sobrien } else { 21198944Sobrien return info.toString(); 21298944Sobrien } 21398944Sobrien } 21498944Sobrien 21598944Sobrien private static String methodName(FrameState frameState, int bci) { 21698944Sobrien StringBuilder sb = new StringBuilder(); 21798944Sobrien if (frameState.outerFrameState() != null) { 21898944Sobrien sb.append(methodName(frameState.outerFrameState(), frameState.outerFrameState().bci)); 21998944Sobrien sb.append("->"); 22098944Sobrien } 22198944Sobrien sb.append(frameState.getMethod().format("%h.%n")); 22298944Sobrien sb.append("@").append(bci); 22398944Sobrien return sb.toString(); 22498944Sobrien } 22598944Sobrien 22698944Sobrien public static void replaceInvokeCallTarget(Invoke invoke, StructuredGraph graph, InvokeKind invokeKind, ResolvedJavaMethod targetMethod) { 22798944Sobrien MethodCallTargetNode oldCallTarget = (MethodCallTargetNode) invoke.callTarget(); 22898944Sobrien MethodCallTargetNode newCallTarget = graph.add(new MethodCallTargetNode(invokeKind, targetMethod, oldCallTarget.arguments().toArray(new ValueNode[0]), oldCallTarget.returnStamp(), 22998944Sobrien oldCallTarget.getProfile())); 23098944Sobrien invoke.asNode().replaceFirstInput(oldCallTarget, newCallTarget); 23198944Sobrien } 23298944Sobrien 23398944Sobrien public static PiNode createAnchoredReceiver(StructuredGraph graph, GuardingNode anchor, ResolvedJavaType commonType, ValueNode receiver, boolean exact) { 23498944Sobrien return createAnchoredReceiver(graph, anchor, receiver, 23598944Sobrien exact ? StampFactory.objectNonNull(TypeReference.createExactTrusted(commonType)) : StampFactory.objectNonNull(TypeReference.createTrusted(graph.getAssumptions(), commonType))); 23698944Sobrien } 23798944Sobrien 23898944Sobrien private static PiNode createAnchoredReceiver(StructuredGraph graph, GuardingNode anchor, ValueNode receiver, Stamp stamp) { 23998944Sobrien // to avoid that floating reads on receiver fields float above the type check 24098944Sobrien return graph.unique(new PiNode(receiver, stamp, (ValueNode) anchor)); 24198944Sobrien } 24298944Sobrien 24398944Sobrien /** 24498944Sobrien * @return null iff the check succeeds, otherwise a (non-null) descriptive message. 24598944Sobrien */ 24698944Sobrien public static String checkInvokeConditions(Invoke invoke) { 24798944Sobrien if (invoke.predecessor() == null || !invoke.asNode().isAlive()) { 24898944Sobrien return "the invoke is dead code"; 24998944Sobrien } 25098944Sobrien if (!(invoke.callTarget() instanceof MethodCallTargetNode)) { 25198944Sobrien return "the invoke has already been lowered, or has been created as a low-level node"; 25298944Sobrien } 25398944Sobrien MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget(); 25498944Sobrien if (callTarget.targetMethod() == null) { 25598944Sobrien return "target method is null"; 25698944Sobrien } 25798944Sobrien assert invoke.stateAfter() != null : invoke; 25898944Sobrien if (!invoke.useForInlining()) { 25998944Sobrien return "the invoke is marked to be not used for inlining"; 26098944Sobrien } 26198944Sobrien ValueNode receiver = callTarget.receiver(); 26298944Sobrien if (receiver != null && receiver.isConstant() && receiver.isNullConstant()) { 26398944Sobrien return "receiver is null"; 26498944Sobrien } 26598944Sobrien return null; 26698944Sobrien } 26798944Sobrien 26898944Sobrien /** 26998944Sobrien * Performs an actual inlining, thereby replacing the given invoke with the given inlineGraph. 27098944Sobrien * 27198944Sobrien * @param invoke the invoke that will be replaced 27298944Sobrien * @param inlineGraph the graph that the invoke will be replaced with 27398944Sobrien * @param receiverNullCheck true if a null check needs to be generated for non-static inlinings, 27498944Sobrien * false if no such check is required 27598944Sobrien * @param inlineeMethod the actual method being inlined. Maybe be null for snippets. 27698944Sobrien */ 27798944Sobrien @SuppressWarnings("try") 27898944Sobrien public static UnmodifiableEconomicMap<Node, Node> inline(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck, ResolvedJavaMethod inlineeMethod) { 27998944Sobrien FixedNode invokeNode = invoke.asNode(); 28098944Sobrien StructuredGraph graph = invokeNode.graph(); 28198944Sobrien MethodMetricsInlineeScopeInfo m = MethodMetricsInlineeScopeInfo.create(graph.getOptions()); 28298944Sobrien try (Debug.Scope s = Debug.methodMetricsScope("InlineEnhancement", m, false)) { 28398944Sobrien if (Fingerprint.ENABLED) { 28498944Sobrien Fingerprint.submit("inlining %s into %s: %s", formatGraph(inlineGraph), formatGraph(invoke.asNode().graph()), inlineGraph.getNodes().snapshot()); 28598944Sobrien } 28698944Sobrien final NodeInputList<ValueNode> parameters = invoke.callTarget().arguments(); 28798944Sobrien 28898944Sobrien assert inlineGraph.getGuardsStage().ordinal() >= graph.getGuardsStage().ordinal(); 28998944Sobrien assert !invokeNode.graph().isAfterFloatingReadPhase() : "inline isn't handled correctly after floating reads phase"; 29098944Sobrien 29198944Sobrien if (receiverNullCheck && !((MethodCallTargetNode) invoke.callTarget()).isStatic()) { 29298944Sobrien nonNullReceiver(invoke); 29398944Sobrien } 29498944Sobrien 29598944Sobrien ArrayList<Node> nodes = new ArrayList<>(inlineGraph.getNodes().count()); 29698944Sobrien ArrayList<ReturnNode> returnNodes = new ArrayList<>(4); 29798944Sobrien UnwindNode unwindNode = null; 29898944Sobrien final StartNode entryPointNode = inlineGraph.start(); 29998944Sobrien FixedNode firstCFGNode = entryPointNode.next(); 30098944Sobrien if (firstCFGNode == null) { 30198944Sobrien throw new IllegalStateException("Inlined graph is in invalid state: " + inlineGraph); 30298944Sobrien } 30398944Sobrien for (Node node : inlineGraph.getNodes()) { 30498944Sobrien if (node == entryPointNode || (node == entryPointNode.stateAfter() && node.usages().count() == 1) || node instanceof ParameterNode) { 30598944Sobrien // Do nothing. 30698944Sobrien } else { 30798944Sobrien nodes.add(node); 30898944Sobrien if (node instanceof ReturnNode) { 30998944Sobrien returnNodes.add((ReturnNode) node); 31098944Sobrien } else if (node instanceof UnwindNode) { 31198944Sobrien assert unwindNode == null; 31298944Sobrien unwindNode = (UnwindNode) node; 31398944Sobrien } 31498944Sobrien } 31598944Sobrien } 31698944Sobrien 31798944Sobrien final AbstractBeginNode prevBegin = AbstractBeginNode.prevBegin(invokeNode); 31898944Sobrien DuplicationReplacement localReplacement = new DuplicationReplacement() { 31998944Sobrien 32098944Sobrien @Override 32198944Sobrien public Node replacement(Node node) { 32298944Sobrien if (node instanceof ParameterNode) { 32398944Sobrien return parameters.get(((ParameterNode) node).index()); 32498944Sobrien } else if (node == entryPointNode) { 32598944Sobrien return prevBegin; 32698944Sobrien } 32798944Sobrien return node; 32898944Sobrien } 32998944Sobrien }; 33098944Sobrien 33198944Sobrien assert invokeNode.successors().first() != null : invoke; 33298944Sobrien assert invokeNode.predecessor() != null; 33398944Sobrien 33498944Sobrien UnmodifiableEconomicMap<Node, Node> duplicates = graph.addDuplicates(nodes, inlineGraph, inlineGraph.getNodeCount(), localReplacement); 33598944Sobrien 33698944Sobrien FrameState stateAfter = invoke.stateAfter(); 33798944Sobrien assert stateAfter == null || stateAfter.isAlive(); 33898944Sobrien 33998944Sobrien FrameState stateAtExceptionEdge = null; 34098944Sobrien if (invoke instanceof InvokeWithExceptionNode) { 34198944Sobrien InvokeWithExceptionNode invokeWithException = ((InvokeWithExceptionNode) invoke); 34298944Sobrien if (unwindNode != null) { 34398944Sobrien ExceptionObjectNode obj = (ExceptionObjectNode) invokeWithException.exceptionEdge(); 34498944Sobrien stateAtExceptionEdge = obj.stateAfter(); 34598944Sobrien } 34698944Sobrien } 34798944Sobrien 34898944Sobrien updateSourcePositions(invoke, inlineGraph, duplicates); 34998944Sobrien if (stateAfter != null) { 35098944Sobrien processFrameStates(invoke, inlineGraph, duplicates, stateAtExceptionEdge, returnNodes.size() > 1); 35198944Sobrien int callerLockDepth = stateAfter.nestedLockDepth(); 35298944Sobrien if (callerLockDepth != 0) { 35398944Sobrien for (MonitorIdNode original : inlineGraph.getNodes(MonitorIdNode.TYPE)) { 35498944Sobrien MonitorIdNode monitor = (MonitorIdNode) duplicates.get(original); 35598944Sobrien processMonitorId(invoke.stateAfter(), monitor); 35698944Sobrien } 35798944Sobrien } 35898944Sobrien } else { 35998944Sobrien assert checkContainsOnlyInvalidOrAfterFrameState(duplicates); 36098944Sobrien } 36198944Sobrien 36298944Sobrien firstCFGNode = (FixedNode) duplicates.get(firstCFGNode); 36398944Sobrien for (int i = 0; i < returnNodes.size(); i++) { 36498944Sobrien returnNodes.set(i, (ReturnNode) duplicates.get(returnNodes.get(i))); 36598944Sobrien } 36698944Sobrien if (unwindNode != null) { 36798944Sobrien unwindNode = (UnwindNode) duplicates.get(unwindNode); 36898944Sobrien } 36998944Sobrien 37098944Sobrien finishInlining(invoke, graph, firstCFGNode, returnNodes, unwindNode, inlineGraph.getAssumptions(), inlineGraph); 37198944Sobrien GraphUtil.killCFG(invokeNode); 37298944Sobrien 37398944Sobrien if (Debug.isMethodMeterEnabled() && m != null) { 37498944Sobrien MethodMetricsImpl.recordInlinee(m.getRootMethod(), invoke.asNode().graph().method(), inlineeMethod); 37598944Sobrien } 37698944Sobrien return duplicates; 37798944Sobrien } 37898944Sobrien } 37998944Sobrien 38098944Sobrien /** 38198944Sobrien * Inline {@code inlineGraph} into the current replacoing the node {@code Invoke} and return the 38298944Sobrien * set of nodes which should be canonicalized. The set should only contain nodes which modified 38398944Sobrien * by the inlining since the current graph and {@code inlineGraph} are expected to already be 38498944Sobrien * canonical. 38598944Sobrien * 38698944Sobrien * @param invoke 38798944Sobrien * @param inlineGraph 38898944Sobrien * @param receiverNullCheck 38998944Sobrien * @param inlineeMethod 39098944Sobrien * @return the set of nodes to canonicalize 39198944Sobrien */ 39298944Sobrien @SuppressWarnings("try") 39398944Sobrien public static EconomicSet<Node> inlineForCanonicalization(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck, ResolvedJavaMethod inlineeMethod) { 39498944Sobrien HashSetNodeEventListener listener = new HashSetNodeEventListener(); 39598944Sobrien /* 39698944Sobrien * This code relies on the fact that Graph.addDuplicates doesn't trigger the 39798944Sobrien * NodeEventListener to track only nodes which were modified into the process of inlining 39898944Sobrien * the graph into the current graph. 39998944Sobrien */ 40098944Sobrien try (NodeEventScope nes = invoke.asNode().graph().trackNodeEvents(listener)) { 40198944Sobrien InliningUtil.inline(invoke, inlineGraph, receiverNullCheck, inlineeMethod); 40298944Sobrien } 40398944Sobrien return listener.getNodes(); 40498944Sobrien } 40598944Sobrien 40698944Sobrien private static ValueNode finishInlining(Invoke invoke, StructuredGraph graph, FixedNode firstNode, List<ReturnNode> returnNodes, UnwindNode unwindNode, Assumptions inlinedAssumptions, 40798944Sobrien StructuredGraph inlineGraph) { 40898944Sobrien FixedNode invokeNode = invoke.asNode(); 40998944Sobrien FrameState stateAfter = invoke.stateAfter(); 41098944Sobrien assert stateAfter == null || stateAfter.isAlive(); 41198944Sobrien 41298944Sobrien invokeNode.replaceAtPredecessor(firstNode); 41398944Sobrien 41498944Sobrien if (invoke instanceof InvokeWithExceptionNode) { 41598944Sobrien InvokeWithExceptionNode invokeWithException = ((InvokeWithExceptionNode) invoke); 41698944Sobrien if (unwindNode != null && unwindNode.isAlive()) { 41798944Sobrien assert unwindNode.predecessor() != null; 41898944Sobrien assert invokeWithException.exceptionEdge().successors().count() == 1; 41998944Sobrien ExceptionObjectNode obj = (ExceptionObjectNode) invokeWithException.exceptionEdge(); 42098944Sobrien obj.replaceAtUsages(unwindNode.exception()); 42198944Sobrien Node n = obj.next(); 42298944Sobrien obj.setNext(null); 42398944Sobrien unwindNode.replaceAndDelete(n); 42498944Sobrien 42598944Sobrien obj.replaceAtPredecessor(null); 42698944Sobrien obj.safeDelete(); 42798944Sobrien } else { 42898944Sobrien invokeWithException.killExceptionEdge(); 42998944Sobrien } 43098944Sobrien 43198944Sobrien // get rid of memory kill 43298944Sobrien AbstractBeginNode begin = invokeWithException.next(); 43398944Sobrien if (begin instanceof KillingBeginNode) { 43498944Sobrien AbstractBeginNode newBegin = new BeginNode(); 43598944Sobrien graph.addAfterFixed(begin, graph.add(newBegin)); 43698944Sobrien begin.replaceAtUsages(newBegin); 43798944Sobrien graph.removeFixed(begin); 43898944Sobrien } 43998944Sobrien } else { 44098944Sobrien if (unwindNode != null && unwindNode.isAlive()) { 44198944Sobrien DeoptimizeNode deoptimizeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler)); 44298944Sobrien unwindNode.replaceAndDelete(deoptimizeNode); 443130803Smarcel } 444130803Smarcel } 445130803Smarcel 44698944Sobrien ValueNode returnValue; 44798944Sobrien if (!returnNodes.isEmpty()) { 44898944Sobrien FixedNode n = invoke.next(); 44998944Sobrien invoke.setNext(null); 45098944Sobrien if (returnNodes.size() == 1) { 45198944Sobrien ReturnNode returnNode = returnNodes.get(0); 45298944Sobrien returnValue = returnNode.result(); 45398944Sobrien invokeNode.replaceAtUsages(returnValue); 45498944Sobrien returnNode.replaceAndDelete(n); 45598944Sobrien } else { 45698944Sobrien AbstractMergeNode merge = graph.add(new MergeNode()); 45798944Sobrien merge.setStateAfter(stateAfter); 45898944Sobrien returnValue = mergeReturns(merge, returnNodes); 45998944Sobrien invokeNode.replaceAtUsages(returnValue); 46098944Sobrien merge.setNext(n); 46198944Sobrien } 46298944Sobrien } else { 463130803Smarcel returnValue = null; 464130803Smarcel invokeNode.replaceAtUsages(null); 46598944Sobrien GraphUtil.killCFG(invoke.next()); 46698944Sobrien } 46798944Sobrien 46898944Sobrien // Copy assumptions from inlinee to caller 46998944Sobrien Assumptions assumptions = graph.getAssumptions(); 47098944Sobrien if (assumptions != null) { 47198944Sobrien if (inlinedAssumptions != null) { 47298944Sobrien assumptions.record(inlinedAssumptions); 47398944Sobrien } 47498944Sobrien } else { 47598944Sobrien assert inlinedAssumptions == null : String.format("cannot inline graph (%s) which makes assumptions into a graph (%s) that doesn't", inlineGraph, graph); 47698944Sobrien } 47798944Sobrien 47898944Sobrien // Copy inlined methods from inlinee to caller 47998944Sobrien graph.updateMethods(inlineGraph); 48098944Sobrien 48198944Sobrien // Update the set of accessed fields 48298944Sobrien if (GraalOptions.GeneratePIC.getValue(graph.getOptions())) { 48398944Sobrien graph.updateFields(inlineGraph); 48498944Sobrien } 48598944Sobrien 48698944Sobrien if (inlineGraph.hasUnsafeAccess()) { 48798944Sobrien graph.markUnsafeAccess(); 48898944Sobrien } 48998944Sobrien assert inlineGraph.getSpeculationLog() == null : "Only the root graph should have a speculation log"; 49098944Sobrien 49198944Sobrien return returnValue; 49298944Sobrien } 49398944Sobrien 49498944Sobrien private static String formatGraph(StructuredGraph graph) { 49598944Sobrien if (graph.method() == null) { 49698944Sobrien return graph.name; 49798944Sobrien } 49898944Sobrien return graph.method().format("%H.%n(%p)"); 49998944Sobrien } 50098944Sobrien 50198944Sobrien @SuppressWarnings("try") 50298944Sobrien private static void updateSourcePositions(Invoke invoke, StructuredGraph inlineGraph, UnmodifiableEconomicMap<Node, Node> duplicates) { 50398944Sobrien if (inlineGraph.mayHaveNodeSourcePosition() && invoke.stateAfter() != null) { 50498944Sobrien if (invoke.asNode().getNodeSourcePosition() == null) { 50598944Sobrien // Temporarily ignore the assert below. 50698944Sobrien return; 50798944Sobrien } 50898944Sobrien 50998944Sobrien JavaConstant constantReceiver = invoke.getInvokeKind().hasReceiver() ? invoke.getReceiver().asJavaConstant() : null; 51098944Sobrien NodeSourcePosition invokePos = invoke.asNode().getNodeSourcePosition(); 51198944Sobrien assert invokePos != null : "missing source information"; 51298944Sobrien 51398944Sobrien EconomicMap<NodeSourcePosition, NodeSourcePosition> posMap = EconomicMap.create(Equivalence.DEFAULT); 51498944Sobrien UnmodifiableMapCursor<Node, Node> cursor = duplicates.getEntries(); 51598944Sobrien while (cursor.advance()) { 51698944Sobrien NodeSourcePosition pos = cursor.getKey().getNodeSourcePosition(); 51798944Sobrien if (pos != null) { 51898944Sobrien NodeSourcePosition callerPos = pos.addCaller(constantReceiver, invokePos); 51998944Sobrien if (!posMap.containsKey(callerPos)) { 52098944Sobrien posMap.put(callerPos, callerPos); 52198944Sobrien } 52298944Sobrien cursor.getValue().setNodeSourcePosition(posMap.get(callerPos)); 52398944Sobrien } 52498944Sobrien } 52598944Sobrien } 52698944Sobrien } 52798944Sobrien 52898944Sobrien public static void processMonitorId(FrameState stateAfter, MonitorIdNode monitorIdNode) { 52998944Sobrien if (stateAfter != null) { 53098944Sobrien int callerLockDepth = stateAfter.nestedLockDepth(); 53198944Sobrien monitorIdNode.setLockDepth(monitorIdNode.getLockDepth() + callerLockDepth); 53298944Sobrien } 53398944Sobrien } 53498944Sobrien 53598944Sobrien protected static void processFrameStates(Invoke invoke, StructuredGraph inlineGraph, UnmodifiableEconomicMap<Node, Node> duplicates, FrameState stateAtExceptionEdge, 53698944Sobrien boolean alwaysDuplicateStateAfter) { 53798944Sobrien FrameState stateAtReturn = invoke.stateAfter(); 53898944Sobrien FrameState outerFrameState = null; 53998944Sobrien JavaKind invokeReturnKind = invoke.asNode().getStackKind(); 54098944Sobrien for (FrameState original : inlineGraph.getNodes(FrameState.TYPE)) { 54198944Sobrien FrameState frameState = (FrameState) duplicates.get(original); 54298944Sobrien if (frameState != null && frameState.isAlive()) { 54398944Sobrien if (outerFrameState == null) { 54498944Sobrien outerFrameState = stateAtReturn.duplicateModifiedDuringCall(invoke.bci(), invokeReturnKind); 54598944Sobrien } 54698944Sobrien processFrameState(frameState, invoke, inlineGraph.method(), stateAtExceptionEdge, outerFrameState, alwaysDuplicateStateAfter, invoke.callTarget().targetMethod(), 54798944Sobrien invoke.callTarget().arguments()); 54898944Sobrien } 54998944Sobrien } 55098944Sobrien } 55198944Sobrien 55298944Sobrien public static FrameState processFrameState(FrameState frameState, Invoke invoke, ResolvedJavaMethod inlinedMethod, FrameState stateAtExceptionEdge, FrameState outerFrameState, 55398944Sobrien boolean alwaysDuplicateStateAfter, ResolvedJavaMethod invokeTargetMethod, List<ValueNode> invokeArgsList) { 55498944Sobrien 55598944Sobrien assert outerFrameState == null || !outerFrameState.isDeleted() : outerFrameState; 55698944Sobrien FrameState stateAtReturn = invoke.stateAfter(); 55798944Sobrien JavaKind invokeReturnKind = invoke.asNode().getStackKind(); 55898944Sobrien 55998944Sobrien if (frameState.bci == BytecodeFrame.AFTER_BCI) { 56098944Sobrien FrameState stateAfterReturn = stateAtReturn; 56198944Sobrien if (frameState.getCode() == null) { 562130803Smarcel // This is a frame state for a side effect within an intrinsic 56398944Sobrien // that was parsed for post-parse intrinsification 56498944Sobrien for (Node usage : frameState.usages()) { 56598944Sobrien if (usage instanceof ForeignCallNode) { 56698944Sobrien // A foreign call inside an intrinsic needs to have 56798944Sobrien // the BCI of the invoke being intrinsified 56898944Sobrien ForeignCallNode foreign = (ForeignCallNode) usage; 56998944Sobrien foreign.setBci(invoke.bci()); 57098944Sobrien } 57198944Sobrien } 57298944Sobrien } 57398944Sobrien 57498944Sobrien // pop return kind from invoke's stateAfter and replace with this frameState's return 57598944Sobrien // value (top of stack) 57698944Sobrien if (frameState.stackSize() > 0 && (alwaysDuplicateStateAfter || stateAfterReturn.stackAt(0) != frameState.stackAt(0))) { 57798944Sobrien stateAfterReturn = stateAtReturn.duplicateModified(invokeReturnKind, invokeReturnKind, frameState.stackAt(0)); 57898944Sobrien } 57998944Sobrien 58098944Sobrien // Return value does no longer need to be limited by the monitor exit. 58198944Sobrien for (MonitorExitNode n : frameState.usages().filter(MonitorExitNode.class)) { 58298944Sobrien n.clearEscapedReturnValue(); 58398944Sobrien } 58498944Sobrien 58598944Sobrien frameState.replaceAndDelete(stateAfterReturn); 58698944Sobrien return stateAfterReturn; 58798944Sobrien } else if (stateAtExceptionEdge != null && isStateAfterException(frameState)) { 58898944Sobrien // pop exception object from invoke's stateAfter and replace with this frameState's 58998944Sobrien // exception object (top of stack) 59098944Sobrien FrameState stateAfterException = stateAtExceptionEdge; 59198944Sobrien if (frameState.stackSize() > 0 && stateAtExceptionEdge.stackAt(0) != frameState.stackAt(0)) { 59298944Sobrien stateAfterException = stateAtExceptionEdge.duplicateModified(JavaKind.Object, JavaKind.Object, frameState.stackAt(0)); 59398944Sobrien } 59498944Sobrien frameState.replaceAndDelete(stateAfterException); 59598944Sobrien return stateAfterException; 59698944Sobrien } else if (frameState.bci == BytecodeFrame.UNWIND_BCI || frameState.bci == BytecodeFrame.AFTER_EXCEPTION_BCI) { 59798944Sobrien return handleMissingAfterExceptionFrameState(frameState); 59898944Sobrien } else if (frameState.bci == BytecodeFrame.BEFORE_BCI) { 59998944Sobrien // This is an intrinsic. Deoptimizing within an intrinsic 60098944Sobrien // must re-execute the intrinsified invocation 60198944Sobrien assert frameState.outerFrameState() == null; 60298944Sobrien ValueNode[] invokeArgs = invokeArgsList.isEmpty() ? NO_ARGS : invokeArgsList.toArray(new ValueNode[invokeArgsList.size()]); 60398944Sobrien FrameState stateBeforeCall = stateAtReturn.duplicateModifiedBeforeCall(invoke.bci(), invokeReturnKind, invokeTargetMethod.getSignature().toParameterKinds(!invokeTargetMethod.isStatic()), 60498944Sobrien invokeArgs); 60598944Sobrien frameState.replaceAndDelete(stateBeforeCall); 60698944Sobrien return stateBeforeCall; 60798944Sobrien } else { 60898944Sobrien // only handle the outermost frame states 60998944Sobrien if (frameState.outerFrameState() == null) { 61098944Sobrien assert checkInlineeFrameState(invoke, inlinedMethod, frameState); 61198944Sobrien frameState.setOuterFrameState(outerFrameState); 61298944Sobrien } 61398944Sobrien return frameState; 61498944Sobrien } 61598944Sobrien } 61698944Sobrien 61798944Sobrien static boolean checkInlineeFrameState(Invoke invoke, ResolvedJavaMethod inlinedMethod, FrameState frameState) { 61898944Sobrien assert frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI : frameState; 61998944Sobrien assert frameState.bci != BytecodeFrame.BEFORE_BCI : frameState; 62098944Sobrien assert frameState.bci != BytecodeFrame.UNKNOWN_BCI : frameState; 62198944Sobrien assert frameState.bci != BytecodeFrame.UNWIND_BCI : frameState; 62298944Sobrien if (frameState.bci != BytecodeFrame.INVALID_FRAMESTATE_BCI) { 62398944Sobrien ResolvedJavaMethod method = frameState.getMethod(); 62498944Sobrien if (method.equals(inlinedMethod)) { 62598944Sobrien // Normal inlining expects all outermost inlinee frame states to 62698944Sobrien // denote the inlinee method 62798944Sobrien } else if (method.equals(invoke.callTarget().targetMethod())) { 62898944Sobrien // This occurs when an intrinsic calls back to the original 62998944Sobrien // method to handle a slow path. During parsing of such a 63098944Sobrien // partial intrinsic, these calls are given frame states 63198944Sobrien // that exclude the outer frame state denoting a position 63298944Sobrien // in the intrinsic code. 63398944Sobrien assert inlinedMethod.getAnnotation( 63498944Sobrien MethodSubstitution.class) != null : "expected an intrinsic when inlinee frame state matches method of call target but does not match the method of the inlinee graph: " + 63598944Sobrien frameState; 63698944Sobrien } else if (method.getName().equals(inlinedMethod.getName())) { 63798944Sobrien // This can happen for method substitutions. 63898944Sobrien } else { 63998944Sobrien throw new AssertionError(String.format("inlinedMethod=%s frameState.method=%s frameState=%s invoke.method=%s", inlinedMethod, method, frameState, 640130803Smarcel invoke.callTarget().targetMethod())); 641130803Smarcel } 64298944Sobrien } 64398944Sobrien return true; 64498944Sobrien } 64598944Sobrien 64698944Sobrien private static final ValueNode[] NO_ARGS = {}; 64798944Sobrien 64898944Sobrien private static boolean isStateAfterException(FrameState frameState) { 64998944Sobrien return frameState.bci == BytecodeFrame.AFTER_EXCEPTION_BCI || (frameState.bci == BytecodeFrame.UNWIND_BCI && !frameState.getMethod().isSynchronized()); 65098944Sobrien } 65198944Sobrien 65298944Sobrien public static FrameState handleMissingAfterExceptionFrameState(FrameState nonReplaceableFrameState) { 65398944Sobrien Graph graph = nonReplaceableFrameState.graph(); 65498944Sobrien NodeWorkList workList = graph.createNodeWorkList(); 65598944Sobrien workList.add(nonReplaceableFrameState); 65698944Sobrien for (Node node : workList) { 65798944Sobrien FrameState fs = (FrameState) node; 65898944Sobrien for (Node usage : fs.usages().snapshot()) { 65998944Sobrien if (!usage.isAlive()) { 66098944Sobrien continue; 66198944Sobrien } 66298944Sobrien if (usage instanceof FrameState) { 66398944Sobrien workList.add(usage); 66498944Sobrien } else { 66598944Sobrien StateSplit stateSplit = (StateSplit) usage; 66698944Sobrien FixedNode fixedStateSplit = stateSplit.asNode(); 66798944Sobrien if (fixedStateSplit instanceof AbstractMergeNode) { 66898944Sobrien AbstractMergeNode merge = (AbstractMergeNode) fixedStateSplit; 66998944Sobrien while (merge.isAlive()) { 67098944Sobrien AbstractEndNode end = merge.forwardEnds().first(); 67198944Sobrien DeoptimizeNode deoptimizeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler)); 67298944Sobrien end.replaceAtPredecessor(deoptimizeNode); 67398944Sobrien GraphUtil.killCFG(end); 67498944Sobrien } 67598944Sobrien } else { 67698944Sobrien FixedNode deoptimizeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler)); 67798944Sobrien if (fixedStateSplit instanceof AbstractBeginNode) { 67898944Sobrien deoptimizeNode = BeginNode.begin(deoptimizeNode); 67998944Sobrien } 68098944Sobrien fixedStateSplit.replaceAtPredecessor(deoptimizeNode); 68198944Sobrien GraphUtil.killCFG(fixedStateSplit); 68298944Sobrien } 68398944Sobrien } 68498944Sobrien } 68598944Sobrien } 68698944Sobrien return nonReplaceableFrameState; 68798944Sobrien } 68898944Sobrien 68998944Sobrien public static ValueNode mergeReturns(AbstractMergeNode merge, List<? extends ReturnNode> returnNodes) { 69098944Sobrien return mergeValueProducers(merge, returnNodes, returnNode -> returnNode.result()); 69198944Sobrien } 69298944Sobrien 69398944Sobrien public static <T extends ControlSinkNode> ValueNode mergeValueProducers(AbstractMergeNode merge, List<? extends T> valueProducers, Function<T, ValueNode> valueFunction) { 69498944Sobrien ValueNode singleResult = null; 69598944Sobrien PhiNode phiResult = null; 69698944Sobrien for (T valueProducer : valueProducers) { 69798944Sobrien ValueNode result = valueFunction.apply(valueProducer); 69898944Sobrien if (result != null) { 69998944Sobrien if (phiResult == null && (singleResult == null || singleResult == result)) { 70098944Sobrien /* Only one result value, so no need yet for a phi node. */ 70198944Sobrien singleResult = result; 70298944Sobrien } else if (phiResult == null) { 70398944Sobrien /* Found a second result value, so create phi node. */ 70498944Sobrien phiResult = merge.graph().addWithoutUnique(new ValuePhiNode(result.stamp().unrestricted(), merge)); 70598944Sobrien for (int i = 0; i < merge.forwardEndCount(); i++) { 70698944Sobrien phiResult.addInput(singleResult); 70798944Sobrien } 70898944Sobrien phiResult.addInput(result); 70998944Sobrien 71098944Sobrien } else { 71198944Sobrien /* Multiple return values, just add to existing phi node. */ 71298944Sobrien phiResult.addInput(result); 71398944Sobrien } 71498944Sobrien } 71598944Sobrien 71698944Sobrien // create and wire up a new EndNode 71798944Sobrien EndNode endNode = merge.graph().add(new EndNode()); 71898944Sobrien merge.addForwardEnd(endNode); 71998944Sobrien valueProducer.replaceAndDelete(endNode); 72098944Sobrien } 72198944Sobrien 72298944Sobrien if (phiResult != null) { 72398944Sobrien assert phiResult.verify(); 72498944Sobrien phiResult.inferStamp(); 72598944Sobrien return phiResult; 72698944Sobrien } else { 72798944Sobrien return singleResult; 72898944Sobrien } 72998944Sobrien } 73098944Sobrien 73198944Sobrien /** 73298944Sobrien * Ensure that all states are either {@link BytecodeFrame#INVALID_FRAMESTATE_BCI} or one of 73398944Sobrien * {@link BytecodeFrame#AFTER_BCI} or {@link BytecodeFrame#BEFORE_BCI}. Mixing of before and 73498944Sobrien * after isn't allowed. 73598944Sobrien */ 73698944Sobrien private static boolean checkContainsOnlyInvalidOrAfterFrameState(UnmodifiableEconomicMap<Node, Node> duplicates) { 73798944Sobrien int okBci = BytecodeFrame.INVALID_FRAMESTATE_BCI; 73898944Sobrien for (Node node : duplicates.getValues()) { 73998944Sobrien if (node instanceof FrameState) { 74098944Sobrien FrameState frameState = (FrameState) node; 74198944Sobrien if (frameState.bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) { 74298944Sobrien continue; 74398944Sobrien } 74498944Sobrien if (frameState.bci == BytecodeFrame.AFTER_BCI || frameState.bci == BytecodeFrame.BEFORE_BCI) { 74598944Sobrien if (okBci == BytecodeFrame.INVALID_FRAMESTATE_BCI) { 74698944Sobrien okBci = frameState.bci; 74798944Sobrien } else { 74898944Sobrien assert okBci == frameState.bci : node.toString(Verbosity.Debugger); 74998944Sobrien } 75098944Sobrien } else { 75198944Sobrien assert false : node.toString(Verbosity.Debugger); 75298944Sobrien } 75398944Sobrien } 75498944Sobrien } 75598944Sobrien return true; 75698944Sobrien } 75798944Sobrien 75898944Sobrien /** 75998944Sobrien * Gets the receiver for an invoke, adding a guard if necessary to ensure it is non-null, and 76098944Sobrien * ensuring that the resulting type is compatible with the method being invoked. 76198944Sobrien */ 76298944Sobrien public static ValueNode nonNullReceiver(Invoke invoke) { 76398944Sobrien MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget(); 76498944Sobrien assert !callTarget.isStatic() : callTarget.targetMethod(); 76598944Sobrien StructuredGraph graph = callTarget.graph(); 76698944Sobrien ValueNode oldReceiver = callTarget.arguments().get(0); 76798944Sobrien ValueNode newReceiver = oldReceiver; 76898944Sobrien if (newReceiver.getStackKind() == JavaKind.Object) { 76998944Sobrien 77098944Sobrien if (invoke.getInvokeKind() == InvokeKind.Special) { 77198944Sobrien Stamp paramStamp = newReceiver.stamp(); 77298944Sobrien Stamp stamp = paramStamp.join(StampFactory.object(TypeReference.create(graph.getAssumptions(), callTarget.targetMethod().getDeclaringClass()))); 77398944Sobrien if (!stamp.equals(paramStamp)) { 77498944Sobrien // The verifier and previous optimizations guarantee unconditionally that the 77598944Sobrien // receiver is at least of the type of the method holder for a special invoke. 77698944Sobrien newReceiver = graph.unique(new PiNode(newReceiver, stamp)); 77798944Sobrien } 77898944Sobrien } 77998944Sobrien 78098944Sobrien if (!StampTool.isPointerNonNull(newReceiver)) { 78198944Sobrien LogicNode condition = graph.unique(IsNullNode.create(newReceiver)); 78298944Sobrien FixedGuardNode fixedGuard = graph.add(new FixedGuardNode(condition, NullCheckException, InvalidateReprofile, true)); 78398944Sobrien PiNode nonNullReceiver = graph.unique(new PiNode(newReceiver, StampFactory.objectNonNull(), fixedGuard)); 78498944Sobrien graph.addBeforeFixed(invoke.asNode(), fixedGuard); 78598944Sobrien newReceiver = nonNullReceiver; 78698944Sobrien } 78798944Sobrien } 78898944Sobrien 78998944Sobrien if (newReceiver != oldReceiver) { 79098944Sobrien callTarget.replaceFirstInput(oldReceiver, newReceiver); 791130803Smarcel } 792130803Smarcel return newReceiver; 793130803Smarcel } 794130803Smarcel 795130803Smarcel public static boolean canIntrinsify(Replacements replacements, ResolvedJavaMethod target, int invokeBci) { 796130803Smarcel return replacements.hasSubstitution(target, invokeBci); 797130803Smarcel } 798130803Smarcel 79998944Sobrien public static StructuredGraph getIntrinsicGraph(Replacements replacements, ResolvedJavaMethod target, int invokeBci) { 80098944Sobrien return replacements.getSubstitution(target, invokeBci); 80198944Sobrien } 80298944Sobrien 80398944Sobrien public static FixedWithNextNode inlineMacroNode(Invoke invoke, ResolvedJavaMethod concrete, Class<? extends FixedWithNextNode> macroNodeClass) throws GraalError { 80498944Sobrien StructuredGraph graph = invoke.asNode().graph(); 80598944Sobrien if (!concrete.equals(((MethodCallTargetNode) invoke.callTarget()).targetMethod())) { 80698944Sobrien assert ((MethodCallTargetNode) invoke.callTarget()).invokeKind().hasReceiver(); 80798944Sobrien InliningUtil.replaceInvokeCallTarget(invoke, graph, InvokeKind.Special, concrete); 80898944Sobrien } 80998944Sobrien 81098944Sobrien FixedWithNextNode macroNode = createMacroNodeInstance(macroNodeClass, invoke); 81198944Sobrien 81298944Sobrien CallTargetNode callTarget = invoke.callTarget(); 81398944Sobrien if (invoke instanceof InvokeNode) { 81498944Sobrien graph.replaceFixedWithFixed((InvokeNode) invoke, graph.add(macroNode)); 81598944Sobrien } else { 81698944Sobrien InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke; 81798944Sobrien invokeWithException.killExceptionEdge(); 818 graph.replaceSplitWithFixed(invokeWithException, graph.add(macroNode), invokeWithException.next()); 819 } 820 GraphUtil.killWithUnusedFloatingInputs(callTarget); 821 return macroNode; 822 } 823 824 private static FixedWithNextNode createMacroNodeInstance(Class<? extends FixedWithNextNode> macroNodeClass, Invoke invoke) throws GraalError { 825 try { 826 Constructor<?> cons = macroNodeClass.getDeclaredConstructor(Invoke.class); 827 return (FixedWithNextNode) cons.newInstance(invoke); 828 } catch (ReflectiveOperationException | IllegalArgumentException | SecurityException e) { 829 throw new GraalGraphError(e).addContext(invoke.asNode()).addContext("macroSubstitution", macroNodeClass); 830 } 831 } 832 833 /** 834 * This method exclude InstrumentationNode from inlining heuristics. 835 */ 836 public static int getNodeCount(StructuredGraph graph) { 837 return graph.getNodeCount(); 838 } 839 840} 841