|
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