Search in sources :

Example 1 with KillingBeginNode

use of org.graalvm.compiler.nodes.KillingBeginNode in project graal by oracle.

the class InliningUtil method finishInlining.

private static ValueNode finishInlining(Invoke invoke, StructuredGraph graph, FixedNode firstNode, List<ReturnNode> returnNodes, UnwindNode unwindNode, Assumptions inlinedAssumptions, StructuredGraph inlineGraph) {
    FixedNode invokeNode = invoke.asNode();
    FrameState stateAfter = invoke.stateAfter();
    assert stateAfter == null || stateAfter.isAlive();
    invokeNode.replaceAtPredecessor(firstNode);
    if (invoke instanceof InvokeWithExceptionNode) {
        InvokeWithExceptionNode invokeWithException = ((InvokeWithExceptionNode) invoke);
        if (unwindNode != null && unwindNode.isAlive()) {
            assert unwindNode.predecessor() != null;
            assert invokeWithException.exceptionEdge().successors().count() == 1;
            ExceptionObjectNode obj = (ExceptionObjectNode) invokeWithException.exceptionEdge();
            obj.replaceAtUsages(unwindNode.exception());
            Node n = obj.next();
            obj.setNext(null);
            unwindNode.replaceAndDelete(n);
            obj.replaceAtPredecessor(null);
            obj.safeDelete();
        } else {
            invokeWithException.killExceptionEdge();
        }
        // get rid of memory kill
        AbstractBeginNode begin = invokeWithException.next();
        if (begin instanceof KillingBeginNode) {
            AbstractBeginNode newBegin = new BeginNode();
            graph.addAfterFixed(begin, graph.add(newBegin));
            begin.replaceAtUsages(newBegin);
            graph.removeFixed(begin);
        }
    } else {
        if (unwindNode != null && unwindNode.isAlive()) {
            DeoptimizeNode deoptimizeNode = addDeoptimizeNode(graph, DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler);
            unwindNode.replaceAndDelete(deoptimizeNode);
        }
    }
    ValueNode returnValue;
    if (!returnNodes.isEmpty()) {
        FixedNode n = invoke.next();
        invoke.setNext(null);
        if (returnNodes.size() == 1) {
            ReturnNode returnNode = returnNodes.get(0);
            returnValue = returnNode.result();
            invokeNode.replaceAtUsages(returnValue);
            returnNode.replaceAndDelete(n);
        } else {
            MergeNode merge = graph.add(new MergeNode());
            merge.setStateAfter(stateAfter);
            returnValue = mergeReturns(merge, returnNodes);
            invokeNode.replaceAtUsages(returnValue);
            if (merge.isPhiAtMerge(returnValue)) {
                fixFrameStates(graph, merge, (PhiNode) returnValue);
            }
            merge.setNext(n);
        }
    } else {
        returnValue = null;
        invokeNode.replaceAtUsages(null);
        GraphUtil.killCFG(invoke.next());
    }
    // Copy assumptions from inlinee to caller
    Assumptions assumptions = graph.getAssumptions();
    if (assumptions != null) {
        if (inlinedAssumptions != null) {
            assumptions.record(inlinedAssumptions);
        }
    } else {
        assert inlinedAssumptions == null : String.format("cannot inline graph (%s) which makes assumptions into a graph (%s) that doesn't", inlineGraph, graph);
    }
    // Copy inlined methods from inlinee to caller
    graph.updateMethods(inlineGraph);
    // Update the set of accessed fields
    if (GraalOptions.GeneratePIC.getValue(graph.getOptions())) {
        graph.updateFields(inlineGraph);
    }
    if (inlineGraph.hasUnsafeAccess()) {
        graph.markUnsafeAccess();
    }
    assert inlineGraph.getSpeculationLog() == null || inlineGraph.getSpeculationLog() == graph.getSpeculationLog() : "Only the root graph should have a speculation log";
    return returnValue;
}
Also used : AbstractMergeNode(org.graalvm.compiler.nodes.AbstractMergeNode) BeginNode(org.graalvm.compiler.nodes.BeginNode) MonitorIdNode(org.graalvm.compiler.nodes.java.MonitorIdNode) MethodCallTargetNode(org.graalvm.compiler.nodes.java.MethodCallTargetNode) ReturnNode(org.graalvm.compiler.nodes.ReturnNode) CallTargetNode(org.graalvm.compiler.nodes.CallTargetNode) AbstractBeginNode(org.graalvm.compiler.nodes.AbstractBeginNode) FixedGuardNode(org.graalvm.compiler.nodes.FixedGuardNode) PiNode(org.graalvm.compiler.nodes.PiNode) LogicNode(org.graalvm.compiler.nodes.LogicNode) ValueNode(org.graalvm.compiler.nodes.ValueNode) MonitorExitNode(org.graalvm.compiler.nodes.java.MonitorExitNode) IsNullNode(org.graalvm.compiler.nodes.calc.IsNullNode) GuardingNode(org.graalvm.compiler.nodes.extended.GuardingNode) KillingBeginNode(org.graalvm.compiler.nodes.KillingBeginNode) StartNode(org.graalvm.compiler.nodes.StartNode) InvokeWithExceptionNode(org.graalvm.compiler.nodes.InvokeWithExceptionNode) ExceptionObjectNode(org.graalvm.compiler.nodes.java.ExceptionObjectNode) InvokeNode(org.graalvm.compiler.nodes.InvokeNode) ParameterNode(org.graalvm.compiler.nodes.ParameterNode) MergeNode(org.graalvm.compiler.nodes.MergeNode) DeoptimizeNode(org.graalvm.compiler.nodes.DeoptimizeNode) FixedNode(org.graalvm.compiler.nodes.FixedNode) AbstractEndNode(org.graalvm.compiler.nodes.AbstractEndNode) UnwindNode(org.graalvm.compiler.nodes.UnwindNode) Node(org.graalvm.compiler.graph.Node) EndNode(org.graalvm.compiler.nodes.EndNode) ForeignCallNode(org.graalvm.compiler.nodes.extended.ForeignCallNode) FixedWithNextNode(org.graalvm.compiler.nodes.FixedWithNextNode) PhiNode(org.graalvm.compiler.nodes.PhiNode) ExceptionObjectNode(org.graalvm.compiler.nodes.java.ExceptionObjectNode) FixedNode(org.graalvm.compiler.nodes.FixedNode) FrameState(org.graalvm.compiler.nodes.FrameState) AbstractBeginNode(org.graalvm.compiler.nodes.AbstractBeginNode) AbstractMergeNode(org.graalvm.compiler.nodes.AbstractMergeNode) MergeNode(org.graalvm.compiler.nodes.MergeNode) ReturnNode(org.graalvm.compiler.nodes.ReturnNode) InvokeWithExceptionNode(org.graalvm.compiler.nodes.InvokeWithExceptionNode) BeginNode(org.graalvm.compiler.nodes.BeginNode) AbstractBeginNode(org.graalvm.compiler.nodes.AbstractBeginNode) KillingBeginNode(org.graalvm.compiler.nodes.KillingBeginNode) ValueNode(org.graalvm.compiler.nodes.ValueNode) Assumptions(jdk.vm.ci.meta.Assumptions) KillingBeginNode(org.graalvm.compiler.nodes.KillingBeginNode) DeoptimizeNode(org.graalvm.compiler.nodes.DeoptimizeNode)

Example 2 with KillingBeginNode

use of org.graalvm.compiler.nodes.KillingBeginNode in project graal by oracle.

the class HostedBytecodeParser method finishInstruction.

/**
 * Insert deopt entries after all state splits.
 */
@Override
protected FixedWithNextNode finishInstruction(FixedWithNextNode instr, FrameStateBuilder stateBuilder) {
    if (getMethod().compilationInfo.isDeoptTarget() && !parsingIntrinsic()) {
        FrameState stateAfter = null;
        if (instr instanceof StateSplit && !(instr instanceof DeoptEntryNode)) {
            /*
                 * The regular case: the instruction is a state split and we insert a DeoptEntryNode
                 * right after it.
                 */
            StateSplit stateSplit = (StateSplit) instr;
            stateAfter = stateSplit.stateAfter();
        } else if (instr instanceof AbstractBeginNode) {
            /*
                 * We are at a block begin. If the block predecessor is a LoopExitNode or an
                 * InvokeWithException (both are state splits), we didn't inserted a deopt entry
                 * yet. So we do it at the begin of a block.
                 *
                 * Note that this only happens if the LoopExitNode/InvokeWithException is the
                 * _single_ predcessor of this block. In case of multiple predecessors, the block
                 * starts with a MergeNode and this is handled like a regular case.
                 */
            Node predecessor = instr.predecessor();
            if (predecessor instanceof KillingBeginNode) {
                /*
                     * This is between an InvokeWithException and the BlockPlaceholderNode.
                     */
                predecessor = predecessor.predecessor();
            }
            if (predecessor instanceof StateSplit && !(predecessor instanceof DeoptEntryNode)) {
                stateAfter = ((StateSplit) predecessor).stateAfter();
            }
        }
        boolean needsDeoptEntry = false;
        boolean needsProxies = false;
        if (stateAfter != null) {
            if (getMethod().compilationInfo.isDeoptEntry(stateAfter.bci, stateAfter.duringCall(), stateAfter.rethrowException())) {
                needsDeoptEntry = true;
                needsProxies = true;
            } else if (instr.predecessor() instanceof Invoke && getMethod().compilationInfo.isDeoptEntry(((Invoke) instr.predecessor()).bci(), true, false)) {
                /*
                     * Invoke nodes can be implicit deoptimization entry points. But we cannot
                     * anchor proxy nodes on invocations: The invoke has two successors (normal and
                     * exception handler), and we need to proxy values at the beginning of both.
                     */
                needsProxies = true;
            } else if (instr instanceof ExceptionObjectNode && getMethod().compilationInfo.isDeoptEntry(((ExceptionObjectNode) instr).stateAfter().bci, true, false)) {
                /*
                     * The predecessor of the ExceptionObjectNode will be an Invoke, but the Invoke
                     * has not been created yet. So the check above for the predecessor does not
                     * trigger.
                     */
                needsProxies = true;
            }
        }
        if (needsProxies) {
            long encodedBci = FrameInfoEncoder.encodeBci(stateAfter.bci, stateAfter.duringCall(), stateAfter.rethrowException());
            DeoptProxyAnchorNode existingDeoptEntry = deoptEntries.get(encodedBci);
            if (existingDeoptEntry != STICKY_DEOPT_ENTRY) {
                if (existingDeoptEntry != null) {
                    /*
                         * Some state splits (i.e. MergeNode and DispatchBeginNode) do not have a
                         * correspondent byte code. Therefore there can be a previously added deopt
                         * entry with the same BCI. For MergeNodes we replace the previous entry
                         * because the new frame state has less live locals.
                         */
                    existingDeoptEntry.replaceAtUsages(null);
                    graph.removeFixed(existingDeoptEntry);
                    deoptEntries.remove(encodedBci);
                    if (existingDeoptEntry instanceof DeoptEntryNode) {
                        /*
                             * We already had a DeoptEntryNode registered earlier for some reason,
                             * so be conservative and create one again (and not just a
                             * DeoptProxyAnchorNode).
                             */
                        needsDeoptEntry = true;
                    }
                }
                assert !deoptEntries.containsKey(encodedBci) : "duplicate deopt entry for encoded BCI " + encodedBci;
                DeoptProxyAnchorNode deoptEntry = createDeoptEntry(stateBuilder, stateAfter, !needsDeoptEntry);
                if (instr instanceof LoopBeginNode) {
                    /*
                         * Loop headers to not have their own bci. Never move a deopt entry for the
                         * loop header down, e.g., into a loop end (that might then end up to be
                         * dead code).
                         */
                    deoptEntries.put(encodedBci, STICKY_DEOPT_ENTRY);
                } else {
                    deoptEntries.put(encodedBci, deoptEntry);
                }
                assert instr.next() == null : "cannot append instruction to instruction which isn't end (" + instr + "->" + instr.next() + ")";
                instr.setNext(deoptEntry);
                return deoptEntry;
            }
        }
    }
    return super.finishInstruction(instr, stateBuilder);
}
Also used : DeoptProxyAnchorNode(com.oracle.svm.core.graal.nodes.DeoptProxyAnchorNode) LoopBeginNode(org.graalvm.compiler.nodes.LoopBeginNode) DeoptEntryNode(com.oracle.svm.core.graal.nodes.DeoptEntryNode) KillingBeginNode(org.graalvm.compiler.nodes.KillingBeginNode) SubstrateMethodCallTargetNode(com.oracle.svm.hosted.nodes.SubstrateMethodCallTargetNode) ExceptionObjectNode(org.graalvm.compiler.nodes.java.ExceptionObjectNode) DeoptEntryNode(com.oracle.svm.core.graal.nodes.DeoptEntryNode) MethodCallTargetNode(org.graalvm.compiler.nodes.java.MethodCallTargetNode) DeoptProxyAnchorNode(com.oracle.svm.core.graal.nodes.DeoptProxyAnchorNode) LoopBeginNode(org.graalvm.compiler.nodes.LoopBeginNode) FixedNode(org.graalvm.compiler.nodes.FixedNode) AbstractBeginNode(org.graalvm.compiler.nodes.AbstractBeginNode) ValueNode(org.graalvm.compiler.nodes.ValueNode) Node(org.graalvm.compiler.graph.Node) FixedWithNextNode(org.graalvm.compiler.nodes.FixedWithNextNode) DeoptProxyNode(com.oracle.svm.hosted.nodes.DeoptProxyNode) ExceptionObjectNode(org.graalvm.compiler.nodes.java.ExceptionObjectNode) KillingBeginNode(org.graalvm.compiler.nodes.KillingBeginNode) FrameState(org.graalvm.compiler.nodes.FrameState) StateSplit(org.graalvm.compiler.nodes.StateSplit) AbstractBeginNode(org.graalvm.compiler.nodes.AbstractBeginNode) Invoke(org.graalvm.compiler.nodes.Invoke)

Aggregations

Node (org.graalvm.compiler.graph.Node)2 AbstractBeginNode (org.graalvm.compiler.nodes.AbstractBeginNode)2 FixedNode (org.graalvm.compiler.nodes.FixedNode)2 FixedWithNextNode (org.graalvm.compiler.nodes.FixedWithNextNode)2 FrameState (org.graalvm.compiler.nodes.FrameState)2 KillingBeginNode (org.graalvm.compiler.nodes.KillingBeginNode)2 ValueNode (org.graalvm.compiler.nodes.ValueNode)2 ExceptionObjectNode (org.graalvm.compiler.nodes.java.ExceptionObjectNode)2 MethodCallTargetNode (org.graalvm.compiler.nodes.java.MethodCallTargetNode)2 DeoptEntryNode (com.oracle.svm.core.graal.nodes.DeoptEntryNode)1 DeoptProxyAnchorNode (com.oracle.svm.core.graal.nodes.DeoptProxyAnchorNode)1 DeoptProxyNode (com.oracle.svm.hosted.nodes.DeoptProxyNode)1 SubstrateMethodCallTargetNode (com.oracle.svm.hosted.nodes.SubstrateMethodCallTargetNode)1 Assumptions (jdk.vm.ci.meta.Assumptions)1 AbstractEndNode (org.graalvm.compiler.nodes.AbstractEndNode)1 AbstractMergeNode (org.graalvm.compiler.nodes.AbstractMergeNode)1 BeginNode (org.graalvm.compiler.nodes.BeginNode)1 CallTargetNode (org.graalvm.compiler.nodes.CallTargetNode)1 DeoptimizeNode (org.graalvm.compiler.nodes.DeoptimizeNode)1 EndNode (org.graalvm.compiler.nodes.EndNode)1