001/*
002 * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.replacements;
024
025import static com.oracle.graal.java.BytecodeParser.Options.*;
026import static jdk.internal.jvmci.common.JVMCIError.*;
027
028import java.util.*;
029
030import jdk.internal.jvmci.code.*;
031import com.oracle.graal.debug.*;
032import jdk.internal.jvmci.meta.*;
033import jdk.internal.jvmci.options.*;
034
035import com.oracle.graal.compiler.common.type.*;
036import com.oracle.graal.graph.*;
037import com.oracle.graal.graph.spi.*;
038import com.oracle.graal.graphbuilderconf.*;
039import com.oracle.graal.graphbuilderconf.InlineInvokePlugin.InlineInfo;
040import com.oracle.graal.graphbuilderconf.InvocationPlugins.InvocationPluginReceiver;
041import com.oracle.graal.java.*;
042import com.oracle.graal.nodeinfo.*;
043import com.oracle.graal.nodes.*;
044import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
045import com.oracle.graal.nodes.extended.*;
046import com.oracle.graal.nodes.java.*;
047import com.oracle.graal.nodes.spi.*;
048import com.oracle.graal.phases.common.inlining.*;
049
050/**
051 * A graph decoder that performs partial evaluation, i.e., that performs method inlining and
052 * canonicalization/simplification of nodes during decoding.
053 *
054 * Inlining and loop explosion are configured via the plugin mechanism also used by the
055 * {@link GraphBuilderPhase}. However, not all callback methods defined in
056 * {@link GraphBuilderContext} are available since decoding is more limited than graph building.
057 *
058 * The standard {@link Canonicalizable#canonical node canonicalization} interface is used to
059 * canonicalize nodes during decoding. Additionally, {@link IfNode branches} and
060 * {@link IntegerSwitchNode switches} with constant conditions are simplified.
061 */
062public abstract class PEGraphDecoder extends SimplifyingGraphDecoder {
063
064    public static class Options {
065        @Option(help = "Maximum inlining depth during partial evaluation before reporting an infinite recursion")//
066        public static final OptionValue<Integer> InliningDepthError = new OptionValue<>(200);
067    }
068
069    protected class PEMethodScope extends MethodScope {
070        /** The state of the caller method. Only non-null during method inlining. */
071        protected final PEMethodScope caller;
072        protected final LoopScope callerLoopScope;
073        protected final ResolvedJavaMethod method;
074        protected final InvokeData invokeData;
075        protected final int inliningDepth;
076
077        protected final LoopExplosionPlugin loopExplosionPlugin;
078        protected final InvocationPlugins invocationPlugins;
079        protected final InlineInvokePlugin[] inlineInvokePlugins;
080        protected final ParameterPlugin parameterPlugin;
081        protected final ValueNode[] arguments;
082
083        protected FrameState outerState;
084        protected FrameState exceptionState;
085        protected ExceptionPlaceholderNode exceptionPlaceholderNode;
086        protected BytecodePosition bytecodePosition;
087
088        protected PEMethodScope(StructuredGraph targetGraph, PEMethodScope caller, LoopScope callerLoopScope, EncodedGraph encodedGraph, ResolvedJavaMethod method, InvokeData invokeData,
089                        int inliningDepth, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin[] inlineInvokePlugins, ParameterPlugin parameterPlugin,
090                        ValueNode[] arguments) {
091            super(targetGraph, encodedGraph, loopExplosionKind(method, loopExplosionPlugin));
092
093            this.caller = caller;
094            this.callerLoopScope = callerLoopScope;
095            this.method = method;
096            this.invokeData = invokeData;
097            this.inliningDepth = inliningDepth;
098            this.loopExplosionPlugin = loopExplosionPlugin;
099            this.invocationPlugins = invocationPlugins;
100            this.inlineInvokePlugins = inlineInvokePlugins;
101            this.parameterPlugin = parameterPlugin;
102            this.arguments = arguments;
103        }
104
105        public boolean isInlinedMethod() {
106            return caller != null;
107        }
108
109        public BytecodePosition getBytecodePosition() {
110            if (bytecodePosition == null) {
111                ensureOuterStateDecoded(this);
112                ensureExceptionStateDecoded(this);
113                bytecodePosition = InliningUtil.processBytecodePosition(invokeData.invoke, null);
114            }
115            return bytecodePosition;
116        }
117    }
118
119    protected class PENonAppendGraphBuilderContext implements GraphBuilderContext {
120        protected final PEMethodScope methodScope;
121        protected final Invoke invoke;
122
123        public PENonAppendGraphBuilderContext(PEMethodScope methodScope, Invoke invoke) {
124            this.methodScope = methodScope;
125            this.invoke = invoke;
126        }
127
128        @Override
129        public BailoutException bailout(String string) {
130            throw new BailoutException(string);
131        }
132
133        @Override
134        public StampProvider getStampProvider() {
135            return stampProvider;
136        }
137
138        @Override
139        public MetaAccessProvider getMetaAccess() {
140            return metaAccess;
141        }
142
143        @Override
144        public ConstantReflectionProvider getConstantReflection() {
145            return constantReflection;
146        }
147
148        @Override
149        public StructuredGraph getGraph() {
150            return methodScope.graph;
151        }
152
153        @Override
154        public int getDepth() {
155            return methodScope.inliningDepth;
156        }
157
158        @Override
159        public IntrinsicContext getIntrinsic() {
160            return null;
161        }
162
163        @Override
164        public <T extends ValueNode> T append(T value) {
165            throw unimplemented();
166        }
167
168        @Override
169        public <T extends ValueNode> T recursiveAppend(T value) {
170            throw unimplemented();
171        }
172
173        @Override
174        public void push(Kind kind, ValueNode value) {
175            throw unimplemented();
176        }
177
178        @Override
179        public void handleReplacedInvoke(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, boolean inlineEverything) {
180            throw unimplemented();
181        }
182
183        @Override
184        public void intrinsify(ResolvedJavaMethod targetMethod, ResolvedJavaMethod substitute, ValueNode[] args) {
185            throw unimplemented();
186        }
187
188        @Override
189        public void setStateAfter(StateSplit stateSplit) {
190            throw unimplemented();
191        }
192
193        @Override
194        public GraphBuilderContext getParent() {
195            throw unimplemented();
196        }
197
198        @Override
199        public ResolvedJavaMethod getMethod() {
200            throw unimplemented();
201        }
202
203        @Override
204        public int bci() {
205            return invoke.bci();
206        }
207
208        @Override
209        public InvokeKind getInvokeKind() {
210            throw unimplemented();
211        }
212
213        @Override
214        public JavaType getInvokeReturnType() {
215            throw unimplemented();
216        }
217    }
218
219    protected class PEAppendGraphBuilderContext extends PENonAppendGraphBuilderContext {
220        protected FixedWithNextNode lastInstr;
221        protected ValueNode pushedNode;
222
223        public PEAppendGraphBuilderContext(PEMethodScope inlineScope, FixedWithNextNode lastInstr) {
224            super(inlineScope, inlineScope.invokeData.invoke);
225            this.lastInstr = lastInstr;
226        }
227
228        @Override
229        public void push(Kind kind, ValueNode value) {
230            if (pushedNode != null) {
231                throw unimplemented("Only one push is supported");
232            }
233            pushedNode = value;
234        }
235
236        @Override
237        public void setStateAfter(StateSplit stateSplit) {
238            Node stateAfter = decodeFloatingNode(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.stateAfterOrderId);
239            getGraph().add(stateAfter);
240            FrameState fs = (FrameState) handleFloatingNodeAfterAdd(methodScope.caller, methodScope.callerLoopScope, stateAfter);
241            stateSplit.setStateAfter(fs);
242        }
243
244        @Override
245        public <T extends ValueNode> T append(T v) {
246            if (v.graph() != null) {
247                return v;
248            }
249            T added = getGraph().addOrUnique(v);
250            if (added == v) {
251                updateLastInstruction(v);
252            }
253            return added;
254        }
255
256        @Override
257        public <T extends ValueNode> T recursiveAppend(T v) {
258            if (v.graph() != null) {
259                return v;
260            }
261            T added = getGraph().addOrUniqueWithInputs(v);
262            if (added == v) {
263                updateLastInstruction(v);
264            }
265            return added;
266        }
267
268        private <T extends ValueNode> void updateLastInstruction(T v) {
269            if (v instanceof FixedNode) {
270                FixedNode fixedNode = (FixedNode) v;
271                lastInstr.setNext(fixedNode);
272                if (fixedNode instanceof FixedWithNextNode) {
273                    FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) fixedNode;
274                    assert fixedWithNextNode.next() == null : "cannot append instruction to instruction which isn't end";
275                    lastInstr = fixedWithNextNode;
276                } else {
277                    lastInstr = null;
278                }
279            }
280        }
281    }
282
283    @NodeInfo
284    static class ExceptionPlaceholderNode extends ValueNode {
285        public static final NodeClass<ExceptionPlaceholderNode> TYPE = NodeClass.create(ExceptionPlaceholderNode.class);
286
287        public ExceptionPlaceholderNode() {
288            super(TYPE, StampFactory.object());
289        }
290    }
291
292    public PEGraphDecoder(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, StampProvider stampProvider, Architecture architecture) {
293        super(metaAccess, constantReflection, stampProvider, true, architecture);
294    }
295
296    protected static LoopExplosionKind loopExplosionKind(ResolvedJavaMethod method, LoopExplosionPlugin loopExplosionPlugin) {
297        if (loopExplosionPlugin == null) {
298            return LoopExplosionKind.NONE;
299        } else if (loopExplosionPlugin.shouldMergeExplosions(method)) {
300            return LoopExplosionKind.MERGE_EXPLODE;
301        } else if (loopExplosionPlugin.shouldExplodeLoops(method)) {
302            return LoopExplosionKind.FULL_EXPLODE;
303        } else {
304            return LoopExplosionKind.NONE;
305        }
306    }
307
308    public void decode(StructuredGraph targetGraph, ResolvedJavaMethod method, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin[] inlineInvokePlugins,
309                    ParameterPlugin parameterPlugin) {
310        PEMethodScope methodScope = new PEMethodScope(targetGraph, null, null, lookupEncodedGraph(method, false), method, null, 0, loopExplosionPlugin, invocationPlugins, inlineInvokePlugins,
311                        parameterPlugin, null);
312        decode(methodScope, null);
313        cleanupGraph(methodScope, null);
314        methodScope.graph.verify();
315    }
316
317    @Override
318    protected void checkLoopExplosionIteration(MethodScope s, LoopScope loopScope) {
319        PEMethodScope methodScope = (PEMethodScope) s;
320
321        if (loopScope.loopIteration > MaximumLoopExplosionCount.getValue()) {
322            String message = "too many loop explosion iterations - does the explosion not terminate for method " + methodScope.method + "?";
323            if (FailedLoopExplosionIsFatal.getValue()) {
324                throw new RuntimeException(message);
325            } else {
326                throw new BailoutException(message);
327            }
328        }
329    }
330
331    @Override
332    protected void handleInvoke(MethodScope s, LoopScope loopScope, InvokeData invokeData) {
333        PEMethodScope methodScope = (PEMethodScope) s;
334
335        /*
336         * Decode the call target, but do not add it to the graph yet. This avoids adding usages for
337         * all the arguments, which are expensive to remove again when we can inline the method.
338         */
339        assert invokeData.invoke.callTarget() == null : "callTarget edge is ignored during decoding of Invoke";
340        CallTargetNode callTarget = (CallTargetNode) decodeFloatingNode(methodScope, loopScope, invokeData.callTargetOrderId);
341        if (!(callTarget instanceof MethodCallTargetNode) || !trySimplifyInvoke(methodScope, loopScope, invokeData, (MethodCallTargetNode) callTarget)) {
342
343            /* We know that we need an invoke, so now we can add the call target to the graph. */
344            methodScope.graph.add(callTarget);
345            registerNode(loopScope, invokeData.callTargetOrderId, callTarget, false, false);
346            super.handleInvoke(methodScope, loopScope, invokeData);
347        }
348    }
349
350    protected boolean trySimplifyInvoke(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, MethodCallTargetNode callTarget) {
351        // attempt to devirtualize the call
352        ResolvedJavaMethod specialCallTarget = MethodCallTargetNode.findSpecialCallTarget(callTarget.invokeKind(), callTarget.receiver(), callTarget.targetMethod(), invokeData.contextType);
353        if (specialCallTarget != null) {
354            callTarget.setTargetMethod(specialCallTarget);
355            callTarget.setInvokeKind(InvokeKind.Special);
356        }
357
358        if (tryInvocationPlugin(methodScope, loopScope, invokeData, callTarget)) {
359            return true;
360        }
361        if (tryInline(methodScope, loopScope, invokeData, callTarget)) {
362            return true;
363        }
364
365        for (InlineInvokePlugin plugin : methodScope.inlineInvokePlugins) {
366            plugin.notifyNotInlined(new PENonAppendGraphBuilderContext(methodScope, invokeData.invoke), callTarget.targetMethod(), invokeData.invoke);
367        }
368        return false;
369    }
370
371    protected boolean tryInvocationPlugin(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, MethodCallTargetNode callTarget) {
372        if (methodScope.invocationPlugins == null) {
373            return false;
374        }
375
376        Invoke invoke = invokeData.invoke;
377
378        ResolvedJavaMethod targetMethod = callTarget.targetMethod();
379        InvocationPlugin invocationPlugin = methodScope.invocationPlugins.lookupInvocation(targetMethod);
380        if (invocationPlugin == null) {
381            return false;
382        }
383
384        ValueNode[] arguments = callTarget.arguments().toArray(new ValueNode[0]);
385        FixedWithNextNode invokePredecessor = (FixedWithNextNode) invoke.asNode().predecessor();
386
387        /* Remove invoke from graph so that invocation plugin can append nodes to the predecessor. */
388        invoke.asNode().replaceAtPredecessor(null);
389
390        PEMethodScope inlineScope = new PEMethodScope(methodScope.graph, methodScope, loopScope, null, targetMethod, invokeData, methodScope.inliningDepth + 1, methodScope.loopExplosionPlugin,
391                        methodScope.invocationPlugins, methodScope.inlineInvokePlugins, null, arguments);
392        PEAppendGraphBuilderContext graphBuilderContext = new PEAppendGraphBuilderContext(inlineScope, invokePredecessor);
393        InvocationPluginReceiver invocationPluginReceiver = new InvocationPluginReceiver(graphBuilderContext);
394
395        if (invocationPlugin.execute(graphBuilderContext, targetMethod, invocationPluginReceiver.init(targetMethod, arguments), arguments)) {
396
397            if (graphBuilderContext.lastInstr != null) {
398                registerNode(loopScope, invokeData.invokeOrderId, graphBuilderContext.pushedNode, true, true);
399                invoke.asNode().replaceAtUsages(graphBuilderContext.pushedNode);
400                graphBuilderContext.lastInstr.setNext(nodeAfterInvoke(methodScope, loopScope, invokeData, AbstractBeginNode.prevBegin(graphBuilderContext.lastInstr)));
401            } else {
402                assert graphBuilderContext.pushedNode == null : "Why push a node when the invoke does not return anyway?";
403                invoke.asNode().replaceAtUsages(null);
404            }
405
406            deleteInvoke(invoke);
407            return true;
408
409        } else {
410            /* Intrinsification failed, restore original state: invoke is in Graph. */
411            invokePredecessor.setNext(invoke.asNode());
412            return false;
413        }
414    }
415
416    protected boolean tryInline(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, MethodCallTargetNode callTarget) {
417        if (!callTarget.invokeKind().isDirect()) {
418            return false;
419        }
420
421        ResolvedJavaMethod targetMethod = callTarget.targetMethod();
422        if (!targetMethod.canBeInlined()) {
423            return false;
424        }
425
426        ValueNode[] arguments = callTarget.arguments().toArray(new ValueNode[0]);
427        GraphBuilderContext graphBuilderContext = new PENonAppendGraphBuilderContext(methodScope, invokeData.invoke);
428
429        for (InlineInvokePlugin plugin : methodScope.inlineInvokePlugins) {
430            InlineInfo inlineInfo = plugin.shouldInlineInvoke(graphBuilderContext, targetMethod, arguments, callTarget.returnType());
431            if (inlineInfo != null) {
432                if (inlineInfo.getMethodToInline() == null) {
433                    return false;
434                } else {
435                    return doInline(methodScope, loopScope, invokeData, inlineInfo, arguments);
436                }
437            }
438        }
439        return false;
440    }
441
442    protected boolean doInline(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, InlineInfo inlineInfo, ValueNode[] arguments) {
443        ResolvedJavaMethod inlineMethod = inlineInfo.getMethodToInline();
444        EncodedGraph graphToInline = lookupEncodedGraph(inlineMethod, inlineInfo.isIntrinsic());
445        if (graphToInline == null) {
446            return false;
447        }
448
449        if (methodScope.inliningDepth > Options.InliningDepthError.getValue()) {
450            throw tooDeepInlining(methodScope);
451        }
452
453        for (InlineInvokePlugin plugin : methodScope.inlineInvokePlugins) {
454            plugin.notifyBeforeInline(inlineMethod);
455        }
456
457        Invoke invoke = invokeData.invoke;
458        FixedNode invokeNode = invoke.asNode();
459        FixedWithNextNode predecessor = (FixedWithNextNode) invokeNode.predecessor();
460        invokeNode.replaceAtPredecessor(null);
461
462        PEMethodScope inlineScope = new PEMethodScope(methodScope.graph, methodScope, loopScope, graphToInline, inlineMethod, invokeData, methodScope.inliningDepth + 1,
463                        methodScope.loopExplosionPlugin, methodScope.invocationPlugins, methodScope.inlineInvokePlugins, null, arguments);
464        /* Do the actual inlining by decoding the inlineMethod */
465        decode(inlineScope, predecessor);
466
467        ValueNode exceptionValue = null;
468        if (inlineScope.unwindNode != null) {
469            exceptionValue = inlineScope.unwindNode.exception();
470        }
471        UnwindNode unwindNode = inlineScope.unwindNode;
472
473        if (invoke instanceof InvokeWithExceptionNode) {
474            InvokeWithExceptionNode invokeWithException = ((InvokeWithExceptionNode) invoke);
475            assert invokeWithException.next() == null;
476            assert invokeWithException.exceptionEdge() == null;
477
478            if (unwindNode != null) {
479                assert unwindNode.predecessor() != null;
480                Node n = makeStubNode(methodScope, loopScope, invokeData.exceptionNextOrderId);
481                unwindNode.replaceAndDelete(n);
482            }
483
484        } else {
485            if (unwindNode != null && !unwindNode.isDeleted()) {
486                DeoptimizeNode deoptimizeNode = methodScope.graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler));
487                unwindNode.replaceAndDelete(deoptimizeNode);
488            }
489        }
490
491        assert invoke.next() == null;
492
493        ValueNode returnValue;
494        List<ReturnNode> returnNodes = inlineScope.returnNodes;
495        if (!returnNodes.isEmpty()) {
496            if (returnNodes.size() == 1) {
497                ReturnNode returnNode = returnNodes.get(0);
498                returnValue = returnNode.result();
499                FixedNode n = nodeAfterInvoke(methodScope, loopScope, invokeData, AbstractBeginNode.prevBegin(returnNode));
500                returnNode.replaceAndDelete(n);
501            } else {
502                AbstractMergeNode merge = methodScope.graph.add(new MergeNode());
503                merge.setStateAfter((FrameState) ensureNodeCreated(methodScope, loopScope, invokeData.stateAfterOrderId));
504                returnValue = InliningUtil.mergeReturns(merge, returnNodes, null);
505                FixedNode n = nodeAfterInvoke(methodScope, loopScope, invokeData, merge);
506                merge.setNext(n);
507            }
508        } else {
509            returnValue = null;
510        }
511        invokeNode.replaceAtUsages(returnValue);
512
513        /*
514         * Usage the handles that we have on the return value and the exception to update the
515         * orderId->Node table.
516         */
517        registerNode(loopScope, invokeData.invokeOrderId, returnValue, true, true);
518        if (invoke instanceof InvokeWithExceptionNode) {
519            registerNode(loopScope, invokeData.exceptionOrderId, exceptionValue, true, true);
520        }
521        if (inlineScope.exceptionPlaceholderNode != null) {
522            inlineScope.exceptionPlaceholderNode.replaceAtUsages(exceptionValue);
523            inlineScope.exceptionPlaceholderNode.safeDelete();
524        }
525        deleteInvoke(invoke);
526
527        for (InlineInvokePlugin plugin : methodScope.inlineInvokePlugins) {
528            plugin.notifyAfterInline(inlineMethod);
529        }
530
531        if (Debug.isDumpEnabled() && DumpDuringGraphBuilding.getValue()) {
532            Debug.dump(methodScope.graph, "Inline finished: " + inlineMethod.getDeclaringClass().getUnqualifiedName() + "." + inlineMethod.getName());
533        }
534        return true;
535    }
536
537    private static RuntimeException tooDeepInlining(PEMethodScope methodScope) {
538        HashMap<ResolvedJavaMethod, Integer> methodCounts = new HashMap<>();
539        for (PEMethodScope cur = methodScope; cur != null; cur = cur.caller) {
540            Integer oldCount = methodCounts.get(cur.method);
541            methodCounts.put(cur.method, oldCount == null ? 1 : oldCount + 1);
542        }
543
544        List<Map.Entry<ResolvedJavaMethod, Integer>> methods = new ArrayList<>(methodCounts.entrySet());
545        methods.sort((e1, e2) -> -Integer.compare(e1.getValue(), e2.getValue()));
546
547        StringBuilder msg = new StringBuilder("Too deep inlining, probably caused by recursive inlining. Inlined methods ordered by inlining frequency:");
548        for (Map.Entry<ResolvedJavaMethod, Integer> entry : methods) {
549            msg.append(System.lineSeparator()).append(entry.getKey().format("%H.%n(%p) [")).append(entry.getValue()).append("]");
550        }
551        throw new BailoutException(msg.toString());
552    }
553
554    public FixedNode nodeAfterInvoke(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, AbstractBeginNode lastBlock) {
555        assert lastBlock.isAlive();
556        FixedNode n;
557        if (invokeData.invoke instanceof InvokeWithExceptionNode) {
558            registerNode(loopScope, invokeData.nextOrderId, lastBlock, false, false);
559            n = makeStubNode(methodScope, loopScope, invokeData.nextNextOrderId);
560        } else {
561            n = makeStubNode(methodScope, loopScope, invokeData.nextOrderId);
562        }
563        return n;
564    }
565
566    private static void deleteInvoke(Invoke invoke) {
567        /*
568         * Clean up unused nodes. We cannot just call killCFG on the invoke node because that can
569         * kill too much: nodes that are decoded later can use values that appear unused by now.
570         */
571        FrameState frameState = invoke.stateAfter();
572        invoke.asNode().safeDelete();
573        assert invoke.callTarget() == null : "must not have been added to the graph yet";
574        if (frameState != null && frameState.hasNoUsages()) {
575            frameState.safeDelete();
576        }
577    }
578
579    protected abstract EncodedGraph lookupEncodedGraph(ResolvedJavaMethod method, boolean isIntrinsic);
580
581    @Override
582    protected void handleFixedNode(MethodScope s, LoopScope loopScope, int nodeOrderId, FixedNode node) {
583        PEMethodScope methodScope = (PEMethodScope) s;
584        if (node instanceof SimpleInfopointNode && methodScope.isInlinedMethod()) {
585            InliningUtil.processSimpleInfopoint(methodScope.invokeData.invoke, (SimpleInfopointNode) node, methodScope.getBytecodePosition());
586        }
587        super.handleFixedNode(s, loopScope, nodeOrderId, node);
588    }
589
590    @Override
591    protected Node handleFloatingNodeBeforeAdd(MethodScope s, LoopScope loopScope, Node node) {
592        PEMethodScope methodScope = (PEMethodScope) s;
593
594        if (node instanceof ParameterNode) {
595            if (methodScope.arguments != null) {
596                Node result = methodScope.arguments[((ParameterNode) node).index()];
597                assert result != null;
598                return result;
599
600            } else if (methodScope.parameterPlugin != null) {
601                GraphBuilderContext graphBuilderContext = new PENonAppendGraphBuilderContext(methodScope, null);
602                Node result = methodScope.parameterPlugin.interceptParameter(graphBuilderContext, ((ParameterNode) node).index(), ((ParameterNode) node).stamp());
603                if (result != null) {
604                    return result;
605                }
606            }
607
608        }
609
610        return super.handleFloatingNodeBeforeAdd(methodScope, loopScope, node);
611    }
612
613    protected void ensureOuterStateDecoded(PEMethodScope methodScope) {
614        if (methodScope.outerState == null && methodScope.caller != null) {
615            FrameState stateAtReturn = methodScope.invokeData.invoke.stateAfter();
616            if (stateAtReturn == null) {
617                stateAtReturn = (FrameState) decodeFloatingNode(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.stateAfterOrderId);
618            }
619
620            Kind invokeReturnKind = methodScope.invokeData.invoke.asNode().getKind();
621            FrameState outerState = stateAtReturn.duplicateModified(methodScope.graph, methodScope.invokeData.invoke.bci(), stateAtReturn.rethrowException(), true, invokeReturnKind, null, null);
622
623            /*
624             * When the encoded graph has methods inlining, we can already have a proper caller
625             * state. If not, we set the caller state here.
626             */
627            if (outerState.outerFrameState() == null && methodScope.caller != null) {
628                ensureOuterStateDecoded(methodScope.caller);
629                outerState.setOuterFrameState(methodScope.caller.outerState);
630            }
631            methodScope.outerState = outerState;
632        }
633    }
634
635    protected void ensureStateAfterDecoded(PEMethodScope methodScope) {
636        if (methodScope.invokeData.invoke.stateAfter() == null) {
637            methodScope.invokeData.invoke.setStateAfter((FrameState) ensureNodeCreated(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.stateAfterOrderId));
638        }
639    }
640
641    protected void ensureExceptionStateDecoded(PEMethodScope methodScope) {
642        if (methodScope.exceptionState == null && methodScope.caller != null && methodScope.invokeData.invoke instanceof InvokeWithExceptionNode) {
643            ensureStateAfterDecoded(methodScope);
644
645            assert methodScope.exceptionPlaceholderNode == null;
646            methodScope.exceptionPlaceholderNode = methodScope.graph.add(new ExceptionPlaceholderNode());
647            registerNode(methodScope.callerLoopScope, methodScope.invokeData.exceptionOrderId, methodScope.exceptionPlaceholderNode, false, false);
648            FrameState exceptionState = (FrameState) ensureNodeCreated(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.exceptionStateOrderId);
649
650            if (exceptionState.outerFrameState() == null && methodScope.caller != null) {
651                ensureOuterStateDecoded(methodScope.caller);
652                exceptionState.setOuterFrameState(methodScope.caller.outerState);
653            }
654            methodScope.exceptionState = exceptionState;
655        }
656    }
657
658    @Override
659    protected Node handleFloatingNodeAfterAdd(MethodScope s, LoopScope loopScope, Node node) {
660        PEMethodScope methodScope = (PEMethodScope) s;
661
662        if (methodScope.isInlinedMethod()) {
663            if (node instanceof FrameState) {
664                FrameState frameState = (FrameState) node;
665
666                ensureOuterStateDecoded(methodScope);
667                if (frameState.bci < 0) {
668                    ensureExceptionStateDecoded(methodScope);
669                }
670                return InliningUtil.processFrameState(frameState, methodScope.invokeData.invoke, methodScope.method, methodScope.exceptionState, methodScope.outerState, true);
671
672            } else if (node instanceof MonitorIdNode) {
673                ensureOuterStateDecoded(methodScope);
674                InliningUtil.processMonitorId(methodScope.outerState, (MonitorIdNode) node);
675                return node;
676            }
677        }
678
679        return node;
680    }
681}