|
67 | 67 | import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin;
|
68 | 68 | import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext;
|
69 | 69 | import org.graalvm.compiler.nodes.graphbuilderconf.NodePlugin;
|
| 70 | +import org.graalvm.compiler.nodes.java.ExceptionObjectNode; |
70 | 71 | import org.graalvm.compiler.options.Option;
|
71 | 72 | import org.graalvm.compiler.options.OptionValues;
|
72 | 73 | import org.graalvm.compiler.phases.OptimisticOptimizations;
|
|
101 | 102 | import com.oracle.svm.core.ParsingReason;
|
102 | 103 | import com.oracle.svm.core.config.ConfigurationValues;
|
103 | 104 | import com.oracle.svm.core.graal.nodes.DeoptEntryNode;
|
| 105 | +import com.oracle.svm.core.graal.nodes.DeoptEntrySupport; |
| 106 | +import com.oracle.svm.core.graal.nodes.DeoptProxyAnchorNode; |
104 | 107 | import com.oracle.svm.core.graal.nodes.InlinedInvokeArgumentsNode;
|
105 | 108 | import com.oracle.svm.core.graal.stackvalue.StackValueNode;
|
106 | 109 | import com.oracle.svm.core.option.HostedOptionKey;
|
|
126 | 129 | import com.oracle.svm.hosted.phases.InlineBeforeAnalysisPolicyUtils.AlwaysInlineScope;
|
127 | 130 | import com.oracle.svm.hosted.phases.StrengthenStampsPhase;
|
128 | 131 |
|
| 132 | +import jdk.vm.ci.code.BytecodeFrame; |
129 | 133 | import jdk.vm.ci.code.BytecodePosition;
|
130 | 134 | import jdk.vm.ci.meta.JavaKind;
|
131 | 135 | import jdk.vm.ci.meta.ResolvedJavaMethod;
|
|
138 | 142 | public class ParseOnceRuntimeCompilationFeature extends RuntimeCompilationFeature implements Feature, RuntimeCompilationSupport {
|
139 | 143 |
|
140 | 144 | public static class Options {
|
141 |
| - /* |
142 |
| - * Note this phase is currently overly aggressive and can illegally remove proxies. This |
143 |
| - * will be fixed in GR-44459. |
144 |
| - */ |
145 | 145 | @Option(help = "Remove Deopt(Entries,Anchors,Proxies) determined to be unneeded after the runtime compiled graphs have been finalized.")//
|
146 |
| - public static final HostedOptionKey<Boolean> RemoveUnneededDeoptSupport = new HostedOptionKey<>(false); |
| 146 | + public static final HostedOptionKey<Boolean> RemoveUnneededDeoptSupport = new HostedOptionKey<>(true); |
147 | 147 |
|
148 | 148 | @Option(help = "Perform InlineBeforeAnalysis on runtime compiled methods")//
|
149 | 149 | public static final HostedOptionKey<Boolean> RuntimeCompilationInlineBeforeAnalysis = new HostedOptionKey<>(true);
|
@@ -1216,58 +1216,103 @@ public boolean insertPlaceholderParamAndReturnFlows(MultiMethod.MultiMethodKey m
|
1216 | 1216 | }
|
1217 | 1217 |
|
1218 | 1218 | /**
|
1219 |
| - * Removes Deoptimizations Entrypoints which are deemed to be unnecessary after the runtime |
1220 |
| - * compilation methods are optimized. |
| 1219 | + * Removes {@link DeoptEntryNode}s, {@link DeoptProxyAnchorNode}s, and {@link DeoptProxyNode}s |
| 1220 | + * which are determined to be unnecessary after the runtime compilation methods are optimized. |
1221 | 1221 | */
|
1222 | 1222 | static class RemoveUnneededDeoptSupport extends Phase {
|
| 1223 | + enum RemovalDecision { |
| 1224 | + KEEP, |
| 1225 | + PROXIFY, |
| 1226 | + REMOVE |
| 1227 | + } |
1223 | 1228 |
|
1224 | 1229 | @Override
|
1225 | 1230 | protected void run(StructuredGraph graph) {
|
1226 |
| - EconomicMap<StateSplit, Boolean> decisionCache = EconomicMap.create(); |
| 1231 | + EconomicMap<StateSplit, RemovalDecision> decisionCache = EconomicMap.create(); |
1227 | 1232 |
|
1228 | 1233 | // First go through and delete all unneeded proxies
|
1229 | 1234 | for (DeoptProxyNode proxyNode : graph.getNodes(DeoptProxyNode.TYPE).snapshot()) {
|
1230 | 1235 | ValueNode proxyPoint = proxyNode.getProxyPoint();
|
1231 | 1236 | if (proxyPoint instanceof StateSplit) {
|
1232 |
| - if (proxyPoint instanceof DeoptEntryNode && shouldRemove((StateSplit) proxyPoint, decisionCache)) { |
| 1237 | + if (getDecision((StateSplit) proxyPoint, decisionCache) == RemovalDecision.REMOVE) { |
1233 | 1238 | proxyNode.replaceAtAllUsages(proxyNode.getOriginalNode(), true);
|
1234 | 1239 | proxyNode.safeDelete();
|
1235 | 1240 | }
|
1236 | 1241 | }
|
1237 | 1242 | }
|
1238 | 1243 |
|
1239 |
| - // Next remove all unneeded DeoptEntryNodes |
| 1244 | + // Next, remove all unneeded DeoptEntryNodes |
1240 | 1245 | for (DeoptEntryNode deoptEntry : graph.getNodes().filter(DeoptEntryNode.class).snapshot()) {
|
1241 |
| - if (shouldRemove(deoptEntry, decisionCache)) { |
1242 |
| - deoptEntry.killExceptionEdge(); |
1243 |
| - graph.removeSplit(deoptEntry, deoptEntry.getPrimarySuccessor()); |
| 1246 | + switch (getDecision(deoptEntry, decisionCache)) { |
| 1247 | + case REMOVE -> { |
| 1248 | + deoptEntry.killExceptionEdge(); |
| 1249 | + graph.removeSplit(deoptEntry, deoptEntry.getPrimarySuccessor()); |
| 1250 | + } |
| 1251 | + case PROXIFY -> { |
| 1252 | + deoptEntry.killExceptionEdge(); |
| 1253 | + DeoptProxyAnchorNode newAnchor = graph.add(new DeoptProxyAnchorNode(deoptEntry.getProxifiedInvokeBci())); |
| 1254 | + newAnchor.setStateAfter(deoptEntry.stateAfter()); |
| 1255 | + graph.replaceSplitWithFixed(deoptEntry, newAnchor, deoptEntry.getPrimarySuccessor()); |
| 1256 | + } |
| 1257 | + } |
| 1258 | + } |
| 1259 | + |
| 1260 | + // Finally, remove all unneeded DeoptProxyAnchorNodes |
| 1261 | + for (DeoptProxyAnchorNode proxyAnchor : graph.getNodes().filter(DeoptProxyAnchorNode.class).snapshot()) { |
| 1262 | + if (getDecision(proxyAnchor, decisionCache) == RemovalDecision.REMOVE) { |
| 1263 | + graph.removeFixed(proxyAnchor); |
1244 | 1264 | }
|
1245 | 1265 | }
|
1246 | 1266 | }
|
1247 | 1267 |
|
1248 |
| - boolean shouldRemove(StateSplit node, EconomicMap<StateSplit, Boolean> decisionCache) { |
1249 |
| - Boolean cached = decisionCache.get(node); |
| 1268 | + RemovalDecision getDecision(StateSplit node, EconomicMap<StateSplit, RemovalDecision> decisionCache) { |
| 1269 | + RemovalDecision cached = decisionCache.get(node); |
1250 | 1270 | if (cached != null) {
|
1251 | 1271 | return cached;
|
1252 | 1272 | }
|
1253 | 1273 |
|
| 1274 | + DeoptEntrySupport proxyNode; |
| 1275 | + if (node instanceof ExceptionObjectNode exceptionObject) { |
| 1276 | + /* |
| 1277 | + * For the exception edge of a DeoptEntryNode, we insert the proxies on the |
| 1278 | + * exception object. |
| 1279 | + */ |
| 1280 | + proxyNode = (DeoptEntrySupport) exceptionObject.predecessor(); |
| 1281 | + } else { |
| 1282 | + proxyNode = (DeoptEntrySupport) node; |
| 1283 | + } |
| 1284 | + |
| 1285 | + RemovalDecision decision = RemovalDecision.REMOVE; |
1254 | 1286 | var directive = SubstrateCompilationDirectives.singleton();
|
1255 |
| - FrameState state = node.stateAfter(); |
| 1287 | + FrameState state = proxyNode.stateAfter(); |
1256 | 1288 | HostedMethod method = (HostedMethod) state.getMethod();
|
| 1289 | + if (proxyNode instanceof DeoptEntryNode) { |
| 1290 | + if (directive.isDeoptEntry(method, state.bci, state.duringCall(), state.rethrowException())) { |
| 1291 | + // must keep all deopt entries which are still guarding nodes |
| 1292 | + decision = RemovalDecision.KEEP; |
| 1293 | + } |
| 1294 | + } |
1257 | 1295 |
|
1258 |
| - boolean result = true; |
1259 |
| - if (directive.isRegisteredDeoptTarget(method)) { |
1260 |
| - result = !directive.isDeoptEntry(method, state.bci, state.duringCall(), state.rethrowException()); |
| 1296 | + if (decision == RemovalDecision.REMOVE) { |
| 1297 | + // now check for any implicit deopt entry being protected against |
| 1298 | + int proxifiedInvokeBci = proxyNode.getProxifiedInvokeBci(); |
| 1299 | + if (proxifiedInvokeBci != BytecodeFrame.UNKNOWN_BCI && directive.isDeoptEntry(method, proxifiedInvokeBci, true, false)) { |
| 1300 | + // must keep still keep a proxy for nodes which are "proxifying" an invoke |
| 1301 | + decision = proxyNode instanceof DeoptEntryNode ? RemovalDecision.PROXIFY : RemovalDecision.KEEP; |
| 1302 | + } |
1261 | 1303 | }
|
1262 | 1304 |
|
1263 | 1305 | // cache the decision
|
1264 |
| - decisionCache.put(node, result); |
1265 |
| - return result; |
| 1306 | + decisionCache.put(node, decision); |
| 1307 | + if (proxyNode != node) { |
| 1308 | + decisionCache.put(proxyNode, decision); |
| 1309 | + } |
| 1310 | + return decision; |
1266 | 1311 | }
|
1267 | 1312 |
|
1268 | 1313 | @Override
|
1269 | 1314 | public CharSequence getName() {
|
1270 |
| - return "RemoveDeoptEntries"; |
| 1315 | + return "RemoveUnneededDeoptSupport"; |
1271 | 1316 | }
|
1272 | 1317 | }
|
1273 | 1318 | }
|
0 commit comments