Page 40 - 《软件学报》2024年第6期
P. 40

2616                                                       软件学报  2024  年第  35  卷第  6  期


                 2.1.5    增量前端剪枝优化
                    通过增量单元的设计, 我们已经大幅减少了需要重新抽取输入事实的类和方法数量. 然而在实现过程中, 由于
                 框架使用的    Soot 框架的类加载机制, 为了获取一个类的所有依赖, 需要加载大量的类. 不仅包括输入的                         jar 包中的
                 所有类, 还包括这些类可能引用的系统类库中的类. 这个过程是迭代的, 直到无法继续找到传递依赖的类为止. 这
                 样的类加载策略是为了尝试对输入的待分析程序进行一个尽可能精确的建模. 在                           DDoop  框架的早期实现中, 我们
                 采用了这种类加载策略, 以保证与原始            Doop  框架有等价的指针分析精度. 然而, 这种实现相对低效.
                    在我们关注的变更频繁的增量场景下, 一次代码提交引入的变化通常是局部的, 不会导致整个程序引用的基
                 础类库发生巨大的变化. 因此, 全面类加载中也包含重复计算. 因此, 我们提出了对类加载过程的剪枝优化策略, 通
                 过减少需要加载的类数量来提升前端增量输入事实生成的速度.
                    图  4  展示了我们所采用的剪枝策略. 在增量输入事实生成的类加载过程中, 我们不再加载间接引用的类库中
                 的类. 也即在加载类时, 我们只会包括应用类和被应用类直接引用的类库中的类. 然而, 我们的剪枝策略可能会对
                 精度产生影响. 我们将在第        3.4  节和第  4.2  节分别从实验和理论层面就剪枝策略对精度的影响进行讨论.

                                            引擎需要对所有已经有的
                                                lib classes
                                                           .......

                                                   class    class     class
                                                                          剪枝

                                                         class    class
                                               APP classes

                                                    class

                                                   class    class     class

                                               图 4 类加载过程剪枝策略示意图

                 2.2   后端: 增量分析程序生成
                    Datalog  是  Prolog  的一个子集, 它是一种更为限制和精简的逻辑编程语言. 现代            Datalog  引擎都遵循了   Datalog
                 语言的理论规范, 但为了增强表现能力都对语言进行了拓展. 然而不同引擎之间的拓展并不完全相同, 并且目前也
                 不存在通用的标准语法. 因此, 不同的          Datalog  引擎之间一般并不能直接互通.
                    Soufflé 和  DDlog  是当前流行的两种   Datalog  引擎. Soufflé 是  Doop  框架目前所采用的  Datalog  引擎, 而  DDlog
                 支持高效的增量评估. 如果将         Doop  中面向  Soufflé 引擎实现的分析规则直接提交给         DDlog  编译器, 因为语法细节
                 层面的细微变化, 是无法通过编译的.
                    这意味着, 切换具体的       Datalog                    Datalog  规则进行语义等价的重写, 这无疑是一项艰
                 巨的任务. Doop  框架在发展过程中就有过一次切换             Datalog  引擎的经历, 它从对学术使用有相当限制的           LogicBlox
                 引擎切换到了当时新发布的、专为程序分析开发的                  Soufflé 引擎. 开发者为此耗费了大量精力        (大约  10  人月) [20] 完
                 全重写了指针分析的规则库, 将         LogicBlox  引擎所用的  LogiQL  语言切换到了    Soufflé 语言.
                    在我们框架的设计目标中, 我们需要兼容              Doop  框架已有的丰富的     Soufflé 指针分析规则. 这就意味着我们需
                 要对  Doop  框架中已有的    Soufflé 指针分析规则进行完全的重写. 然而, 这其中存在两项主要的挑战, 使得像                   Doop
                 开发者曾经做过的那样进行手动转换在软件工程领域变得不可接受.
                    (1) Doop  框架利用  Soufflé 语言的模块化特性动态地根据具体的分析选项情况从规则库中“装配”生成新的规
                 则, 而  DDlog  语言中没有显式的模块化语法. 这就意味着, 对于            Doop  中的数十种精度的分析及其对应的大量的分
   35   36   37   38   39   40   41   42   43   44   45