可自定义的静态Java调用图生成器?

时间:2012-06-12 07:29:04

标签: java profile graphviz dfa call-graph

我必须重构并维护一堆看起来很糟糕的Java类。许多人都有以下实施模式

class Machine {
    public int advance(int state) {
        switch(state) {
        case 7:  return step_7();
        case 13: return step_13();
        case 4:  return step_4();
        }
    }
    private int step_7() {
        if(something) return 13; else return 4;
    }
    private int step_13() {
        ...
        return 4;
    }
    private int step_4() {
        if(miep) return 7;
        ...
        return 13;
    }
}

从此我想生成一个图形(使用Graphviz和dot) - 一种“静态调用图”,但不完全是。

除了使用Perl或Python自己解析Java代码之外,我在这里游戏如何自动执行此操作。

我真正想要的是拥有一个抽象语法树(AST)或类似我可以浏览的类,同时打印dot - 代码。

  • 如何在这里生成可遍历的AST?我想这将在Java中完成遍历,但如果输出是任何文本表示,那么就可以了(gprof来介意)。
  • 任何其他方法,不使用AST?也许我只是盲目而且有一种更好,更简单的方法。

1 个答案:

答案 0 :(得分:6)

有各种各样的Java解析器可以生成AST:

但在处理真正的计算机语言时,AST几乎还不够。例如,要确定调用站点可以调用哪些方法,您需要全名和类型解析,以便您可以准确地确定成千上万个 foo foo 可能会调用位于源文件中的。由于其复杂的查找规则,这对于Java来说并不容易计算。有关此主题的更多详细信息,请参阅我在Life After Parsing上的文章。除非您不关心答案的准确性,否则您不太可能通过简单地使用Python或Perl来复制这些功能。 Eclipse JDT可能具有名称解析;我不确定。 ANTLR Java解析器没有;他们只是解析。

DMS的Java前端具有Java的全名和类型解析。要静态确定您的调用图,您基本上需要进行points-to分析;包含任何类型对象的每个字段本质上都是一个指针,并且您想知道每个指针,特别是它可能选择哪些对象,然后您需要构建一个(全局)调用图来获取所需的基本信息。 DMS为计算各种control and data flow analysis提供支持; Java前端提供基本的流程事实,它将计算本地数据流分析。要获得分数分析,您必须使用DMS的帮助汇总这些事实,然后构建该调用图。对于Java,我们不会使用DMS,但是我们已经大规模地使用C(一个系统中有2600万行),而Java的模拟将非常相似并且使用大多数相同的DMS机制;一旦进行了点分析,调用图构造就相当容易了。我们已经导出了像DOT图这样的图形;你需要过滤它们以获得DOT实际上可以渲染的子图。

您可以从类二进制分析文件(例如Wala)收集流分析事实。您仍将面临构建点分析和全局调用图的问题。我记得Wala在这里有一些帮助,但我不记得是什么了。

您也许可以使用profiler tool收集动态构造的调用图。除非您在分析过程中仔细运用所有系统功能,否则这样的调用图可能非常不完整;这很难做到。

最终,您可能想要更改代码。也许您想要内联 stepN 函数。也许你想手工完成它,但如果你的代码充满了这些东西,也许你想要自动化。像DMS这样的工具提供了源到源的转换,实现了这种自动代码更改。 Wala在这里不会帮助你。