Search in sources :

Example 1 with DeoptEntryNode

use of com.oracle.svm.core.graal.nodes.DeoptEntryNode in project graal by oracle.

the class HostedBytecodeParser method parseAndInlineCallee.

@Override
protected void parseAndInlineCallee(ResolvedJavaMethod targetMethod, ValueNode[] args, IntrinsicContext calleeIntrinsicContext) {
    assert calleeIntrinsicContext != null : "only inlining replacements";
    if (getMethod().compilationInfo.isDeoptEntry(bci(), false, false)) {
        /*
             * Replacements use the frame state before the invoke for all nodes that need a state,
             * i.e., we want to re-execute the whole replacement in case of deoptimization.
             * Therefore, we need to register a DeoptEntryNode before inlining the replacement. The
             * frame state used for the DeoptEntryNode needs to be the same state that will be used
             * later on in the intrinsic.
             */
        FrameState stateAfter = frameState.create(bci(), getNonIntrinsicAncestor(), false, targetMethod.getSignature().toParameterKinds(!targetMethod.isStatic()), args);
        long encodedBci = FrameInfoEncoder.encodeBci(stateAfter.bci, stateAfter.duringCall(), stateAfter.rethrowException());
        if (!deoptEntries.containsKey(encodedBci)) {
            DeoptEntryNode deoptEntry = graph.add(new DeoptEntryNode());
            deoptEntry.setStateAfter(stateAfter);
            insertProxies(deoptEntry, frameState);
            lastInstr.setNext(deoptEntry);
            lastInstr = deoptEntry;
            for (int i = 0; i < args.length; i++) {
                args[i] = createProxyNode(args[i], deoptEntry);
            }
        }
        /*
             * Ensure that no one registers a later state (after the replacement) with the same
             * frame state.
             */
        deoptEntries.put(encodedBci, STICKY_DEOPT_ENTRY);
    }
    super.parseAndInlineCallee(targetMethod, args, calleeIntrinsicContext);
}
Also used : DeoptEntryNode(com.oracle.svm.core.graal.nodes.DeoptEntryNode) FrameState(org.graalvm.compiler.nodes.FrameState)

Example 2 with DeoptEntryNode

use of com.oracle.svm.core.graal.nodes.DeoptEntryNode 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)

Example 3 with DeoptEntryNode

use of com.oracle.svm.core.graal.nodes.DeoptEntryNode in project graal by oracle.

the class HostedBytecodeParser method createDeoptEntry.

private DeoptProxyAnchorNode createDeoptEntry(FrameStateBuilder stateBuilder, FrameState stateAfter, boolean anchorOnly) {
    DeoptProxyAnchorNode deoptEntry = graph.add(anchorOnly ? new DeoptProxyAnchorNode() : new DeoptEntryNode());
    deoptEntry.setStateAfter(stateAfter);
    insertProxies(deoptEntry, stateBuilder);
    return deoptEntry;
}
Also used : DeoptProxyAnchorNode(com.oracle.svm.core.graal.nodes.DeoptProxyAnchorNode) DeoptEntryNode(com.oracle.svm.core.graal.nodes.DeoptEntryNode)

Example 4 with DeoptEntryNode

use of com.oracle.svm.core.graal.nodes.DeoptEntryNode in project graal by oracle.

the class HostedBytecodeParser method finishPrepare.

/**
 * Insert a deopt entry for the graph's start node.
 */
@Override
protected void finishPrepare(FixedWithNextNode startInstr, int bci) {
    super.finishPrepare(startInstr, bci);
    if (getMethod().compilationInfo.isDeoptEntry(bci, false, false)) {
        DeoptEntryNode deoptEntry = append(new DeoptEntryNode());
        deoptEntry.setStateAfter(frameState.create(bci, deoptEntry));
        deoptEntries.put(Long.valueOf(bci), deoptEntry);
    }
}
Also used : DeoptEntryNode(com.oracle.svm.core.graal.nodes.DeoptEntryNode)

Aggregations

DeoptEntryNode (com.oracle.svm.core.graal.nodes.DeoptEntryNode)4 DeoptProxyAnchorNode (com.oracle.svm.core.graal.nodes.DeoptProxyAnchorNode)2 FrameState (org.graalvm.compiler.nodes.FrameState)2 DeoptProxyNode (com.oracle.svm.hosted.nodes.DeoptProxyNode)1 SubstrateMethodCallTargetNode (com.oracle.svm.hosted.nodes.SubstrateMethodCallTargetNode)1 Node (org.graalvm.compiler.graph.Node)1 AbstractBeginNode (org.graalvm.compiler.nodes.AbstractBeginNode)1 FixedNode (org.graalvm.compiler.nodes.FixedNode)1 FixedWithNextNode (org.graalvm.compiler.nodes.FixedWithNextNode)1 Invoke (org.graalvm.compiler.nodes.Invoke)1 KillingBeginNode (org.graalvm.compiler.nodes.KillingBeginNode)1 LoopBeginNode (org.graalvm.compiler.nodes.LoopBeginNode)1 StateSplit (org.graalvm.compiler.nodes.StateSplit)1 ValueNode (org.graalvm.compiler.nodes.ValueNode)1 ExceptionObjectNode (org.graalvm.compiler.nodes.java.ExceptionObjectNode)1 MethodCallTargetNode (org.graalvm.compiler.nodes.java.MethodCallTargetNode)1