方法分析
本章介绍基于树API的ASM API,用于分析方法代码。
首先介绍代码分析算法,然后提供相应的ASM API和一些示例。
介绍
代码分析是一个非常大的主题,并且存在许多用于分析代码的算法。
在这里不可能全部展示它们,这超出了本文的范围。
实际上,本部分的目的只是概述ASM中使用的算法。
在有关编译器的书中可以找到关于此主题的更好的介绍。
下一节将介绍两种重要的代码分析技术,即数据流和控制流分析:
数据流分析包括针对该方法的每个指令计算方法的执行框架的状态。
该状态可以以或多或少的抽象方式表示。
例如,参考值可以由单个值,每个类一个值,由 {null,not null,may be null}
集合中的三个可能值表示,等等。
控制流分析包括计算方法的控制流图,以及对该图进行分析。
控制流程图是一个图,其节点为指令,其定向边连接两个指令 i!j 如果可以在i之后执行j,则返回j。
数据流分析
可以执行两种类型的数据流分析:
-
前向分析从每条指令执行前的状态开始,为每条指令计算该指令后执行帧的状态。
-
向后分析从每条指令执行后的状态为每条指令计算该指令前执行帧的状态。
通过模拟方法的eac字节码指令在其执行帧上的执行来执行前向数据流分析,通常包括:
-
从堆栈中弹出值,
-
结合起来,
-
并将结果推入堆栈。
这看起来像解释器或Java虚拟机的功能,但实际上却完全不同,因为目标是针对所有可能的参数值模拟方法中的所有潜在执行路径,而不是由某些特定参数确定的单个执行路径。方法参数值。
结果是,对于分支指令,将模拟两个分支(而实际解释器仅跟随一个分支,具体取决于实际条件值)。
另一个结果是,操纵值实际上是可能值的集合。
这些集合可能非常大,例如“所有可能的值”,“所有整数”,“所有可能的对象”或“所有可能的String对象”,在这种情况下,它们也可以称为类型。
它们也可以更精确,例如“所有正整数”,“ 0到10之间的所有整数”或“所有可能的非null对象”。
模拟一条指令i的执行过程包括为其操作数值集中的值的所有组合找到i的所有可能结果的集合。
例如,如果整数由三组表示P =“正数或null”,N =“负数或null”和A =“所有整数”,则模拟IADD指令意味着如果两个操作数均为P,则返回P,如果两个都为N,则返回N操作数为N,在所有其他情况下为A。
最后一个结果是需要计算值集的并集:例如,与(b?e1:e2)对应的可能值集是e1的可能值和e2的可能值的并集。
更一般而言,每次控制流程图包含具有共同目的地的两个或更多边时,都需要执行此操作。
在前面的示例中,整数由三个集合P,N和A表示,计算这两个集合的并集很容易:除非两个集合相等,否则总为A。
控制流分析
控制流分析是基于一种方法的控制流图的分析。
例如,下面给出了第3.1.3节中的checkAndSetF方法的控制流程图(带有包含在标签中的标签,如真实指令):
该图可以分解为四个基本块(上面用矩形显示),一个基本块是一个指令序列,这样,除最后一个指令外的每个指令都具有一个后继指令,并且除第一个指令外的其他指令均不能成为目标指令一跳。