RFR: 8356761: IGV: dump escape analysis information
Roberto Castañeda Lozano
rcastanedalo at openjdk.org
Wed Nov 12 11:51:43 UTC 2025
On Thu, 30 Oct 2025 13:49:44 GMT, Anton Seoane Ampudia <aseoane at openjdk.org> wrote:
> This PR introduces new IGV dumps, property fields and filters related to escape analysis information.
>
> The C2 escape analysis algorithm is carried out in six primary steps, of which many have interesting sub-steps (e.g. `split_unique_types`) or present an iterative nature where access to intermediate results can aid debugging and analysis. Additionally, escape analysis relies on an "intermediate structure" called the _connection graph_, which is also particularly valuable for deeper investigations.
>
> With this changeset, escape analysis information is now dumped at key points throughout the algorithm, with a degree of granularity (from only the basic steps to in-detail iterative dumping). The dumps include several property fields, such as:
>
> - Node escape “level”.
> - Scalar replaceability.
> - Node type within the connection graph (per [C2 Escape Analysis connection graph](https://wiki.openjdk.org/display/HotSpot/EscapeAnalysis)).
>
> This is achieved by passing the `ConnectionGraph` in use to the `IdealGraphPrinter` during escape analysis, so that these properties can be dumped. After escape analysis, remaining interesting information that is left until macro elimination (and consequent elimination of non-escaping, replaceable allocations) is also dumped.
>
> Additionally, two filters are provided: one for displaying the connection node type in the IGV node box, and another one for color-scaling nodes based on their escaping/scalar status.
>
> **Testing:** passes tiers 1-3, manual testing in IGV
Thanks for this work, Antón! This is going to help immensely understanding, debugging, and improving C2's escape analysis. Here are a few higher-level comments and suggestions:
- In lack of a proper hierarchical structure, the IGV filters are roughly sorted by generality. Transformation-specific filters like those proposed by this changeset should be placed further down. I suggest moving them to in between "Hide exception blocks" and "Color live ranges by allocation".
- The "Color by escape analysis state" is very useful, but the current version has a couple of issues.
1. The coloring function is not "total" (i.e. does not color all nodes involved in EA). In particular, nodes with `escape=global_escape` and `replaceable=true` (which seems contradictory, I assume this is a transient state) are not colored. I guess they should be colored in red, but please check. Here is an example (see 98 Return): <img width="1118" height="940" alt="no-color" src="https://github.com/user-attachments/assets/2c0fd974-3ba8-4b80-8d1b-5da938c38f9a" />
2. The order in which colors are applied leads to wrong coloring of allocation nodes in the intermediate EA phases. See e.g. 205 Allocate in the following example (which should be green but is colored in red): <img width="1459" height="947" alt="wrong-coloring" src="https://github.com/user-attachments/assets/9f3bbc47-6aba-4faa-b336-659e81cf8b75" />
I suggest applying colors based on persistent node attributes ("is_non_escaping", "does_not_escape_thread", etc.) first, and then applying colors based on CG-derived attributes ("escape", "replaceable", etc.).
- Please name node attributes as closely as possible to the C2 source code names as possible for traceability, e.g. "escape_state" instead of "escape", "scalar_replaceable" instead of "replaceable", etc.
- The "Show connection graph nodes" looks promising but I would suggest renaming it to "Show connection graph info" (for consistency with "Show custom node info") and extending it with the `PointsToNode::_pidx` corresponding to each relevant Ideal node. Actually printing the equivalent line of `PointsToNode::dump_header(false)` would be ideal, in my opinion.
- It could also be useful to add yet another filter (named "Show connection graph nodes only" or similar) to show only connection graph nodes. This filter would be as simple as `remove(not(hasProperty("ea_node")));`. Here is an example, note how the EA information becomes much denser: <img width="774" height="489" alt="cg-only" src="https://github.com/user-attachments/assets/3b5d6b72-9103-406d-92c6-d3775867b198" />
- Finally, please define all the new phases in `test/hotspot/jtreg/compiler/lib/ir_framework/CompilePhase.java`, we try to keep this file in sync with `phasetype.hpp` (manually).
src/hotspot/share/opto/escape.cpp line 117:
> 115: }
> 116: ConnectionGraph* congraph = new(C->comp_arena()) ConnectionGraph(C, igvn, invocation);
> 117: NOT_PRODUCT(if (C->igv_printer()) C->igv_printer()->set_congraph(congraph);)
Suggestion:
NOT_PRODUCT(if (C->igv_printer() != nullptr) C->igv_printer()->set_congraph(congraph);)
src/hotspot/share/opto/escape.cpp line 123:
> 121: C->set_congraph(congraph);
> 122: }
> 123: NOT_PRODUCT(if (C->igv_printer()) C->igv_printer()->set_congraph(nullptr);)
Suggestion:
NOT_PRODUCT(if (C->igv_printer() != nullptr) C->igv_printer()->set_congraph(nullptr);)
src/hotspot/share/opto/escape.cpp line 323:
> 321: }
> 322: }
> 323: _compile->print_method(PHASE_EA_ADJUST_SCALAR_REPLACEABLE_ITER, 6);
Suggestion:
_compile->print_method(PHASE_EA_ADJUST_SCALAR_REPLACEABLE_ITER, 6, n);
src/hotspot/share/opto/escape.cpp line 1320:
> 1318: }
> 1319:
> 1320: _compile->print_method(PHASE_EA_BEFORE_PHI_REDUCTION, 5);
Suggestion:
_compile->print_method(PHASE_EA_BEFORE_PHI_REDUCTION, 5, ophi);
src/hotspot/share/opto/escape.cpp line 1327:
> 1325: for (uint i = 0; i < castpps.size(); i++) {
> 1326: reduce_phi_on_castpp_field_load(castpps.at(i), alloc_worklist);
> 1327: _compile->print_method(PHASE_EA_AFTER_PHI_CASTPP_REDUCTION, 6);
Suggestion:
_compile->print_method(PHASE_EA_AFTER_PHI_CASTPP_REDUCTION, 6, castpps.at(i));
src/hotspot/share/opto/escape.cpp line 1339:
> 1337: }
> 1338:
> 1339: _compile->print_method(PHASE_EA_AFTER_PHI_ADDPP_CMP_REDUCTION, 6);
Suggestion:
_compile->print_method(PHASE_EA_AFTER_PHI_ADDPP_CMP_REDUCTION, 6, use);
Also, please consider defining a separate phase for each type (AddP/Cmp).
src/hotspot/share/opto/escape.cpp line 2576:
> 2574: }
> 2575: if (!verify) {
> 2576: _compile->print_method(PHASE_EA_CONNECTION_GRAPH_PROPAGATE_ITER, 6);
Suggestion:
_compile->print_method(PHASE_EA_CONNECTION_GRAPH_PROPAGATE_ITER, 6, e->ideal_node());
src/hotspot/share/opto/escape.cpp line 3153:
> 3151: revisit_reducible_phi_status(jobj, reducible_merges);
> 3152: found_nsr_alloc = true;
> 3153: _compile->print_method(PHASE_EA_PROPAGATE_NSR_ITER, 5);
Why dumping here and not for the `use->is_LocalVar()` case? Anyway, maybe it would be more useful to dump one or two levels up instead, e.g. for each `jobj`.
src/hotspot/share/opto/escape.cpp line 4749:
> 4747: uint new_index_end = (uint) _compile->num_alias_types();
> 4748:
> 4749: _compile->print_method(PHASE_EA_AFTER_SPLIT_UNIQUE_TYPES_1, 5);
I guess there is no `PHASE_EA_AFTER_SPLIT_UNIQUE_TYPES_2` because Phase 2 does not change the state of the Ideal graph or the connection graph and hence the changes are not observable within IGV, right?
src/hotspot/share/opto/escape.cpp line 5173:
> 5171: }
> 5172: }
> 5173:
Spurious change?
src/hotspot/share/opto/idealGraphPrinter.cpp line 653:
> 651: if (alloc->does_not_escape_thread()) {
> 652: print_prop("does_not_escape_thread", "true");
> 653: }
Please fix indentation.
src/hotspot/share/opto/idealGraphPrinter.cpp line 761:
> 759: if (_congraph && node->_idx < _congraph->nodes_size()) {
> 760: PointsToNode* ptn = _congraph->ptnode_adr(node->_idx);
> 761: if (ptn) {
Suggestion:
if (ptn != nullptr) {
src/hotspot/share/opto/idealGraphPrinter.cpp line 765:
> 763: ptn->is_LocalVar() ? "localvar" :
> 764: ptn->is_Field() ? "field" :
> 765: "");
Consider using `node_type_names` from `escape.cpp` instead.
src/hotspot/share/opto/idealGraphPrinter.cpp line 769:
> 767: ptn->escape_state() == PointsToNode::EscapeState::ArgEscape ? "arg_escape" :
> 768: ptn->escape_state() == PointsToNode::EscapeState::GlobalEscape ? "global_escape" :
> 769: "");
Consider using `esc_names` from `escape.cpp` instead.
src/hotspot/share/opto/idealGraphPrinter.cpp line 770:
> 768: ptn->escape_state() == PointsToNode::EscapeState::GlobalEscape ? "global_escape" :
> 769: "");
> 770: print_prop("replaceable", ptn->scalar_replaceable() ? "true" : "");
I suggest to name the properties as closely as possible to C2's source code as possible, for traceability (don't forget to update the corresponding IGV filters):
Suggestion:
print_prop("scalar_replaceable", ptn->scalar_replaceable() ? "true" : "");
src/utils/IdealGraphVisualizer/ServerCompiler/src/main/resources/com/sun/hotspot/igv/servercompiler/filters/colorEscapeAnalysis.filter line 1:
> 1: // Color allocation nodes to indicate the result of scape analysis.
Please update the comment, the filter colors other nodes than allocation nodes.
src/utils/IdealGraphVisualizer/ServerCompiler/src/main/resources/com/sun/hotspot/igv/servercompiler/filters/showConnectionNodes.filter line 8:
> 6: // Merge a possibly existing extra label, bottom type, and phase type into a
> 7: // new, single extra label. For memory nodes, add an extra label with the memory
> 8: // slice, extracted from the dump_spec field.
Please update this leftover comment.
src/utils/IdealGraphVisualizer/ServerCompiler/src/main/resources/com/sun/hotspot/igv/servercompiler/filters/showConnectionNodes.filter line 20:
> 18: "extra_label",
> 19: function(propertyValues) {return mergeAndAppendTypeInfo(propertyValues[0], propertyValues[1]);});
> 20:
Unnecessary line.
src/utils/IdealGraphVisualizer/ServerCompiler/src/main/resources/com/sun/hotspot/igv/servercompiler/layer.xml line 26:
> 24: <file name="Show connection graph nodes.js" url="filters/showConnectionNodes.filter">
> 25: <attr name="enabled" boolvalue="false"/>
> 26: <attr name="after" stringvalue="Show connection node types"/>
Note that `stringvalue` here should refer to the name of the preceding filter (`"Show types"` in this case).
src/utils/IdealGraphVisualizer/ServerCompiler/src/main/resources/com/sun/hotspot/igv/servercompiler/layer.xml line 94:
> 92: <file name="Color by escape analysis state.js" url="filters/colorEscapeAnalysis.filter">
> 93: <attr name="enabled" boolvalue="false"/>
> 94: <attr name="after" stringvalue="Color by escape analysis state"/>
Same as above.
-------------
Changes requested by rcastanedalo (Reviewer).
PR Review: https://git.openjdk.org/jdk/pull/28060#pullrequestreview-3452851763
PR Review Comment: https://git.openjdk.org/jdk/pull/28060#discussion_r2517848300
PR Review Comment: https://git.openjdk.org/jdk/pull/28060#discussion_r2517849185
PR Review Comment: https://git.openjdk.org/jdk/pull/28060#discussion_r2517850276
PR Review Comment: https://git.openjdk.org/jdk/pull/28060#discussion_r2517851664
PR Review Comment: https://git.openjdk.org/jdk/pull/28060#discussion_r2517853082
PR Review Comment: https://git.openjdk.org/jdk/pull/28060#discussion_r2517858612
PR Review Comment: https://git.openjdk.org/jdk/pull/28060#discussion_r2517860126
PR Review Comment: https://git.openjdk.org/jdk/pull/28060#discussion_r2517867376
PR Review Comment: https://git.openjdk.org/jdk/pull/28060#discussion_r2517881453
PR Review Comment: https://git.openjdk.org/jdk/pull/28060#discussion_r2517883463
PR Review Comment: https://git.openjdk.org/jdk/pull/28060#discussion_r2517884976
PR Review Comment: https://git.openjdk.org/jdk/pull/28060#discussion_r2517886131
PR Review Comment: https://git.openjdk.org/jdk/pull/28060#discussion_r2517952967
PR Review Comment: https://git.openjdk.org/jdk/pull/28060#discussion_r2517954679
PR Review Comment: https://git.openjdk.org/jdk/pull/28060#discussion_r2517889340
PR Review Comment: https://git.openjdk.org/jdk/pull/28060#discussion_r2517891149
PR Review Comment: https://git.openjdk.org/jdk/pull/28060#discussion_r2517892986
PR Review Comment: https://git.openjdk.org/jdk/pull/28060#discussion_r2517894537
PR Review Comment: https://git.openjdk.org/jdk/pull/28060#discussion_r2517898489
PR Review Comment: https://git.openjdk.org/jdk/pull/28060#discussion_r2517899100
More information about the hotspot-compiler-dev
mailing list