src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/OnStackReplacementPhase.java
Index
Unified diffs
Context diffs
Sdiffs
Patch
New
Old
Previous File
Next File
*** old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/OnStackReplacementPhase.java Mon Mar 20 17:38:49 2017
--- new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/OnStackReplacementPhase.java Mon Mar 20 17:38:49 2017
*** 22,80 ****
--- 22,133 ----
*/
package org.graalvm.compiler.hotspot.phases;
import static org.graalvm.compiler.phases.common.DeadCodeEliminationPhase.Optionality.Required;
! import org.graalvm.compiler.core.common.PermanentBailoutException;
import org.graalvm.compiler.core.common.cfg.Loop;
+ import org.graalvm.compiler.core.common.type.Stamp;
import org.graalvm.compiler.debug.Debug;
+ import org.graalvm.compiler.debug.DebugCounter;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.graph.iterators.NodeIterable;
import org.graalvm.compiler.loop.LoopsData;
import org.graalvm.compiler.loop.phases.LoopTransformations;
import org.graalvm.compiler.nodeinfo.InputType;
import org.graalvm.compiler.nodeinfo.Verbosity;
import org.graalvm.compiler.nodes.AbstractBeginNode;
+ import org.graalvm.compiler.nodes.AbstractLocalNode;
import org.graalvm.compiler.nodes.EntryMarkerNode;
import org.graalvm.compiler.nodes.EntryProxyNode;
import org.graalvm.compiler.nodes.FixedNode;
import org.graalvm.compiler.nodes.FrameState;
+ import org.graalvm.compiler.nodes.LoopBeginNode;
+ import org.graalvm.compiler.nodes.ParameterNode;
import org.graalvm.compiler.nodes.StartNode;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.cfg.Block;
import org.graalvm.compiler.nodes.extended.OSRLocalNode;
+ import org.graalvm.compiler.nodes.extended.OSRLockNode;
+ import org.graalvm.compiler.nodes.extended.OSRMonitorEnterNode;
import org.graalvm.compiler.nodes.extended.OSRStartNode;
+ import org.graalvm.compiler.nodes.java.AccessMonitorNode;
+ import org.graalvm.compiler.nodes.java.MonitorEnterNode;
+ import org.graalvm.compiler.nodes.java.MonitorExitNode;
+ import org.graalvm.compiler.nodes.java.MonitorIdNode;
import org.graalvm.compiler.nodes.util.GraphUtil;
+ import org.graalvm.compiler.options.Option;
+ import org.graalvm.compiler.options.OptionKey;
+ import org.graalvm.compiler.options.OptionType;
+ import org.graalvm.compiler.options.OptionValues;
import org.graalvm.compiler.phases.Phase;
import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
import jdk.vm.ci.runtime.JVMCICompiler;
public class OnStackReplacementPhase extends Phase {
+ public static class Options {
+ // @formatter:off
+ @Option(help = "Deoptimize OSR compiled code when the OSR entry loop is finished " +
+ "if there is no mature profile available for the rest of the method.", type = OptionType.Debug)
+ public static final OptionKey<Boolean> DeoptAfterOSR = new OptionKey<>(true);
+ @Option(help = "Support OSR compilations with locks. If DeoptAfterOSR is true we can per definition not have " +
+ "unbalaced enter/extis mappings. If DeoptAfterOSR is false insert artificial monitor enters after " +
+ "the OSRStart to have balanced enter/exits in the graph.", type = OptionType.Debug)
+ public static final OptionKey<Boolean> SupportOSRWithLocks = new OptionKey<>(true);
+ // @formatter:on
+ }
+
+ private static final DebugCounter OsrWithLocksCount = Debug.counter("OSRWithLocks");
+
+ private static boolean supportOSRWithLocks(OptionValues options) {
+ return Options.SupportOSRWithLocks.getValue(options);
+ }
+
@Override
protected void run(StructuredGraph graph) {
if (graph.getEntryBCI() == JVMCICompiler.INVOCATION_ENTRY_BCI) {
// This happens during inlining in a OSR method, because the same phase plan will be
// used.
assert graph.getNodes(EntryMarkerNode.TYPE).isEmpty();
return;
}
! Debug.dump(Debug.INFO_LOG_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();
*** 102,131 ****
--- 155,239 ----
osr.setNext(null);
osrStart.setNext(next);
graph.setStart(osrStart);
osrStart.setStateAfter(osrState);
for (int i = 0; i < osrState.localsSize(); i++) {
! ValueNode value = osrState.localAt(i);
+ Debug.dump(Debug.INFO_LOG_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).
*/
! proxy.replaceAndDelete(graph.addOrUnique(new OSRLocalNode(i, proxy.stamp().unrestricted())));
! Stamp s = proxy.stamp().unrestricted();
+ AbstractLocalNode osrLocal = null;
+ if (i >= localsSize) {
+ osrLocal = graph.addOrUnique(new OSRLockNode(i - localsSize, s));
+ } else {
+ osrLocal = graph.addOrUnique(new OSRLocalNode(i, s));
+ }
+ proxy.replaceAndDelete(osrLocal);
} else {
assert value == null || value instanceof OSRLocalNode;
}
}
osr.replaceAtUsages(InputType.Guard, osrStart);
assert osr.usages().isEmpty();
+ osr.replaceAtUsages(InputType.Guard, osrStart);
+ Debug.dump(Debug.INFO_LOG_LEVEL, graph, "OnStackReplacement after replacing entry proxies");
GraphUtil.killCFG(start);
+ Debug.dump(Debug.INFO_LOG_LEVEL, graph, "OnStackReplacement result");
+ new DeadCodeEliminationPhase(Required).apply(graph);
+ if (currentOSRWithLocks) {
+ OsrWithLocksCount.increment();
+ 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(Debug.INFO_LOG_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(Debug.INFO_LOG_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.";
}
private static EntryMarkerNode getEntryMarker(StructuredGraph graph) {
NodeIterable<EntryMarkerNode> osrNodes = graph.getNodes(EntryMarkerNode.TYPE);
EntryMarkerNode osr = osrNodes.first();
*** 133,151 ****
--- 241,270 ----
throw new PermanentBailoutException("No OnStackReplacementNode generated");
}
if (osrNodes.count() > 1) {
throw new GraalError("Multiple OnStackReplacementNodes generated");
}
if (osr.stateAfter().locksSize() != 0) {
throw new PermanentBailoutException("OSR with locks not supported");
}
if (osr.stateAfter().stackSize() != 0) {
throw new PermanentBailoutException("OSR with stack entries not supported: %s", osr.stateAfter().toString(Verbosity.Debugger));
}
return osr;
}
+ 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();
+ }
+
+ private static boolean osrWithLocks(EntryMarkerNode osr) {
+ return osr.stateAfter().locksSize() != 0;
+ }
+
@Override
public float codeSizeIncrease() {
return 5.0f;
}
}
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/OnStackReplacementPhase.java
Index
Unified diffs
Context diffs
Sdiffs
Patch
New
Old
Previous File
Next File