一句话描述DAE逻辑:DAE 根据 callee 中未使用的形参,将 Module 内所有指向该 有函数实体的definition 的调用点对应实参替换为 poison。
按照当前生产流水线,普通非递归调用通常不会触发 DAE 误删 receiver。
原因是:
非 Root callee 有两种结果:
- 已经成功内联:调用点消失。
- 没有内联:InlineDriver 删除其
available_externally body,只留下 declaration。
第二种情况下:
declare @callee(ptr %receiver, ...)
DAE 看不到 callee body,无法判断 %receiver 是否未使用,因此不会把调用实参替换成 poison。
真正危险的条件是:
因为 Root body 必须保留,DAE 能看到 Root 的 receiver 是 use_empty,同时又能看到指向 Root 的递归调用,于是才会修改其 receiver。
因此当前场景可以归纳为:
| 调用形态 |
DAE 是否可能误删 receiver |
| 非 Root callee,已内联 |
不会,调用已消失 |
| 非 Root callee,未内联 |
通常不会,callee 只剩 declaration |
| Root 递归调用 |
会,Root 是 exact definition |
| 内联后形成的间接递归,target 指回 Root |
会,本次 reactors 就是这种情况 |
| 人工 Module 保留多个 exact definitions |
也会,现有 LLVM 单测属于这种情况 |
所以更精确地说:
在当前 JeandleInlineDriver 清理规则下,实际生产问题主要发生于去虚化后 target 指回 Root 的直接或间接递归调用;普通非递归 Java callee 不会进入这条 DAE 误删路径。
runtime-live 仍然值得保留,因为 receiver 的 runtime ABI 活性本来就不应该依赖“当前恰好会删除非 Root body”这个流水线前提。以后 pass 顺序、linkage 或 Module 组成变化时,非递归调用也可能重新暴露同类问题。
一句话描述DAE逻辑:DAE 根据 callee 中未使用的形参,将 Module 内所有指向该 有函数实体的definition 的调用点对应实参替换为
poison。按照当前生产流水线,普通非递归调用通常不会触发 DAE 误删 receiver。
原因是:
非 Root callee 有两种结果:
available_externallybody,只留下 declaration。第二种情况下:
DAE 看不到 callee body,无法判断
%receiver是否未使用,因此不会把调用实参替换成 poison。真正危险的条件是:
因为 Root body 必须保留,DAE 能看到 Root 的 receiver 是
use_empty,同时又能看到指向 Root 的递归调用,于是才会修改其 receiver。因此当前场景可以归纳为:
所以更精确地说:
runtime-live仍然值得保留,因为 receiver 的 runtime ABI 活性本来就不应该依赖“当前恰好会删除非 Root body”这个流水线前提。以后 pass 顺序、linkage 或 Module 组成变化时,非递归调用也可能重新暴露同类问题。