Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 生成调用图的好算法?_Java_Algorithm_Design Patterns_Call Graph - Fatal编程技术网

Java 生成调用图的好算法?

Java 生成调用图的好算法?,java,algorithm,design-patterns,call-graph,Java,Algorithm,Design Patterns,Call Graph,我正在编写一些代码,为特定的中间表示生成调用图,而无需通过静态扫描IR代码来执行它。IR代码本身并不太复杂,我对函数调用序列有很好的理解,所以我需要做的就是跟踪调用。我目前的做法很明显: 跟踪我们在哪里 如果我们遇到一个函数调用,分支到那个位置,执行并返回 在分支时,在调用者和被调用者之间放置一个边缘 我对自己的目标感到满意,但我想确保我不会在这里重新设计方向盘,不会面临困境。我想知道是否有任何公认的好算法(和/或设计模式)可以有效地做到这一点 更新: IR代码是从一种类似于Java的hom

我正在编写一些代码,为特定的中间表示生成调用图,而无需通过静态扫描IR代码来执行它。IR代码本身并不太复杂,我对函数调用序列有很好的理解,所以我需要做的就是跟踪调用。我目前的做法很明显:

  • 跟踪我们在哪里
  • 如果我们遇到一个函数调用,分支到那个位置,执行并返回
  • 在分支时,在调用者和被调用者之间放置一个边缘
我对自己的目标感到满意,但我想确保我不会在这里重新设计方向盘,不会面临困境。我想知道是否有任何公认的好算法(和/或设计模式)可以有效地做到这一点

更新:
IR代码是从一种类似于Java的homebrewn语言中反汇编出来的字节码,看起来像。

我不知道算法,但做得不错。值得一看。它不会很长,应该适合检查现有的设计模式。

从学术角度来看,以下是一些注意事项:

  • 你在乎保守/正确吗?例如,假设您正在分析的代码包含通过函数指针的调用。如果您只是生成文档,那么就没有必要处理这个问题。如果您正在进行可能出错的代码优化,则需要假设“通过指针调用”的意思是“可以是任何东西”

  • 小心异常执行路径。您的IR可能会也可能不会从您这里抽象出这一点,但请记住,许多操作可能会抛出语言级异常以及硬件中断。同样,这取决于您以后要如何处理调用图

  • 考虑如何处理循环(例如递归、相互递归)。这可能会影响以后编写代码遍历图的方式(即,它们需要某种“已访问”的设置,以避免永远遍历循环)

干杯

3月6日更新

根据添加到原始帖子中的额外信息:

  • 对虚拟方法调用要小心。请记住,通常不知道将执行哪个方法。您可能必须假设调用将转到特定类的任何子类。标准示例有点像这样:假设您有一个
    ArrayList
    ,并且您有
    类B扩展了a
    。基于随机数生成器,您将向列表中添加
    a
    B
    的实例。现在为列表中的所有
    x
    调用
    x.foo()
    ,其中
    foo()
    a
    中的一个虚拟方法,在
    B
    中有一个覆盖。因此,仅通过查看源代码,无法知道循环是在运行时调用
    A.foo
    B.foo
    ,还是两者都调用

+1谢谢。很抱歉没有正确地澄清。我更新了我的问题。我遇到了pycallgraph,但我不想执行代码,而是想通过解析我的中间代码来生成调用图。OP还必须知道符号的运行时绑定;他可能无法获得实际调用图的真实图像。许多语言,包括我认为的Python,在加载新代码时会(重新)绑定一个符号。因此,对函数F到X的调用进行静态分析,其本身的解释可能不会反映出X以后会绑定到一个毛球上(或者更糟,绑定到最终再次调用F的东西上)。@Ira Baxter:这一点很好。我不确定被分析的语言是什么样子;我会要求OP澄清。@phooji:+1了解提示。我已经接受了这个答案。如果您有时间的话,您能详细介绍一下虚拟方法调用吗?代码中目前有三种类型:
调用静态
调用直接
调用虚拟
。虽然我理解了您提到的随机数生成器示例的部分,但我仍然不清楚字节码何时被分解为
invoke virtual
,以及动态重新绑定有何帮助。如果我感兴趣的只是构造近似的调用图,你能建议我应该采取什么步骤来部分解决这个问题吗?@Legend:谢谢你的投票。我不熟悉JVM(或Jasmin)规范的细节。然而,如果您可以进行完整的往返(编译-反汇编),那么您可能可以通过做一些实验来找到答案。下面是我对
foo
virtual方法的猜测,如果您的代码看起来像
ax=newb();x、 foo()
:“push object ref x;push args(none);invokevirtual A.foo()。”请注意,如果确实是这样,那么您必须在分析代码中模拟虚拟方法查找。(哦,“动态重新绑定”只是另一个可以在运行时修改(变量、方法、类、模块)名称的示例。)你能多说一点你想分析的IR吗?它看起来像什么?它与绑定和函数调用相关的特性是什么?@phooji:当然。它是由JReveal Jasmine反汇编程序生成的字节码反汇编生成的IR。它似乎没有描述任何关于重新绑定的内容,但如果我发现任何新的内容,我会发回。但是我可以肯定地说没有指针,因为它是在反汇编Java程序;请参阅下面的更新答案。@phooji:谢谢您抽出时间。我刚刚接受了你的回答并添加了一条评论。