< prev index next >

src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/OnStackReplacementPhase.java

Print this page




   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 package org.graalvm.compiler.hotspot.phases;
  24 

  25 import static org.graalvm.compiler.phases.common.DeadCodeEliminationPhase.Optionality.Required;
  26 




  27 import org.graalvm.compiler.core.common.PermanentBailoutException;
  28 import org.graalvm.compiler.core.common.cfg.Loop;

  29 import org.graalvm.compiler.core.common.type.Stamp;
  30 import org.graalvm.compiler.debug.CounterKey;
  31 import org.graalvm.compiler.debug.DebugContext;
  32 import org.graalvm.compiler.debug.GraalError;
  33 import org.graalvm.compiler.graph.Node;
  34 import org.graalvm.compiler.graph.iterators.NodeIterable;
  35 import org.graalvm.compiler.loop.LoopsData;
  36 import org.graalvm.compiler.loop.phases.LoopTransformations;
  37 import org.graalvm.compiler.nodeinfo.InputType;
  38 import org.graalvm.compiler.nodeinfo.Verbosity;
  39 import org.graalvm.compiler.nodes.AbstractBeginNode;
  40 import org.graalvm.compiler.nodes.AbstractLocalNode;
  41 import org.graalvm.compiler.nodes.EntryMarkerNode;
  42 import org.graalvm.compiler.nodes.EntryProxyNode;

  43 import org.graalvm.compiler.nodes.FixedNode;
  44 import org.graalvm.compiler.nodes.FrameState;

  45 import org.graalvm.compiler.nodes.LoopBeginNode;
  46 import org.graalvm.compiler.nodes.ParameterNode;

  47 import org.graalvm.compiler.nodes.StartNode;
  48 import org.graalvm.compiler.nodes.StructuredGraph;
  49 import org.graalvm.compiler.nodes.ValueNode;
  50 import org.graalvm.compiler.nodes.cfg.Block;
  51 import org.graalvm.compiler.nodes.extended.OSRLocalNode;
  52 import org.graalvm.compiler.nodes.extended.OSRLockNode;
  53 import org.graalvm.compiler.nodes.extended.OSRMonitorEnterNode;
  54 import org.graalvm.compiler.nodes.extended.OSRStartNode;
  55 import org.graalvm.compiler.nodes.java.AccessMonitorNode;

  56 import org.graalvm.compiler.nodes.java.MonitorEnterNode;
  57 import org.graalvm.compiler.nodes.java.MonitorExitNode;
  58 import org.graalvm.compiler.nodes.java.MonitorIdNode;
  59 import org.graalvm.compiler.nodes.util.GraphUtil;
  60 import org.graalvm.compiler.options.Option;
  61 import org.graalvm.compiler.options.OptionKey;
  62 import org.graalvm.compiler.options.OptionType;
  63 import org.graalvm.compiler.options.OptionValues;
  64 import org.graalvm.compiler.phases.Phase;
  65 import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
  66 
  67 import jdk.vm.ci.runtime.JVMCICompiler;
  68 
  69 public class OnStackReplacementPhase extends Phase {
  70 
  71     public static class Options {
  72         // @formatter:off
  73         @Option(help = "Deoptimize OSR compiled code when the OSR entry loop is finished " +
  74                        "if there is no mature profile available for the rest of the method.", type = OptionType.Debug)
  75         public static final OptionKey<Boolean> DeoptAfterOSR = new OptionKey<>(true);


 155         FixedNode next = osr.next();
 156         osr.setNext(null);
 157         osrStart.setNext(next);
 158         graph.setStart(osrStart);
 159         osrStart.setStateAfter(osrState);
 160 
 161         debug.dump(DebugContext.DETAILED_LEVEL, graph, "OnStackReplacement after setting OSR start");
 162         final int localsSize = osrState.localsSize();
 163         final int locksSize = osrState.locksSize();
 164 
 165         for (int i = 0; i < localsSize + locksSize; i++) {
 166             ValueNode value = null;
 167             if (i >= localsSize) {
 168                 value = osrState.lockAt(i - localsSize);
 169             } else {
 170                 value = osrState.localAt(i);
 171             }
 172             if (value instanceof EntryProxyNode) {
 173                 EntryProxyNode proxy = (EntryProxyNode) value;
 174                 /*
 175                  * we need to drop the stamp since the types we see during OSR may be too precise
 176                  * (if a branch was not parsed for example).

 177                  */
 178                 Stamp s = proxy.stamp().unrestricted();
 179                 AbstractLocalNode osrLocal = null;

 180                 if (i >= localsSize) {
 181                     osrLocal = graph.addOrUnique(new OSRLockNode(i - localsSize, s));
 182                 } else {
 183                     osrLocal = graph.addOrUnique(new OSRLocalNode(i, s));















 184                 }
 185                 proxy.replaceAndDelete(osrLocal);
 186             } else {
 187                 assert value == null || value instanceof OSRLocalNode;
 188             }
 189         }
 190 
 191         osr.replaceAtUsages(InputType.Guard, osrStart);
 192         debug.dump(DebugContext.DETAILED_LEVEL, graph, "OnStackReplacement after replacing entry proxies");
 193         GraphUtil.killCFG(start);
 194         debug.dump(DebugContext.DETAILED_LEVEL, graph, "OnStackReplacement result");
 195         new DeadCodeEliminationPhase(Required).apply(graph);
 196 
 197         if (currentOSRWithLocks) {
 198             OsrWithLocksCount.increment(debug);
 199             for (int i = osrState.monitorIdCount() - 1; i >= 0; --i) {
 200                 MonitorIdNode id = osrState.monitorIdAt(i);
 201                 ValueNode lockedObject = osrState.lockAt(i);
 202                 OSRMonitorEnterNode osrMonitorEnter = graph.add(new OSRMonitorEnterNode(lockedObject, id));
 203                 for (Node usage : id.usages()) {


 250         return osr;
 251     }
 252 
 253     private static LoopBeginNode osrLoop(EntryMarkerNode osr) {
 254         // Check that there is an OSR loop for the OSR begin
 255         LoopsData loops = new LoopsData(osr.graph());
 256         Loop<Block> l = loops.getCFG().getNodeToBlock().get(osr).getLoop();
 257         if (l == null) {
 258             return null;
 259         }
 260         return (LoopBeginNode) l.getHeader().getBeginNode();
 261     }
 262 
 263     private static boolean osrWithLocks(EntryMarkerNode osr) {
 264         return osr.stateAfter().locksSize() != 0;
 265     }
 266 
 267     @Override
 268     public float codeSizeIncrease() {
 269         return 5.0f;


























 270     }
 271 }


   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 package org.graalvm.compiler.hotspot.phases;
  24 
  25 import static jdk.vm.ci.meta.SpeculationLog.SpeculationReason;
  26 import static org.graalvm.compiler.phases.common.DeadCodeEliminationPhase.Optionality.Required;
  27 
  28 import jdk.vm.ci.meta.DeoptimizationAction;
  29 import jdk.vm.ci.meta.DeoptimizationReason;
  30 import jdk.vm.ci.meta.JavaConstant;
  31 import jdk.vm.ci.meta.JavaKind;
  32 import org.graalvm.compiler.core.common.PermanentBailoutException;
  33 import org.graalvm.compiler.core.common.cfg.Loop;
  34 import org.graalvm.compiler.core.common.type.ObjectStamp;
  35 import org.graalvm.compiler.core.common.type.Stamp;
  36 import org.graalvm.compiler.debug.CounterKey;
  37 import org.graalvm.compiler.debug.DebugContext;
  38 import org.graalvm.compiler.debug.GraalError;
  39 import org.graalvm.compiler.graph.Node;
  40 import org.graalvm.compiler.graph.iterators.NodeIterable;
  41 import org.graalvm.compiler.loop.LoopsData;
  42 import org.graalvm.compiler.loop.phases.LoopTransformations;
  43 import org.graalvm.compiler.nodeinfo.InputType;
  44 import org.graalvm.compiler.nodeinfo.Verbosity;
  45 import org.graalvm.compiler.nodes.AbstractBeginNode;

  46 import org.graalvm.compiler.nodes.EntryMarkerNode;
  47 import org.graalvm.compiler.nodes.EntryProxyNode;
  48 import org.graalvm.compiler.nodes.FixedGuardNode;
  49 import org.graalvm.compiler.nodes.FixedNode;
  50 import org.graalvm.compiler.nodes.FrameState;
  51 import org.graalvm.compiler.nodes.LogicNode;
  52 import org.graalvm.compiler.nodes.LoopBeginNode;
  53 import org.graalvm.compiler.nodes.ParameterNode;
  54 import org.graalvm.compiler.nodes.PiNode;
  55 import org.graalvm.compiler.nodes.StartNode;
  56 import org.graalvm.compiler.nodes.StructuredGraph;
  57 import org.graalvm.compiler.nodes.ValueNode;
  58 import org.graalvm.compiler.nodes.cfg.Block;
  59 import org.graalvm.compiler.nodes.extended.OSRLocalNode;
  60 import org.graalvm.compiler.nodes.extended.OSRLockNode;
  61 import org.graalvm.compiler.nodes.extended.OSRMonitorEnterNode;
  62 import org.graalvm.compiler.nodes.extended.OSRStartNode;
  63 import org.graalvm.compiler.nodes.java.AccessMonitorNode;
  64 import org.graalvm.compiler.nodes.java.InstanceOfNode;
  65 import org.graalvm.compiler.nodes.java.MonitorEnterNode;
  66 import org.graalvm.compiler.nodes.java.MonitorExitNode;
  67 import org.graalvm.compiler.nodes.java.MonitorIdNode;
  68 import org.graalvm.compiler.nodes.util.GraphUtil;
  69 import org.graalvm.compiler.options.Option;
  70 import org.graalvm.compiler.options.OptionKey;
  71 import org.graalvm.compiler.options.OptionType;
  72 import org.graalvm.compiler.options.OptionValues;
  73 import org.graalvm.compiler.phases.Phase;
  74 import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
  75 
  76 import jdk.vm.ci.runtime.JVMCICompiler;
  77 
  78 public class OnStackReplacementPhase extends Phase {
  79 
  80     public static class Options {
  81         // @formatter:off
  82         @Option(help = "Deoptimize OSR compiled code when the OSR entry loop is finished " +
  83                        "if there is no mature profile available for the rest of the method.", type = OptionType.Debug)
  84         public static final OptionKey<Boolean> DeoptAfterOSR = new OptionKey<>(true);


 164         FixedNode next = osr.next();
 165         osr.setNext(null);
 166         osrStart.setNext(next);
 167         graph.setStart(osrStart);
 168         osrStart.setStateAfter(osrState);
 169 
 170         debug.dump(DebugContext.DETAILED_LEVEL, graph, "OnStackReplacement after setting OSR start");
 171         final int localsSize = osrState.localsSize();
 172         final int locksSize = osrState.locksSize();
 173 
 174         for (int i = 0; i < localsSize + locksSize; i++) {
 175             ValueNode value = null;
 176             if (i >= localsSize) {
 177                 value = osrState.lockAt(i - localsSize);
 178             } else {
 179                 value = osrState.localAt(i);
 180             }
 181             if (value instanceof EntryProxyNode) {
 182                 EntryProxyNode proxy = (EntryProxyNode) value;
 183                 /*
 184                  * We need to drop the stamp since the types we see during OSR may be too precise
 185                  * (if a branch was not parsed for example). In cases when this is possible, we
 186                  * insert a guard and narrow the OSRLocal stamp at its usages.
 187                  */
 188                 Stamp narrowedStamp = proxy.value().stamp();
 189                 Stamp unrestrictedStamp = proxy.stamp().unrestricted();
 190                 ValueNode osrLocal;
 191                 if (i >= localsSize) {
 192                     osrLocal = graph.addOrUnique(new OSRLockNode(i - localsSize, unrestrictedStamp));
 193                 } else {
 194                     osrLocal = graph.addOrUnique(new OSRLocalNode(i, unrestrictedStamp));
 195                 }
 196                 // Speculate on the OSRLocal stamps that could be more precise.
 197                 OSRLocalSpeculationReason reason = new OSRLocalSpeculationReason(osrState.bci, narrowedStamp, i);
 198                 if (graph.getSpeculationLog().maySpeculate(reason) && osrLocal instanceof OSRLocalNode && value.getStackKind().equals(JavaKind.Object) && !narrowedStamp.isUnrestricted()) {
 199                     // Add guard.
 200                     LogicNode check = graph.addOrUniqueWithInputs(InstanceOfNode.createHelper((ObjectStamp) narrowedStamp, osrLocal, null, null));
 201                     JavaConstant constant = graph.getSpeculationLog().speculate(reason);
 202                     FixedGuardNode guard = graph.add(new FixedGuardNode(check, DeoptimizationReason.OptimizedTypeCheckViolated, DeoptimizationAction.InvalidateRecompile, constant, false));
 203                     graph.addAfterFixed(osrStart, guard);
 204 
 205                     // Replace with a more specific type at usages.
 206                     // We know that we are at the root,
 207                     // so we need to replace the proxy in the state.
 208                     proxy.replaceAtMatchingUsages(osrLocal, n -> n == osrState);
 209                     osrLocal = graph.addOrUnique(new PiNode(osrLocal, narrowedStamp, guard));
 210                 }
 211                 proxy.replaceAndDelete(osrLocal);
 212             } else {
 213                 assert value == null || value instanceof OSRLocalNode;
 214             }
 215         }
 216 
 217         osr.replaceAtUsages(InputType.Guard, osrStart);
 218         debug.dump(DebugContext.DETAILED_LEVEL, graph, "OnStackReplacement after replacing entry proxies");
 219         GraphUtil.killCFG(start);
 220         debug.dump(DebugContext.DETAILED_LEVEL, graph, "OnStackReplacement result");
 221         new DeadCodeEliminationPhase(Required).apply(graph);
 222 
 223         if (currentOSRWithLocks) {
 224             OsrWithLocksCount.increment(debug);
 225             for (int i = osrState.monitorIdCount() - 1; i >= 0; --i) {
 226                 MonitorIdNode id = osrState.monitorIdAt(i);
 227                 ValueNode lockedObject = osrState.lockAt(i);
 228                 OSRMonitorEnterNode osrMonitorEnter = graph.add(new OSRMonitorEnterNode(lockedObject, id));
 229                 for (Node usage : id.usages()) {


 276         return osr;
 277     }
 278 
 279     private static LoopBeginNode osrLoop(EntryMarkerNode osr) {
 280         // Check that there is an OSR loop for the OSR begin
 281         LoopsData loops = new LoopsData(osr.graph());
 282         Loop<Block> l = loops.getCFG().getNodeToBlock().get(osr).getLoop();
 283         if (l == null) {
 284             return null;
 285         }
 286         return (LoopBeginNode) l.getHeader().getBeginNode();
 287     }
 288 
 289     private static boolean osrWithLocks(EntryMarkerNode osr) {
 290         return osr.stateAfter().locksSize() != 0;
 291     }
 292 
 293     @Override
 294     public float codeSizeIncrease() {
 295         return 5.0f;
 296     }
 297 
 298     private static class OSRLocalSpeculationReason implements SpeculationReason {
 299         private int bci;
 300         private Stamp speculatedStamp;
 301         private int localIndex;
 302 
 303         OSRLocalSpeculationReason(int bci, Stamp speculatedStamp, int localIndex) {
 304             this.bci = bci;
 305             this.speculatedStamp = speculatedStamp;
 306             this.localIndex = localIndex;
 307         }
 308 
 309         @Override
 310         public boolean equals(Object obj) {
 311             if (obj instanceof OSRLocalSpeculationReason) {
 312                 OSRLocalSpeculationReason that = (OSRLocalSpeculationReason) obj;
 313                 return this.bci == that.bci && this.speculatedStamp.equals(that.speculatedStamp) && this.localIndex == that.localIndex;
 314             }
 315             return false;
 316         }
 317 
 318         @Override
 319         public int hashCode() {
 320             return (bci << 16) ^ speculatedStamp.hashCode() ^ localIndex;
 321         }
 322     }
 323 }
< prev index next >