Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
9cd3106
add flag for C2 Optimization Tracing (debug only)
Oct 18, 2025
d192c09
add canonicalization hook
Oct 18, 2025
9b02d47
eliminate autobox hooks
Oct 18, 2025
b76e81f
Eliminate Autobox hook
Oct 18, 2025
005276e
CCP opt hook added for trace c2 opts
Oct 18, 2025
c292b2e
escape analysis hook
Oct 18, 2025
dcea212
loop unswitch hook
Oct 18, 2025
a475111
splitif hook
Oct 18, 2025
4281d92
ptr compare hook
Oct 18, 2025
55cdff9
null check elim hook
Oct 18, 2025
b0502b7
CEE hook
Oct 18, 2025
c9d3dc9
lock elim hook
Oct 18, 2025
f763f8a
deopt hook
Oct 18, 2025
60b6277
simplify phi hook
Oct 18, 2025
72ee6fb
inline hook
Oct 18, 2025
3b2d074
block elim hook
Oct 18, 2025
c44d277
range check elim hook
Oct 18, 2025
c2488b0
missing header for hook
Oct 18, 2025
3d64afb
loop unrolling hook
Oct 18, 2025
c66a68a
loop peeling hock
Oct 18, 2025
e0fd583
parallel iv hook
Oct 18, 2025
93be05e
implement printing of c2 optimization
Oct 18, 2025
f03f6b9
add guards for release build
Oct 19, 2025
a8403f0
remove very simple optimizations behaviors and add new ones
Oct 20, 2025
a5f8fef
instrumentation and optimization hooks for fuzzer
Oct 18, 2025
e0a0e63
add guards for release build
Oct 19, 2025
76adf8b
remove very simple optimizations behaviors and add new ones
Oct 20, 2025
3bc724f
Merge branch 'dev' of github.com:oliviermattmann/jdk into dev
Oct 22, 2025
30d0a3f
instrumentation and optimization hooks for fuzzer
Oct 18, 2025
6b8652d
add guards for release build
Oct 19, 2025
cd8ee2c
remove very simple optimizations behaviors and add new ones
Oct 20, 2025
9dcce5c
add flag for C2 Optimization Tracing (debug only)
Oct 18, 2025
9f21aab
add canonicalization hook
Oct 18, 2025
a359e36
eliminate autobox hooks
Oct 18, 2025
6e66840
Eliminate Autobox hook
Oct 18, 2025
a314ae0
simplify phi hook
Oct 18, 2025
07ec2ad
remove very simple optimizations behaviors and add new ones
Oct 20, 2025
4993b1b
Merge branch 'dev' of github.com:oliviermattmann/jdk into dev
Oct 26, 2025
aeb9e6a
Merge branch 'openjdk:master' into dev
oliviermattmann Oct 26, 2025
c0baf09
remove trailing whitespace
Oct 27, 2025
c0750e6
Merge branch 'dev' of github.com:oliviermattmann/jdk into dev
Oct 27, 2025
159a8a1
first try to track additional opt behaviors
Nov 1, 2025
2661e8a
fix overcounting for LoopIterationSplit event
Nov 3, 2025
ac4460a
Merge branch 'dev-additional-intr' into dev
Nov 3, 2025
857d6aa
Merge branch 'openjdk:master' into dev
oliviermattmann Nov 3, 2025
67bf5bd
Merge branch 'openjdk:master' into dev
oliviermattmann Nov 4, 2025
2cf80f2
aquire ttylocker before printing to prevent opt statistics interleaving
Nov 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/hotspot/share/opto/block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "memory/allocation.inline.hpp"
#include "memory/resourceArea.hpp"
#include "opto/block.hpp"
#include "opto/compile.hpp"
#include "opto/cfgnode.hpp"
#include "opto/chaitin.hpp"
#include "opto/loopnode.hpp"
Expand Down Expand Up @@ -1017,6 +1018,7 @@ void PhaseCFG::remove_unreachable_blocks() {
get_block(i)->_pre_order--;
}
_blocks.remove(dead->_pre_order);
C->record_optimization_event(OptEvent_BlockElimination);
_number_of_blocks--;
// Update the successors' predecessor list and push new unreachable blocks.
for (uint i = 0; i < dead->_num_succs; i++) {
Expand Down
3 changes: 3 additions & 0 deletions src/hotspot/share/opto/c2_globals.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,9 @@
product(bool, TraceTypeProfile, false, DIAGNOSTIC, \
"Trace type profile") \
\
develop(bool, TraceC2Optimizations, false, \
"Trace selected C2 loop optimizations (counts only)") \
\
develop(bool, PoisonOSREntry, true, \
"Detect abnormal calls to OSR code") \
\
Expand Down
1 change: 1 addition & 0 deletions src/hotspot/share/opto/callGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,7 @@ void CallGenerator::do_late_inline_helper() {
C->env()->notice_inlined_method(inline_cg()->method());
}
C->set_inlining_progress(true);
C->record_optimization_event(OptEvent_FunctionInlining);
C->set_do_cleanup(kit.stopped()); // path is dead; needs cleanup
kit.replace_call(call, result, true, do_asserts);
}
Expand Down
10 changes: 6 additions & 4 deletions src/hotspot/share/opto/cfgnode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "opto/addnode.hpp"
#include "opto/castnode.hpp"
#include "opto/cfgnode.hpp"
#include "opto/compile.hpp"
#include "opto/connode.hpp"
#include "opto/convertnode.hpp"
#include "opto/loopnode.hpp"
Expand Down Expand Up @@ -2157,10 +2158,11 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) {
uin = unique_input(phase, true);
}
if (uin == top) { // Simplest case: no alive inputs.
if (can_reshape) // IGVN transformation
if (can_reshape) { // IGVN transformation
return top;
else
} else {
return nullptr; // Identity will return TOP
}
} else if (uin != nullptr) {
// Only one not-null unique input path is left.
// Determine if this input is backedge of a loop.
Expand Down Expand Up @@ -2279,8 +2281,9 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) {
if( opt != nullptr ) {
if( opt == unsafe_id || is_unsafe_data_reference(opt) ) {
// Found dead loop.
if( can_reshape )
if( can_reshape ) {
return top;
}
// We can't return top if we are in Parse phase - cut inputs only
// to stop further optimizations for this phi. Identity will return TOP.
assert(req() == 3, "only diamond merge phi here");
Expand Down Expand Up @@ -3135,4 +3138,3 @@ void BlackholeNode::format(PhaseRegAlloc* ra, outputStream* st) const {
st->cr();
}
#endif

147 changes: 146 additions & 1 deletion src/hotspot/share/opto/compile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

#include "asm/macroAssembler.hpp"
#include "asm/macroAssembler.inline.hpp"
#include "ci/ciInstanceKlass.hpp"
#include "ci/ciReplay.hpp"
#include "classfile/javaClasses.hpp"
#include "code/aotCodeCache.hpp"
Expand Down Expand Up @@ -80,6 +81,7 @@
#include "opto/type.hpp"
#include "opto/vector.hpp"
#include "opto/vectornode.hpp"
#include "opto/c2_globals.hpp"
#include "runtime/globals_extension.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/signature.hpp"
Expand All @@ -90,6 +92,37 @@
#include "utilities/hashTable.hpp"
#include "utilities/macros.hpp"

#ifndef PRODUCT
static const char* const optimization_event_names[OptEvent_Count] = {
"Loop Unrolling",
"Loop Peeling",
"Parallel Induction Variables",
"Split If",
"Loop Unswitching",
"Conditional Expression Elimination",
"Function Inlining",
"Deoptimization",
"Escape Analysis",
"Eliminate Locks",
"Locks Coarsening",
"Conditional Constant Propagation",
"Eliminate Autobox",
"Block Elimination",
"Null Check Elimination",
"Range Check Elimination",
"Optimize Ptr Compare",
"Merge Stores",
"Loop Predication",
"Auto Vectorization",
"Partial Peeling",
"Iterative GVN Iterations",
"Loop Iteration Split",
"Reassociate Invariants",
"Loop Intrinsification",
"Peephole"
};
#endif

// -------------------- Compile::mach_constant_base_node -----------------------
// Constant table base node singleton.
MachConstantBaseNode* Compile::mach_constant_base_node() {
Expand Down Expand Up @@ -707,6 +740,10 @@ Compile::Compile(ciEnv* ci_env, ciMethod* target, int osr_bci,
TraceTime t1("Total compilation time", &_t_totalCompilation, CITime, CITimeVerbose);
TraceTime t2(nullptr, &_t_methodCompilation, CITime, false);

#ifndef PRODUCT
Copy::zero_to_bytes(_optimization_counters, sizeof(_optimization_counters));
#endif

#if defined(SUPPORT_ASSEMBLY) || defined(SUPPORT_ABSTRACT_ASSEMBLY)
bool print_opto_assembly = directive->PrintOptoAssemblyOption;
// We can always print a disassembly, either abstract (hex dump) or
Expand Down Expand Up @@ -891,6 +928,48 @@ Compile::Compile(ciEnv* ci_env, ciMethod* target, int osr_bci,

// Now generate code
Code_Gen();
#ifndef PRODUCT
if (TraceC2Optimizations) {
if (method() == nullptr) {
// Skip C2 runtime stubs (notify_jvmti_vthread_mount_blob, …).
return;
}
bool printed_header = false;
stringStream ss;
for (int i = 0; i < OptEvent_Count; i++) {
int count = _optimization_counters[i];
if (!printed_header) {
printed_header = true;
ResourceMark rm;
const char* holder_name = "<no-klass>";
const char* method_name = "<no-method>";
const char* method_signature = "<no-signature>";
int current_entry_bci = this->entry_bci();
if (method() != nullptr) {
ciInstanceKlass* holder = method()->holder();
if (holder != nullptr) {
holder_name = holder->name()->as_klass_external_name();
}
method_name = method()->name()->as_utf8();
method_signature = method()->signature()->as_symbol()->as_utf8();
current_entry_bci = this->entry_bci();
} else if (_stub_name != nullptr) {
method_name = _stub_name;
current_entry_bci = InvocationEntryBci;
}
const char* compilation_kind = is_osr_compilation() ? "OSR" : "non-OSR";
ss.print_cr("OPTS_START");
ss.print_cr("Opts|%s|%s|%s|%s|%d|%d", holder_name, method_name, method_signature, compilation_kind, current_entry_bci, _compile_id);
}
ss.print_cr("%s=%d", optimization_event_names[i], count);
}
if (printed_header) {
ss.print_cr("OPTS_END");
ttyLocker ttyl;
tty->print_raw(ss.base());
}
}
#endif
}

//------------------------------Compile----------------------------------------
Expand Down Expand Up @@ -964,6 +1043,10 @@ Compile::Compile(ciEnv* ci_env,
_allowed_reasons(0) {
C = this;

#ifndef PRODUCT
Copy::zero_to_bytes(_optimization_counters, sizeof(_optimization_counters));
#endif

// try to reuse an existing stub
{
BlobId blob_id = StubInfo::blob(_stub_id);
Expand Down Expand Up @@ -1010,12 +1093,68 @@ Compile::Compile(ciEnv* ci_env,
NOT_PRODUCT( verify_graph_edges(); )

Code_Gen();

#ifndef PRODUCT
if (TraceC2Optimizations) {
if (method() == nullptr) {
// Skip C2 runtime stubs (notify_jvmti_vthread_mount_blob, …).
return;
}
bool printed_header = false;
stringStream ss;
for (int i = 0; i < OptEvent_Count; i++) {
int count = _optimization_counters[i];
if (!printed_header) {
printed_header = true;
ResourceMark rm;
const char* holder_name = "<no-klass>";
const char* method_name = "<no-method>";
const char* method_signature = "<no-signature>";
int current_entry_bci = this->entry_bci();
if (method() != nullptr) {
ciInstanceKlass* holder = method()->holder();
if (holder != nullptr) {
holder_name = holder->name()->as_klass_external_name();
}
method_name = method()->name()->as_utf8();
method_signature = method()->signature()->as_symbol()->as_utf8();
current_entry_bci = this->entry_bci();
} else if (_stub_name != nullptr) {
method_name = _stub_name;
current_entry_bci = InvocationEntryBci;
}
const char* compilation_kind = is_osr_compilation() ? "OSR" : "non-OSR";
ss.print_cr("OPTS_START");
ss.print_cr("Opts|%s|%s|%s|%s|%d|%d", holder_name, method_name, method_signature, compilation_kind, current_entry_bci, _compile_id);
}
ss.print_cr("%s=%d", optimization_event_names[i], count);
}
if (printed_header) {
ss.print_cr("OPTS_END");
ttyLocker ttyl;
tty->print_raw(ss.base());
}
}
#endif

// Insert printing here (see below)
}

Compile::~Compile() {
delete _first_failure_details;
};


#ifndef PRODUCT
void Compile::record_optimization_event(OptimizationEvent event) {
if (!TraceC2Optimizations) {
return;
}
assert((int)event >= 0 && (int)event < OptEvent_Count, "optimization event out of bounds");
_optimization_counters[event]++;
}
#endif

//------------------------------Init-------------------------------------------
// Prepare for a single compilation
void Compile::Init(bool aliasing) {
Expand Down Expand Up @@ -1926,15 +2065,20 @@ void Compile::process_for_merge_stores_igvn(PhaseIterGVN& igvn) {
C->set_merge_stores_phase();

if (_for_merge_stores_igvn.length() > 0) {
bool performed_merge = false;
while (_for_merge_stores_igvn.length() > 0) {
Node* n = _for_merge_stores_igvn.pop();
n->remove_flag(Node::NodeFlags::Flag_for_merge_stores_igvn);
igvn._worklist.push(n);
performed_merge = true;
}
igvn.optimize();
if (failing()) return;
assert(_for_merge_stores_igvn.length() == 0, "no more delayed nodes allowed");
print_method(PHASE_AFTER_MERGE_STORES, 3);
print_method(PHASE_AFTER_MERGE_STORES, 3); // INTERESTING
if (performed_merge) {
record_optimization_event(OptEvent_MergeStores);
}
}
}

Expand Down Expand Up @@ -4835,6 +4979,7 @@ void Compile::add_coarsened_locks(GrowableArray<AbstractLockNode*>& locks) {
}
}
_coarsened_locks.append(locks_list);
record_optimization_event(OptEvent_LockCoarsening);
}
}

Expand Down
36 changes: 36 additions & 0 deletions src/hotspot/share/opto/compile.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,36 @@ enum LoopOptsMode {
LoopOptsVerify
};

enum OptimizationEvent {
OptEvent_LoopUnrolling = 0,
OptEvent_LoopPeeling,
OptEvent_ParallelInductionVars,
OptEvent_SplitIf,
OptEvent_LoopUnswitching,
OptEvent_ConditionalExpressionElimination,
OptEvent_FunctionInlining,
OptEvent_Deoptimization,
OptEvent_EscapeAnalysis,
OptEvent_EliminateLocks,
OptEvent_LockCoarsening,
OptEvent_ConditionalConstantPropagation,
OptEvent_EliminateAutobox,
OptEvent_BlockElimination,
OptEvent_NullCheckElimination,
OptEvent_RangeCheckElimination,
OptEvent_OptimizePtrCompare,
OptEvent_MergeStores,
OptEvent_LoopPredication,
OptEvent_AutoVectorization,
OptEvent_PartialPeeling,
OptEvent_IterGVNIteration,
OptEvent_LoopIterationSplit,
OptEvent_ReassociateInvariants,
OptEvent_LoopIntrinsification,
OptEvent_Peephole,
OptEvent_Count
};

// The type of all node counts and indexes.
// It must hold at least 16 bits, but must also be fast to load and store.
// This type, if less than 32 bits, could limit the number of possible nodes.
Expand Down Expand Up @@ -389,6 +419,9 @@ class Compile : public Phase {
GrowableArray<UnstableIfTrap*> _unstable_if_traps; // List of ifnodes after IGVN
GrowableArray<Node_List*> _coarsened_locks; // List of coarsened Lock and Unlock nodes
ConnectionGraph* _congraph;
#ifndef PRODUCT
int _optimization_counters[OptEvent_Count];
#endif
#ifndef PRODUCT
IdealGraphPrinter* _igv_printer;
static IdealGraphPrinter* _debug_file_printer;
Expand Down Expand Up @@ -888,6 +921,9 @@ class Compile : public Phase {
_recent_alloc_ctl = ctl;
_recent_alloc_obj = obj;
}

void record_optimization_event(OptimizationEvent event) PRODUCT_RETURN;

void record_dead_node(uint idx) { if (_dead_node_list.test_set(idx)) return;
_dead_node_count++;
}
Expand Down
4 changes: 4 additions & 0 deletions src/hotspot/share/opto/doCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "opto/callGenerator.hpp"
#include "opto/castnode.hpp"
#include "opto/cfgnode.hpp"
#include "opto/compile.hpp"
#include "opto/mulnode.hpp"
#include "opto/parse.hpp"
#include "opto/rootnode.hpp"
Expand Down Expand Up @@ -704,6 +705,9 @@ void Parse::do_call() {
if (cg->is_inline()) {
// Accumulate has_loops estimate
C->env()->notice_inlined_method(cg->method());
if (!cg->is_late_inline()) {
C->record_optimization_event(OptEvent_FunctionInlining);
}
}

// Reset parser state from [new_]jvms, which now carries results of the call.
Expand Down
2 changes: 2 additions & 0 deletions src/hotspot/share/opto/escape.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ void ConnectionGraph::do_analysis(Compile *C, PhaseIterGVN *igvn) {
if (congraph->compute_escape()) {
// There are non escaping objects.
C->set_congraph(congraph);
C->record_optimization_event(OptEvent_EscapeAnalysis);
}
// Cleanup.
if (oop_null->outcnt() == 0) {
Expand Down Expand Up @@ -3256,6 +3257,7 @@ void ConnectionGraph::optimize_ideal_graph(GrowableArray<Node*>& ptr_cmp_worklis
}
}
#endif
C->record_optimization_event(OptEvent_OptimizePtrCompare);
igvn->replace_node(n, cmp);
}
}
Expand Down
Loading