我是编译器设计的新手,并且几年没有使用java。
使用this和paper 在类层次结构分析和快速类型分析之后,它将获得进行去虚拟化的信息。但是在哪里修补源代码或字节代码的信息。以及如何检查结果?
试图理解事情是如何发生的,但却停留在这里。 例如:我们有一个从上面指定的纸张中获取的示例程序。
def pdf_test
require "prawn"
Prawn::Document.generate("hello.pdf") do
text "Hello World!"
end
end
使用Class hieracrchy方法我们可以得出结论,因为没有子类覆盖hasRightToVote(),动态方法调用可以用对Estonian #hasRightToVote()的静态过程调用替换。但是在哪里更换这些信息又如何?如何告诉JVM(提供JVM)我们在分析期间收集的信息。
您无法更改源代码并将其放在那里?任何人都可以给我一个例子,这样我就可以开始尝试新的分析方法,并且仍然可以修补这些信息。 感谢。
答案 0 :(得分:2)
类层次结构分析是虚拟机本身在运行时完成的优化,您无需告知 VM。它只是根据类文件中可用的信息自行进行分析。
答案 1 :(得分:1)
通常情况下,分析结果通常存储为与程序表示形式的某种关联,或者立即用于实现优化,因此不会出现任何问题。需要存储。
你是对的:通常没有"好"使用分析结果注释源代码的方法(您可以将Java注释用作 a 方式)。但是编译器已经阅读了源代码并且没有再次读取它。
通常,在任何严肃的分析/优化开始之前,编译器会对程序进行解析并构建各种类似编译器的结构(AST,符号表,控制流图,数据流弧等)。程序的低级模型(运算符上的数据流)通常是分析的,优化分析器将用它的意见来装饰这个结构,或者通常直接修改这个结构以实现优化的效果。
使用Java,有两个机会:在JavaC和JITter中。我的理解(可能是错误的,可能因JavaC实现而异)是JavaC中根本没有进行太多优化;它只是生成天真的JVM字节码,并且所有实际工作都在JITter中完成。 JITter没有源代码,但是它可以对经典编译器结构上可以执行的字节代码进行所有相同类型的分析(控制流,数据流......),从而实现相同的效果
答案 2 :(得分:0)
我有同样的怀疑和 Rohan Padhey 清除了那些。
在Java中,我认为没有办法在字节码中指定虚方法调用的单一性。去虚拟化分析通常发生在JIT编译器中,它将字节码编译为本机代码,并使用动态分析进行编译。
为什么修补是一个问题:
在Java字节码中,唯一的方法调用指令是:invokestatic,invokedynamic,invokevirtual,invokeinterface和invokespecial(最后一个用于构造函数等)。唯一不引用虚方法表查找的调用类型是invokestatic调用,因为静态方法不能被覆盖并在对象上以多态方式使用。
因此,虽然无法对目标方法执行编译时规范,但可以使用静态调用替换虚拟调用。怎么样?考虑一个对象" x"使用方法" foo"和一个呼叫站点:
x.foo(arg1, arg2, ...)
如果您确定知道" x"属于" A",然后您可以将其转换为:
A.static_foo(x, arg1, arg2, ...)
其中" static_foo"是一个在A类中新创建的静态方法,它的正文包含" foo()"的主体。在" A"本来会做的,除了引用"这个"现在,身体内部应该被第一个参数替换,无论你怎么称呼它。
这正是Soot中整个Jimple-Optimization-Pack(WJOP)的作用。
关于使用Soot的静态分析,有一个优化包使用变通方法进行虚拟化:https://github.com/Sable/soot/wiki/Whole-program-Devirtualization-Optimizations 但那只是一个黑客。
为什么JIT Times会更好:
JIT做得更好是因为静态分析必须是合理的,因为你需要确保在进行这种转换时,100%的时间内虚拟调用的目标将是一个类。使用JIT编译,您可以找到更多优化机会,因为即使目标在90%的时间内都是单个类,但不是10%,您可以及时编译代码以使用最常用的路由,并且在这种预测错误的10%的情况下回退到使用字节码,因为你可以动态地检查这个错误。虽然回落是昂贵的,但90%的时间正确预测的常见情况会带来整体效益。通过静态变换,您必须决定是否优化,最好是声音。