Search in sources :

Example 1 with LoopBeginNode

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

the class OnStackReplacementPhase method run.

@Override
@SuppressWarnings("try")
protected void run(StructuredGraph graph) {
    DebugContext debug = graph.getDebug();
    if (graph.getEntryBCI() == JVMCICompiler.INVOCATION_ENTRY_BCI) {
        // used.
        assert graph.getNodes(EntryMarkerNode.TYPE).isEmpty();
        return;
    }
    debug.dump(DebugContext.DETAILED_LEVEL, graph, "OnStackReplacement initial at bci %d", graph.getEntryBCI());
    EntryMarkerNode osr;
    int maxIterations = -1;
    int iterations = 0;
    final EntryMarkerNode originalOSRNode = getEntryMarker(graph);
    final LoopBeginNode originalOSRLoop = osrLoop(originalOSRNode);
    final boolean currentOSRWithLocks = osrWithLocks(originalOSRNode);
    if (originalOSRLoop == null) {
        /*
             * OSR with Locks: We do not have an OSR loop for the original OSR bci. Therefore we
             * cannot decide where to deopt and which framestate will be used. In the worst case the
             * framestate of the OSR entry would be used.
             */
        throw new PermanentBailoutException("OSR compilation without OSR entry loop.");
    }
    if (!supportOSRWithLocks(graph.getOptions()) && currentOSRWithLocks) {
        throw new PermanentBailoutException("OSR with locks disabled.");
    }
    do {
        osr = getEntryMarker(graph);
        LoopsData loops = new LoopsData(graph);
        // Find the loop that contains the EntryMarker
        Loop<Block> l = loops.getCFG().getNodeToBlock().get(osr).getLoop();
        if (l == null) {
            break;
        }
        iterations++;
        if (maxIterations == -1) {
            maxIterations = l.getDepth();
        } else if (iterations > maxIterations) {
            throw GraalError.shouldNotReachHere();
        }
        // Peel the outermost loop first
        while (l.getParent() != null) {
            l = l.getParent();
        }
        LoopTransformations.peel(loops.loop(l));
        osr.replaceAtUsages(InputType.Guard, AbstractBeginNode.prevBegin((FixedNode) osr.predecessor()));
        for (Node usage : osr.usages().snapshot()) {
            EntryProxyNode proxy = (EntryProxyNode) usage;
            proxy.replaceAndDelete(proxy.value());
        }
        GraphUtil.removeFixedWithUnusedInputs(osr);
        debug.dump(DebugContext.DETAILED_LEVEL, graph, "OnStackReplacement loop peeling result");
    } while (true);
    StartNode start = graph.start();
    FrameState osrState = osr.stateAfter();
    OSRStartNode osrStart;
    try (DebugCloseable context = osr.withNodeSourcePosition()) {
        osr.setStateAfter(null);
        osrStart = graph.add(new OSRStartNode());
        FixedNode next = osr.next();
        osr.setNext(null);
        osrStart.setNext(next);
        graph.setStart(osrStart);
        osrStart.setStateAfter(osrState);
        debug.dump(DebugContext.DETAILED_LEVEL, graph, "OnStackReplacement after setting OSR start");
        final int localsSize = osrState.localsSize();
        final int locksSize = osrState.locksSize();
        for (int i = 0; i < localsSize + locksSize; i++) {
            ValueNode value = null;
            if (i >= localsSize) {
                value = osrState.lockAt(i - localsSize);
            } else {
                value = osrState.localAt(i);
            }
            if (value instanceof EntryProxyNode) {
                EntryProxyNode proxy = (EntryProxyNode) value;
                /*
                     * We need to drop the stamp since the types we see during OSR may be too
                     * precise (if a branch was not parsed for example). In cases when this is
                     * possible, we insert a guard and narrow the OSRLocal stamp at its usages.
                     */
                Stamp narrowedStamp = proxy.value().stamp(NodeView.DEFAULT);
                Stamp unrestrictedStamp = proxy.stamp(NodeView.DEFAULT).unrestricted();
                ValueNode osrLocal;
                if (i >= localsSize) {
                    osrLocal = graph.addOrUnique(new OSRLockNode(i - localsSize, unrestrictedStamp));
                } else {
                    osrLocal = graph.addOrUnique(new OSRLocalNode(i, unrestrictedStamp));
                }
                // Speculate on the OSRLocal stamps that could be more precise.
                OSRLocalSpeculationReason reason = new OSRLocalSpeculationReason(osrState.bci, narrowedStamp, i);
                if (graph.getSpeculationLog().maySpeculate(reason) && osrLocal instanceof OSRLocalNode && value.getStackKind().equals(JavaKind.Object) && !narrowedStamp.isUnrestricted()) {
                    // Add guard.
                    LogicNode check = graph.addOrUniqueWithInputs(InstanceOfNode.createHelper((ObjectStamp) narrowedStamp, osrLocal, null, null));
                    JavaConstant constant = graph.getSpeculationLog().speculate(reason);
                    FixedGuardNode guard = graph.add(new FixedGuardNode(check, DeoptimizationReason.OptimizedTypeCheckViolated, DeoptimizationAction.InvalidateRecompile, constant, false));
                    graph.addAfterFixed(osrStart, guard);
                    // Replace with a more specific type at usages.
                    // We know that we are at the root,
                    // so we need to replace the proxy in the state.
                    proxy.replaceAtMatchingUsages(osrLocal, n -> n == osrState);
                    osrLocal = graph.addOrUnique(new PiNode(osrLocal, narrowedStamp, guard));
                }
                proxy.replaceAndDelete(osrLocal);
            } else {
                assert value == null || value instanceof OSRLocalNode;
            }
        }
        osr.replaceAtUsages(InputType.Guard, osrStart);
    }
    debug.dump(DebugContext.DETAILED_LEVEL, graph, "OnStackReplacement after replacing entry proxies");
    GraphUtil.killCFG(start);
    debug.dump(DebugContext.DETAILED_LEVEL, graph, "OnStackReplacement result");
    new DeadCodeEliminationPhase(Required).apply(graph);
    if (currentOSRWithLocks) {
        OsrWithLocksCount.increment(debug);
        try (DebugCloseable context = osrStart.withNodeSourcePosition()) {
            for (int i = osrState.monitorIdCount() - 1; i >= 0; --i) {
                MonitorIdNode id = osrState.monitorIdAt(i);
                ValueNode lockedObject = osrState.lockAt(i);
                OSRMonitorEnterNode osrMonitorEnter = graph.add(new OSRMonitorEnterNode(lockedObject, id));
                for (Node usage : id.usages()) {
                    if (usage instanceof AccessMonitorNode) {
                        AccessMonitorNode access = (AccessMonitorNode) usage;
                        access.setObject(lockedObject);
                    }
                }
                FixedNode oldNext = osrStart.next();
                oldNext.replaceAtPredecessor(null);
                osrMonitorEnter.setNext(oldNext);
                osrStart.setNext(osrMonitorEnter);
            }
        }
        debug.dump(DebugContext.DETAILED_LEVEL, graph, "After inserting OSR monitor enters");
        /*
             * Ensure balanced monitorenter - monitorexit
             *
             * Ensure that there is no monitor exit without a monitor enter in the graph. If there
             * is one this can only be done by bytecode as we have the monitor enter before the OSR
             * loop but the exit in a path of the loop that must be under a condition, else it will
             * throw an IllegalStateException anyway in the 2.iteration
             */
        for (MonitorExitNode exit : graph.getNodes(MonitorExitNode.TYPE)) {
            MonitorIdNode id = exit.getMonitorId();
            if (id.usages().filter(MonitorEnterNode.class).count() != 1) {
                throw new PermanentBailoutException("Unbalanced monitor enter-exit in OSR compilation with locks. Object is locked before the loop but released inside the loop.");
            }
        }
    }
    debug.dump(DebugContext.DETAILED_LEVEL, graph, "OnStackReplacement result");
    new DeadCodeEliminationPhase(Required).apply(graph);
    /*
         * There must not be any parameter nodes left after OSR compilation.
         */
    assert graph.getNodes(ParameterNode.TYPE).count() == 0 : "OSR Compilation contains references to parameters.";
}
Also used : EntryMarkerNode(org.graalvm.compiler.nodes.EntryMarkerNode) AccessMonitorNode(org.graalvm.compiler.nodes.java.AccessMonitorNode) ObjectStamp(org.graalvm.compiler.core.common.type.ObjectStamp) OSRLockNode(org.graalvm.compiler.nodes.extended.OSRLockNode) MonitorIdNode(org.graalvm.compiler.nodes.java.MonitorIdNode) LoopBeginNode(org.graalvm.compiler.nodes.LoopBeginNode) OSRLocalNode(org.graalvm.compiler.nodes.extended.OSRLocalNode) EntryMarkerNode(org.graalvm.compiler.nodes.EntryMarkerNode) AbstractBeginNode(org.graalvm.compiler.nodes.AbstractBeginNode) EntryProxyNode(org.graalvm.compiler.nodes.EntryProxyNode) FixedGuardNode(org.graalvm.compiler.nodes.FixedGuardNode) PiNode(org.graalvm.compiler.nodes.PiNode) LogicNode(org.graalvm.compiler.nodes.LogicNode) ValueNode(org.graalvm.compiler.nodes.ValueNode) OSRMonitorEnterNode(org.graalvm.compiler.nodes.extended.OSRMonitorEnterNode) MonitorExitNode(org.graalvm.compiler.nodes.java.MonitorExitNode) StartNode(org.graalvm.compiler.nodes.StartNode) InstanceOfNode(org.graalvm.compiler.nodes.java.InstanceOfNode) ParameterNode(org.graalvm.compiler.nodes.ParameterNode) AccessMonitorNode(org.graalvm.compiler.nodes.java.AccessMonitorNode) FixedNode(org.graalvm.compiler.nodes.FixedNode) OSRStartNode(org.graalvm.compiler.nodes.extended.OSRStartNode) MonitorEnterNode(org.graalvm.compiler.nodes.java.MonitorEnterNode) Node(org.graalvm.compiler.graph.Node) JavaConstant(jdk.vm.ci.meta.JavaConstant) FixedNode(org.graalvm.compiler.nodes.FixedNode) PiNode(org.graalvm.compiler.nodes.PiNode) FrameState(org.graalvm.compiler.nodes.FrameState) MonitorExitNode(org.graalvm.compiler.nodes.java.MonitorExitNode) LoopBeginNode(org.graalvm.compiler.nodes.LoopBeginNode) DeadCodeEliminationPhase(org.graalvm.compiler.phases.common.DeadCodeEliminationPhase) PermanentBailoutException(org.graalvm.compiler.core.common.PermanentBailoutException) MonitorIdNode(org.graalvm.compiler.nodes.java.MonitorIdNode) StartNode(org.graalvm.compiler.nodes.StartNode) OSRStartNode(org.graalvm.compiler.nodes.extended.OSRStartNode) LoopsData(org.graalvm.compiler.loop.LoopsData) ObjectStamp(org.graalvm.compiler.core.common.type.ObjectStamp) Stamp(org.graalvm.compiler.core.common.type.Stamp) OSRLocalNode(org.graalvm.compiler.nodes.extended.OSRLocalNode) DebugContext(org.graalvm.compiler.debug.DebugContext) EntryProxyNode(org.graalvm.compiler.nodes.EntryProxyNode) OSRLockNode(org.graalvm.compiler.nodes.extended.OSRLockNode) OSRMonitorEnterNode(org.graalvm.compiler.nodes.extended.OSRMonitorEnterNode) FixedGuardNode(org.graalvm.compiler.nodes.FixedGuardNode) OSRStartNode(org.graalvm.compiler.nodes.extended.OSRStartNode) ValueNode(org.graalvm.compiler.nodes.ValueNode) Block(org.graalvm.compiler.nodes.cfg.Block) LogicNode(org.graalvm.compiler.nodes.LogicNode) DebugCloseable(org.graalvm.compiler.debug.DebugCloseable)

Example 2 with LoopBeginNode

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

the class OnStackReplacementPhase method osrLoop.

private static LoopBeginNode osrLoop(EntryMarkerNode osr) {
    // Check that there is an OSR loop for the OSR begin
    LoopsData loops = new LoopsData(osr.graph());
    Loop<Block> l = loops.getCFG().getNodeToBlock().get(osr).getLoop();
    if (l == null) {
        return null;
    }
    return (LoopBeginNode) l.getHeader().getBeginNode();
}
Also used : LoopsData(org.graalvm.compiler.loop.LoopsData) LoopBeginNode(org.graalvm.compiler.nodes.LoopBeginNode) Block(org.graalvm.compiler.nodes.cfg.Block)

Example 3 with LoopBeginNode

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

the class FinalizeProfileNodesPhase method assignRandomSources.

private static void assignRandomSources(StructuredGraph graph) {
    ValueNode seed = graph.unique(new RandomSeedNode());
    ControlFlowGraph cfg = ControlFlowGraph.compute(graph, false, true, false, false);
    Map<LoopBeginNode, ValueNode> loopRandomValueCache = new HashMap<>();
    for (ProfileNode node : getProfileNodes(graph)) {
        ValueNode random;
        Block block = cfg.blockFor(node);
        Loop<Block> loop = block.getLoop();
        // pseudo-random number generator into the loop
        if (loop != null) {
            LoopBeginNode loopBegin = (LoopBeginNode) loop.getHeader().getBeginNode();
            random = loopRandomValueCache.get(loopBegin);
            if (random == null) {
                PhiNode phi = graph.addWithoutUnique(new ValuePhiNode(seed.stamp(NodeView.DEFAULT), loopBegin));
                phi.addInput(seed);
                // X_{n+1} = a*X_n + c, using glibc-like constants
                ValueNode a = ConstantNode.forInt(1103515245, graph);
                ValueNode c = ConstantNode.forInt(12345, graph);
                ValueNode next = graph.addOrUniqueWithInputs(new AddNode(c, new MulNode(phi, a)));
                for (int i = 0; i < loopBegin.getLoopEndCount(); i++) {
                    phi.addInput(next);
                }
                random = phi;
                loopRandomValueCache.put(loopBegin, random);
            }
        } else {
            // Graal doesn't compile methods with irreducible loops. So all profile nodes that
            // are not in a loop are guaranteed to be executed at most once. We feed the seed
            // value to such nodes directly.
            random = seed;
        }
        node.setRandom(random);
    }
}
Also used : ValuePhiNode(org.graalvm.compiler.nodes.ValuePhiNode) PhiNode(org.graalvm.compiler.nodes.PhiNode) HashMap(java.util.HashMap) ValuePhiNode(org.graalvm.compiler.nodes.ValuePhiNode) LoopBeginNode(org.graalvm.compiler.nodes.LoopBeginNode) ProfileNode(org.graalvm.compiler.hotspot.nodes.profiling.ProfileNode) ControlFlowGraph(org.graalvm.compiler.nodes.cfg.ControlFlowGraph) ValueNode(org.graalvm.compiler.nodes.ValueNode) Block(org.graalvm.compiler.nodes.cfg.Block) RandomSeedNode(org.graalvm.compiler.hotspot.nodes.profiling.RandomSeedNode) MulNode(org.graalvm.compiler.nodes.calc.MulNode) AddNode(org.graalvm.compiler.nodes.calc.AddNode)

Example 4 with LoopBeginNode

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

the class FloatingReadPhase method run.

@Override
@SuppressWarnings("try")
protected void run(StructuredGraph graph) {
    EconomicMap<LoopBeginNode, EconomicSet<LocationIdentity>> modifiedInLoops = null;
    if (graph.hasLoops()) {
        modifiedInLoops = EconomicMap.create(Equivalence.IDENTITY);
        ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, false, false);
        for (Loop<?> l : cfg.getLoops()) {
            HIRLoop loop = (HIRLoop) l;
            processLoop(loop, modifiedInLoops);
        }
    }
    HashSetNodeEventListener listener = new HashSetNodeEventListener(EnumSet.of(NODE_ADDED, ZERO_USAGES));
    try (NodeEventScope nes = graph.trackNodeEvents(listener)) {
        ReentrantNodeIterator.apply(new FloatingReadClosure(modifiedInLoops, createFloatingReads, createMemoryMapNodes), graph.start(), new MemoryMapImpl(graph.start()));
    }
    for (Node n : removeExternallyUsedNodes(listener.getNodes())) {
        if (n.isAlive() && n instanceof FloatingNode) {
            n.replaceAtUsages(null);
            GraphUtil.killWithUnusedFloatingInputs(n);
        }
    }
    if (createFloatingReads) {
        assert !graph.isAfterFloatingReadPhase();
        graph.setAfterFloatingReadPhase(true);
    }
}
Also used : HashSetNodeEventListener(org.graalvm.compiler.phases.common.util.HashSetNodeEventListener) LoopBeginNode(org.graalvm.compiler.nodes.LoopBeginNode) NodeEventScope(org.graalvm.compiler.graph.Graph.NodeEventScope) ControlFlowGraph(org.graalvm.compiler.nodes.cfg.ControlFlowGraph) FloatingAccessNode(org.graalvm.compiler.nodes.memory.FloatingAccessNode) FloatingNode(org.graalvm.compiler.nodes.calc.FloatingNode) MemoryPhiNode(org.graalvm.compiler.nodes.memory.MemoryPhiNode) StartNode(org.graalvm.compiler.nodes.StartNode) FloatingReadNode(org.graalvm.compiler.nodes.memory.FloatingReadNode) MemoryNode(org.graalvm.compiler.nodes.memory.MemoryNode) ReadNode(org.graalvm.compiler.nodes.memory.ReadNode) InvokeWithExceptionNode(org.graalvm.compiler.nodes.InvokeWithExceptionNode) AbstractMergeNode(org.graalvm.compiler.nodes.AbstractMergeNode) MemoryAnchorNode(org.graalvm.compiler.nodes.memory.MemoryAnchorNode) LoopBeginNode(org.graalvm.compiler.nodes.LoopBeginNode) ReturnNode(org.graalvm.compiler.nodes.ReturnNode) FixedNode(org.graalvm.compiler.nodes.FixedNode) AbstractBeginNode(org.graalvm.compiler.nodes.AbstractBeginNode) MemoryMapNode(org.graalvm.compiler.nodes.memory.MemoryMapNode) LoopEndNode(org.graalvm.compiler.nodes.LoopEndNode) FloatableAccessNode(org.graalvm.compiler.nodes.memory.FloatableAccessNode) LoopExitNode(org.graalvm.compiler.nodes.LoopExitNode) Node(org.graalvm.compiler.graph.Node) PhiNode(org.graalvm.compiler.nodes.PhiNode) FloatingNode(org.graalvm.compiler.nodes.calc.FloatingNode) EconomicSet(org.graalvm.collections.EconomicSet) HIRLoop(org.graalvm.compiler.nodes.cfg.HIRLoop)

Example 5 with LoopBeginNode

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

the class GraphUtil method fixSurvivingAffectedMerges.

private static void fixSurvivingAffectedMerges(EconomicSet<Node> markedNodes, EconomicMap<AbstractMergeNode, List<AbstractEndNode>> unmarkedMerges) {
    MapCursor<AbstractMergeNode, List<AbstractEndNode>> cursor = unmarkedMerges.getEntries();
    while (cursor.advance()) {
        AbstractMergeNode merge = cursor.getKey();
        for (AbstractEndNode end : cursor.getValue()) {
            merge.removeEnd(end);
        }
        if (merge.phiPredecessorCount() == 1) {
            if (merge instanceof LoopBeginNode) {
                LoopBeginNode loopBegin = (LoopBeginNode) merge;
                assert merge.forwardEndCount() == 1;
                for (LoopExitNode loopExit : loopBegin.loopExits().snapshot()) {
                    if (markedNodes.contains(loopExit)) {
                        /*
                             * disconnect from loop begin so that reduceDegenerateLoopBegin doesn't
                             * transform it into a new beginNode
                             */
                        loopExit.replaceFirstInput(loopBegin, null);
                    }
                }
                merge.graph().reduceDegenerateLoopBegin(loopBegin);
            } else {
                merge.graph().reduceTrivialMerge(merge);
            }
        } else {
            assert merge.phiPredecessorCount() > 1 : merge;
        }
    }
}
Also used : LoopBeginNode(org.graalvm.compiler.nodes.LoopBeginNode) LoopExitNode(org.graalvm.compiler.nodes.LoopExitNode) AbstractEndNode(org.graalvm.compiler.nodes.AbstractEndNode) List(java.util.List) ArrayList(java.util.ArrayList) AbstractMergeNode(org.graalvm.compiler.nodes.AbstractMergeNode)

Aggregations

LoopBeginNode (org.graalvm.compiler.nodes.LoopBeginNode)61 FixedNode (org.graalvm.compiler.nodes.FixedNode)30 AbstractMergeNode (org.graalvm.compiler.nodes.AbstractMergeNode)26 LoopExitNode (org.graalvm.compiler.nodes.LoopExitNode)24 LoopEndNode (org.graalvm.compiler.nodes.LoopEndNode)23 AbstractBeginNode (org.graalvm.compiler.nodes.AbstractBeginNode)22 Node (org.graalvm.compiler.graph.Node)21 FixedWithNextNode (org.graalvm.compiler.nodes.FixedWithNextNode)21 EndNode (org.graalvm.compiler.nodes.EndNode)20 PhiNode (org.graalvm.compiler.nodes.PhiNode)20 ValueNode (org.graalvm.compiler.nodes.ValueNode)20 AbstractEndNode (org.graalvm.compiler.nodes.AbstractEndNode)19 ControlSplitNode (org.graalvm.compiler.nodes.ControlSplitNode)14 ConstantNode (org.graalvm.compiler.nodes.ConstantNode)13 MergeNode (org.graalvm.compiler.nodes.MergeNode)11 ProxyNode (org.graalvm.compiler.nodes.ProxyNode)10 StructuredGraph (org.graalvm.compiler.nodes.StructuredGraph)10 ArrayList (java.util.ArrayList)9 IfNode (org.graalvm.compiler.nodes.IfNode)9 LogicNode (org.graalvm.compiler.nodes.LogicNode)9