可以。先看最核心的策略:C2 在 Parse 调用点时,决定“立即 inline、late inline,还是保留调用”。
1. Parse 阶段的 inline 决策
flowchart TD
A["Parse 遇到 invoke"] --> B{"允许 inline?"}
B -- "否" --> CALL["生成普通 Call 节点<br/>不 inline"]
B -- "是" --> INTR{"能使用 Intrinsic?"}
INTR -- "是,且不是需延迟的 Vector" --> NOWI["立即生成 Intrinsic IR"]
INTR -- "Vector 需要延迟" --> LATE["生成 Call 节点<br/>加入 _late_inlines"]
INTR -- "否" --> MH{"MethodHandle 调用?"}
MH -- "是,目标/参数现在明确" --> NOWMH["立即 inline MH"]
MH -- "是,但目标/参数还不明确" --> LATEMH["先生成 Call<br/>等待常量传播后再尝试"]
MH -- "否" --> TARGET{"当前能确定唯一目标?"}
TARGET -- "否:virtual/interface" --> PROFILE{"类型 Profile / CHA<br/>能否找到候选目标?"}
PROFILE -- "能" --> POLICY
PROFILE -- "不能" --> VLATE{"IncrementalInlineVirtual?"}
VLATE -- "是" --> LATEV["生成 CallDynamicJava<br/>等待 IGVN 去虚化"]
VLATE -- "否" --> VCALL["保留 virtual call"]
TARGET -- "是:static/special/已去虚化" --> POLICY{"InlineTree::ok_to_inline?"}
POLICY -- "不满足 inline 策略" --> CALL
POLICY -- "满足" --> DELAY{"should_delay?"}
DELAY -- "是" --> LATE
DELAY -- "否" --> SPECIAL{"特殊延迟类型?"}
SPECIAL -- "StringBuilder/StringBuffer" --> LATES["进入 string late 队列"]
SPECIAL -- "Boxing valueOf" --> LATEB["进入 boxing late 队列"]
SPECIAL -- "Vector rebox" --> LATEVR["进入 vector reboxing late 队列"]
SPECIAL -- "都不是" --> NOW["立即 inline<br/>callee 在 Parse 中展开"]
Loading
对应的主要代码在 doCall.cpp:164 。
最关键的分支是:
if (should_delay) {
return CallGenerator::for_late_inline (callee, cg);
} else if (should_delay_string_inlining(...)) {
return CallGenerator::for_string_late_inline (callee, cg);
} else if (should_delay_boxing_inlining(...)) {
return CallGenerator::for_boxing_late_inline (callee, cg);
} else if (should_delay_vector_reboxing_inlining(...)) {
return CallGenerator::for_vector_reboxing_late_inline (callee, cg);
} else {
return cg; // 立即 inline
}
见 doCall.cpp:190 。
2. should_delay 什么时候为 true?
可以概括为:
flowchart TD
S["计算 should_delay"] --> A{"AlwaysIncrementalInline?"}
A -- "是" --> Y["late inline"]
A -- "否" --> B{"StressIncrementalInlining<br/>随机命中?"}
B -- "是" --> Y
B -- "否" --> C{"Replay 指定 inline_late?"}
C -- "是" --> Y
C -- "否" --> D{"ForceInline 方法<br/>但已碰到规模/深度限制?"}
D -- "是" --> Y
D -- "否" --> N["不延迟<br/>继续立即 inline"]
D -. "限制包括" .-> D1["DesiredMethodLimit"]
D -.-> D2["NodeCountInliningCutoff"]
D -.-> D3["最大 inline depth"]
Loading
这里有一个很重要的细节:
默认 IncrementalInline=true,并不代表所有调用都 late inline。
默认:
IncrementalInline = true
AlwaysIncrementalInline = false
所以普通、规模合适、目标明确的方法仍然立即 inline。通用 late inline 主要用于:
强制 inline,但当前图已经很大
MethodHandle
后续才能去虚化的 virtual call
Vector intrinsic
编译重放或压力测试
相关限制判断在 bytecodeInfo.cpp:361 。
3. 进入 late 队列后怎么处理?
flowchart TD
P["Parse 完成<br/>late 调用目前仍是 Call 节点"] --> RU["PhaseRemoveUseless<br/>删除 Parse 产生的无用节点"]
RU --> IGVN["第一次 IGVN<br/>常量传播、类型收窄、死代码删除"]
IGVN --> Q{"_late_inlines 非空?"}
Q -- "否" --> NEXT["进入后续 C2 优化"]
Q -- "是" --> LIMIT{"live_nodes 超过<br/>LiveNodeCountInliningCutoff?"}
LIMIT -- "是" --> LOOP["尝试 PhaseIdealLoop<br/>清理和缩小图"]
LOOP --> AGAIN{"清理后仍超限?"}
AGAIN -- "是" --> STOP["停止继续 inline<br/>避免编译图爆炸"]
AGAIN -- "否" --> PICK
LIMIT -- "否" --> PICK["取一个 late inline candidate"]
PICK --> LIVE{"原 Call 仍然存活且可达?"}
LIVE -- "否" --> DROP["丢弃 candidate<br/>不再展开 callee"]
DROP --> Q
LIVE -- "是" --> TYPE{"virtual/MH 的目标和类型<br/>现在足够明确?"}
TYPE -- "否" --> KEEP["暂不 inline<br/>保留或只做 direct-call 化"]
KEEP --> Q
TYPE -- "是" --> INLINE["重建调用点 JVMState<br/>inline_cg()->generate()"]
INLINE --> NESTED{"callee 中又出现<br/>late inline?"}
NESTED -- "是" --> DFS["插入当前队列位置<br/>近似深度优先处理"]
NESTED -- "否" --> CLEAN
DFS --> CLEAN{"需要 cleanup?"}
CLEAN -- "是" --> OPT["RemoveUseless + IGVN"]
CLEAN -- "否" --> Q
OPT --> Q
STOP --> LATEEND["到优化后期<br/>Virtual/MH 还可尝试<br/>strength reduce 为 direct call"]
LATEEND --> NEXT
Loading
通用 late inline 的入口是:
inline_incrementally (igvn);
它位于第一次 IGVN 后,见 compile.cpp:2230 。
真正展开 callee 的位置是:
JVMState* new_jvms = inline_cg()->generate (jvms);
见 callGenerator.cpp:696 。
4. 特殊 late inline 的执行顺序
不同 late 队列的目的不同,因此执行位置也不一样:
flowchart LR
P["Parse 完成"] --> S["StringOpts"]
S --> G["普通 incremental<br/>late inline"]
G --> SI["剩余 String<br/>late inline"]
SI --> BE["Boxing Elimination"]
BE --> BI["Boxing valueOf<br/>late inline"]
BI --> V["Vector Optimization"]
V --> VR["Vector reboxing<br/>late inline"]
VR --> O["后续优化 / CodeGen"]
Loading
其中:
String late inline:先让 PhaseStringOpts 识别完整的字符串拼接结构,再展开剩余调用。
Boxing late inline:先尝试消除 boxing;无法消除的 valueOf() 再展开。
Vector reboxing late inline:等 Vector 优化处理完逻辑 Vector box 后再展开。
Virtual/MH late inline:等待类型或常量信息明确。
5. 最简单的判断口诀
目标明确 + 图不大 + 没有特殊优化需求
→ 立即 inline
已经决定应该 inline,但当前图太大
→ late inline,等清理后再展开
String / Boxing / Vector
→ 等对应的高层优化完成后再 inline
Virtual / MethodHandle 目标暂时不明确
→ 保留 Call,等 IGVN 类型传播后重新判断
Call 在等待期间变成死代码
→ 直接删除,不再 inline
等待后图仍然太大
→ 放弃 inline,最多尝试去虚化成 direct call
可以。先看最核心的策略:C2 在 Parse 调用点时,决定“立即 inline、late inline,还是保留调用”。
1. Parse 阶段的 inline 决策
flowchart TD A["Parse 遇到 invoke"] --> B{"允许 inline?"} B -- "否" --> CALL["生成普通 Call 节点<br/>不 inline"] B -- "是" --> INTR{"能使用 Intrinsic?"} INTR -- "是,且不是需延迟的 Vector" --> NOWI["立即生成 Intrinsic IR"] INTR -- "Vector 需要延迟" --> LATE["生成 Call 节点<br/>加入 _late_inlines"] INTR -- "否" --> MH{"MethodHandle 调用?"} MH -- "是,目标/参数现在明确" --> NOWMH["立即 inline MH"] MH -- "是,但目标/参数还不明确" --> LATEMH["先生成 Call<br/>等待常量传播后再尝试"] MH -- "否" --> TARGET{"当前能确定唯一目标?"} TARGET -- "否:virtual/interface" --> PROFILE{"类型 Profile / CHA<br/>能否找到候选目标?"} PROFILE -- "能" --> POLICY PROFILE -- "不能" --> VLATE{"IncrementalInlineVirtual?"} VLATE -- "是" --> LATEV["生成 CallDynamicJava<br/>等待 IGVN 去虚化"] VLATE -- "否" --> VCALL["保留 virtual call"] TARGET -- "是:static/special/已去虚化" --> POLICY{"InlineTree::ok_to_inline?"} POLICY -- "不满足 inline 策略" --> CALL POLICY -- "满足" --> DELAY{"should_delay?"} DELAY -- "是" --> LATE DELAY -- "否" --> SPECIAL{"特殊延迟类型?"} SPECIAL -- "StringBuilder/StringBuffer" --> LATES["进入 string late 队列"] SPECIAL -- "Boxing valueOf" --> LATEB["进入 boxing late 队列"] SPECIAL -- "Vector rebox" --> LATEVR["进入 vector reboxing late 队列"] SPECIAL -- "都不是" --> NOW["立即 inline<br/>callee 在 Parse 中展开"]对应的主要代码在 doCall.cpp:164。
最关键的分支是:
见 doCall.cpp:190。
2.
should_delay什么时候为 true?可以概括为:
flowchart TD S["计算 should_delay"] --> A{"AlwaysIncrementalInline?"} A -- "是" --> Y["late inline"] A -- "否" --> B{"StressIncrementalInlining<br/>随机命中?"} B -- "是" --> Y B -- "否" --> C{"Replay 指定 inline_late?"} C -- "是" --> Y C -- "否" --> D{"ForceInline 方法<br/>但已碰到规模/深度限制?"} D -- "是" --> Y D -- "否" --> N["不延迟<br/>继续立即 inline"] D -. "限制包括" .-> D1["DesiredMethodLimit"] D -.-> D2["NodeCountInliningCutoff"] D -.-> D3["最大 inline depth"]这里有一个很重要的细节:
默认:
所以普通、规模合适、目标明确的方法仍然立即 inline。通用
late inline主要用于:相关限制判断在 bytecodeInfo.cpp:361。
3. 进入 late 队列后怎么处理?
flowchart TD P["Parse 完成<br/>late 调用目前仍是 Call 节点"] --> RU["PhaseRemoveUseless<br/>删除 Parse 产生的无用节点"] RU --> IGVN["第一次 IGVN<br/>常量传播、类型收窄、死代码删除"] IGVN --> Q{"_late_inlines 非空?"} Q -- "否" --> NEXT["进入后续 C2 优化"] Q -- "是" --> LIMIT{"live_nodes 超过<br/>LiveNodeCountInliningCutoff?"} LIMIT -- "是" --> LOOP["尝试 PhaseIdealLoop<br/>清理和缩小图"] LOOP --> AGAIN{"清理后仍超限?"} AGAIN -- "是" --> STOP["停止继续 inline<br/>避免编译图爆炸"] AGAIN -- "否" --> PICK LIMIT -- "否" --> PICK["取一个 late inline candidate"] PICK --> LIVE{"原 Call 仍然存活且可达?"} LIVE -- "否" --> DROP["丢弃 candidate<br/>不再展开 callee"] DROP --> Q LIVE -- "是" --> TYPE{"virtual/MH 的目标和类型<br/>现在足够明确?"} TYPE -- "否" --> KEEP["暂不 inline<br/>保留或只做 direct-call 化"] KEEP --> Q TYPE -- "是" --> INLINE["重建调用点 JVMState<br/>inline_cg()->generate()"] INLINE --> NESTED{"callee 中又出现<br/>late inline?"} NESTED -- "是" --> DFS["插入当前队列位置<br/>近似深度优先处理"] NESTED -- "否" --> CLEAN DFS --> CLEAN{"需要 cleanup?"} CLEAN -- "是" --> OPT["RemoveUseless + IGVN"] CLEAN -- "否" --> Q OPT --> Q STOP --> LATEEND["到优化后期<br/>Virtual/MH 还可尝试<br/>strength reduce 为 direct call"] LATEEND --> NEXT通用 late inline 的入口是:
inline_incrementally(igvn);它位于第一次 IGVN 后,见 compile.cpp:2230。
真正展开 callee 的位置是:
JVMState* new_jvms = inline_cg()->generate(jvms);见 callGenerator.cpp:696。
4. 特殊 late inline 的执行顺序
不同 late 队列的目的不同,因此执行位置也不一样:
flowchart LR P["Parse 完成"] --> S["StringOpts"] S --> G["普通 incremental<br/>late inline"] G --> SI["剩余 String<br/>late inline"] SI --> BE["Boxing Elimination"] BE --> BI["Boxing valueOf<br/>late inline"] BI --> V["Vector Optimization"] V --> VR["Vector reboxing<br/>late inline"] VR --> O["后续优化 / CodeGen"]其中:
String late inline:先让PhaseStringOpts识别完整的字符串拼接结构,再展开剩余调用。Boxing late inline:先尝试消除 boxing;无法消除的valueOf()再展开。Vector reboxing late inline:等 Vector 优化处理完逻辑 Vector box 后再展开。Virtual/MH late inline:等待类型或常量信息明确。5. 最简单的判断口诀