假设这批PR最终都合入并解决冲突,EA、late inline、Type/Loop PGO、arraycopy、字符串和Unsafe intrinsic这几条主线已经有人覆盖。继续对齐C2时,优先检查以下空白。
| 优先级 |
仍需拉齐的能力 |
当前状态 |
| P0 |
Java堆感知的Alias Analysis |
明确缺少 |
| P0 |
GC barrier后移、消除和合并 |
已实现barrier,但流水线明显不完整 |
| P0验收 |
PEA完整优化链 |
有PR,但要确认是否真正覆盖C2的标量替换、拆装箱和锁优化 |
| P1 |
MethodHandle/invokedynamic专项优化 |
通用Type PGO和late inline不一定覆盖完整 |
| P1 |
非虚拟对象的锁粗化、嵌套锁消除 |
PEA只能覆盖其中一部分 |
| P1 |
内联收益模型、代码尺寸控制 |
late inline解决“时机”,不等于解决“选谁内联” |
| P1 |
Java语义下的循环向量化 |
LLVM有向量化,但可能受barrier、statepoint和alias信息限制 |
| P2 |
剩余C2 intrinsic |
仍有缺项,但这五个用例中暂未形成头部热点 |
| P2 |
ZGC/Shenandoah等collector适配 |
当前一些intrinsic只对G1/Serial开放 |
1. Java堆感知的Alias Analysis
这是目前源码中最明确、而且不在所列PR里的缺口。LLVM AA不了解:
- 两个新分配Java对象一定不同;
- 精确Klass带来的对象/数组布局;
- oop handle和Java heap对象之间的关系;
- 不同Java字段、数组之间的别名关系。
源码已经直接写了TODO:
// LLVM AA does not understand Java oop handles, exact Klass facts,
// or Java heap allocation provenance.
见 [ArrayCopySpecialization.cpp (line 89)](/home/luofeng/jdk21-c3-jit/jeandle-llvm/llvm/lib/Transforms/Jeandle/ArrayCopySpecialization.cpp:89)。
这会限制load/store消除、LICM、arraycopy特化和向量化。它和PEA也有明显协同:PEA证明对象身份和逃逸范围,Java AA把这些信息继续提供给后续LLVM优化。
建议任务可以定义为:
增加Jeandle JavaHeapAA或通过noalias/alias scope/attributes传播对象来源、字段和数组别名信息。
2. GC barrier优化流水线
当前C3必须在O3之前插入高层barrier调用,因为barrier pass还不能处理O3产生的memory intrinsic和vector指令;源码明确说明未内联barrier可能阻塞优化:
// But the uninlined barrier calls can still block useful optimizations.
见 [Pipeline.cpp (line 274)](/home/luofeng/jdk21-c3-jit/jeandle-llvm/llvm/lib/Jeandle/Pipeline.cpp:274)。
C2则把barrier作为Ideal Graph和Macro Expansion的一部分,可以利用类型、逃逸和内存链信息消除或合并部分barrier。
建议拆成:
- 让
InsertGCBarriers识别O3生成的memory intrinsic和vector store。 - 将barrier插入推迟到主要标量、循环和向量优化之后。
- 利用PEA/Java AA消除新对象初始化期间不必要的post barrier。
- 支持相邻card mark合并和冗余barrier消除。
这个方向对neo4j和page-rank的对象、数组密集路径比较值得关注。
3. PEA需要按完整链路验收
!123不是小型“删除死分配”补丁,从本地origin/pea看,已经涉及对象/数组虚拟化、分支和循环合流、按逃逸点物化、deopt对象恢复和monitor处理。因此不建议另外再立一个重复EA任务。
但需要确认它是否真正覆盖这些C2能力:
逃逸分析
→ 对象/数组标量替换
→ 分配消除
→ boxing对象消除
→ 不逃逸对象锁消除
→ deopt/异常/OSR时正确物化
→ GC barrier和内存操作继续简化
尤其要检查:
- 对象进入deopt state后是否仍可虚拟化;
- 循环中的对象是否能够稳定收敛;
Integer/Long/Float/Double.valueOf及Tuple/lambda捕获对象能否消除;- 对虚拟对象的monitorenter/exit能否一起消除;
- 编译时间和IR膨胀是否可控。
page-rank和par-mnemonics适合作为PEA验收样本。
4. MethodHandle/invokedynamic专项优化
!106/115/116主要是类型profile传播和类型检查特化,!120是通用late inline。还需要确认它们是否覆盖C2的:
IncrementalInlineMH;- MethodHandle adapter链的延迟内联;
invokedynamic CallSite target常量化;guardWithTest分支profile;- lambda/metafactory调用链折叠;
- 去虚化后再次触发内联。
这对Spark/Scala的page-rank、Stream/lambda密集的par-mnemonics和reactors都可能有价值。不能只看“late inline PR已存在”,需要检查它支持的是普通调用、virtual call,还是也包括MH/indy调用链。
5. 锁粗化和嵌套锁消除
!126修复的是contended monitorenter的deopt状态,属于正确性,不是锁优化。
PEA可以消除“虚拟对象”上的锁,但C2还具有:
EliminateLocks:锁粗化;EliminateNestedLocks:同一对象的嵌套锁消除。
见 [c2_globals.hpp (line 448)](/home/luofeng/jdk21-c3-jit/src/hotspot/share/opto/c2_globals.hpp:448)。
当前没有看到C3中对应的独立优化pass。因此,在PEA之外还应检查:
synchronized (obj) { operation1(); }
synchronized (obj) { operation2(); }
是否可以合并为一次加锁,以及递归/嵌套同步是否能删除重复monitor操作。这个方向可能影响philosophers,但应先解决STM多模态的观测问题。
6. late inline之后仍缺内联收益模型
!120解决的是“能不能晚点内联”,不自动解决:
- 哪个调用值得内联;
- 内联后代码尺寸是否失控;
- 多态调用要生成几个版本;
- 编译CPU预算是否值得;
- 如何平衡调用消除和i-cache/iTLB压力。
page-rank已经观察到部分C3热点代码比C2大1.4~3.3倍;neo4j有frontend/iTLB压力。因此late inline合入后,仍需要代码尺寸感知的收益模型和版本化预算,不能简单扩大阈值。
7. 循环向量化不要和Loop PGO混为一项
当前C3已经有LICM、loop unswitch、loop predication、IRCE和LLVM O3,!122补的是循环profile。它们不等于C2 SuperWord效果已经拉齐。
需要验证:
- Java数组访问能否提供足够的alias信息;
- safepoint/statepoint是否阻断向量化;
- GC barrier是否使vector store退回标量;
- Vector API的masked load/store、gather/scatter、reduction是否完整;
- 编译后是否确实生成AArch64 NEON/SVE指令。
这更适合用向量化成功率、生成指令和循环吞吐量验收,而不是单纯检查有没有LLVM vectorizer。
8. 剩余intrinsic
当前仍未看到的C2 intrinsic包括若干:
Object.clone、Reflection.getCallerClass;- 部分unaligned get/put;
- 部分
getAndAdd/getAndSet类型; - ByteBuffer CRC;
- Montgomery运算;
- Vector masked/gather/scatter/reduction等。
但旧profile中只有reactors的clone/getCallerClass各约0.05%~0.06%,对这五项不是当前P0。
最后还要修正前面的一个判断:当前分支已经有[StringBuilder/StringBuffer concat fusion (line 104)](/home/luofeng/jdk21-c3-jit/src/hotspot/share/jeandle/jeandleStringConcat.cpp:104),所以OptimizeStringConcat不能再列为“C3完全没有”;后续应该比较覆盖范围和收益,而不是重新立项实现。
综合来看,在现有PR之外,最值得新增的两条主任务是:
- JavaHeap Alias Analysis + PEA信息向后续优化传播。
- GC barrier后移、消除、合并,并解除对O3/向量化的阻塞。
然后再审查!120是否完整覆盖MethodHandle/invokedynamic,以及!123是否覆盖锁消除、boxing和deopt物化全链路。
假设这批PR最终都合入并解决冲突,EA、late inline、Type/Loop PGO、arraycopy、字符串和Unsafe intrinsic这几条主线已经有人覆盖。继续对齐C2时,优先检查以下空白。
1. Java堆感知的Alias Analysis
这是目前源码中最明确、而且不在所列PR里的缺口。LLVM AA不了解:
源码已经直接写了TODO:
见 [ArrayCopySpecialization.cpp (line 89)](/home/luofeng/jdk21-c3-jit/jeandle-llvm/llvm/lib/Transforms/Jeandle/ArrayCopySpecialization.cpp:89)。
这会限制load/store消除、LICM、arraycopy特化和向量化。它和PEA也有明显协同:PEA证明对象身份和逃逸范围,Java AA把这些信息继续提供给后续LLVM优化。
建议任务可以定义为:
2. GC barrier优化流水线
当前C3必须在O3之前插入高层barrier调用,因为barrier pass还不能处理O3产生的memory intrinsic和vector指令;源码明确说明未内联barrier可能阻塞优化:
见 [Pipeline.cpp (line 274)](/home/luofeng/jdk21-c3-jit/jeandle-llvm/llvm/lib/Jeandle/Pipeline.cpp:274)。
C2则把barrier作为Ideal Graph和Macro Expansion的一部分,可以利用类型、逃逸和内存链信息消除或合并部分barrier。
建议拆成:
InsertGCBarriers识别O3生成的memory intrinsic和vector store。这个方向对neo4j和page-rank的对象、数组密集路径比较值得关注。
3. PEA需要按完整链路验收
!123不是小型“删除死分配”补丁,从本地origin/pea看,已经涉及对象/数组虚拟化、分支和循环合流、按逃逸点物化、deopt对象恢复和monitor处理。因此不建议另外再立一个重复EA任务。但需要确认它是否真正覆盖这些C2能力:
尤其要检查:
Integer/Long/Float/Double.valueOf及Tuple/lambda捕获对象能否消除;page-rank和par-mnemonics适合作为PEA验收样本。
4. MethodHandle/invokedynamic专项优化
!106/115/116主要是类型profile传播和类型检查特化,!120是通用late inline。还需要确认它们是否覆盖C2的:IncrementalInlineMH;invokedynamicCallSite target常量化;guardWithTest分支profile;这对Spark/Scala的page-rank、Stream/lambda密集的par-mnemonics和reactors都可能有价值。不能只看“late inline PR已存在”,需要检查它支持的是普通调用、virtual call,还是也包括MH/indy调用链。
5. 锁粗化和嵌套锁消除
!126修复的是contended monitorenter的deopt状态,属于正确性,不是锁优化。PEA可以消除“虚拟对象”上的锁,但C2还具有:
EliminateLocks:锁粗化;EliminateNestedLocks:同一对象的嵌套锁消除。见 [c2_globals.hpp (line 448)](/home/luofeng/jdk21-c3-jit/src/hotspot/share/opto/c2_globals.hpp:448)。
当前没有看到C3中对应的独立优化pass。因此,在PEA之外还应检查:
是否可以合并为一次加锁,以及递归/嵌套同步是否能删除重复monitor操作。这个方向可能影响philosophers,但应先解决STM多模态的观测问题。
6. late inline之后仍缺内联收益模型
!120解决的是“能不能晚点内联”,不自动解决:page-rank已经观察到部分C3热点代码比C2大1.4~3.3倍;neo4j有frontend/iTLB压力。因此late inline合入后,仍需要代码尺寸感知的收益模型和版本化预算,不能简单扩大阈值。
7. 循环向量化不要和Loop PGO混为一项
当前C3已经有LICM、loop unswitch、loop predication、IRCE和LLVM O3,
!122补的是循环profile。它们不等于C2 SuperWord效果已经拉齐。需要验证:
这更适合用向量化成功率、生成指令和循环吞吐量验收,而不是单纯检查有没有LLVM vectorizer。
8. 剩余intrinsic
当前仍未看到的C2 intrinsic包括若干:
Object.clone、Reflection.getCallerClass;getAndAdd/getAndSet类型;但旧profile中只有reactors的
clone/getCallerClass各约0.05%~0.06%,对这五项不是当前P0。最后还要修正前面的一个判断:当前分支已经有[StringBuilder/StringBuffer concat fusion (line 104)](/home/luofeng/jdk21-c3-jit/src/hotspot/share/jeandle/jeandleStringConcat.cpp:104),所以
OptimizeStringConcat不能再列为“C3完全没有”;后续应该比较覆盖范围和收益,而不是重新立项实现。综合来看,在现有PR之外,最值得新增的两条主任务是:
然后再审查
!120是否完整覆盖MethodHandle/invokedynamic,以及!123是否覆盖锁消除、boxing和deopt物化全链路。