Eri*_*uth 5 java jvm code-generation auto-generate
我有一个不寻常的要求:我的应用程序从一个非常长的脚本(用动态类型语言编写)自动生成Java代码.脚本太长了,我达到了JVM的最大方法大小65k.
该脚本仅包含关于基本类型的简单指令(除了数学类型之外不调用其他函数).它可能看起来像:
...
a = b * c + sin(d)
...
if a>10 then
e = a * 2
else
e = a * abs(b)
end
...
Run Code Online (Sandbox Code Playgroud)
...转换为:
...
double a = b * c + Math.sin(d);
...
double e;
if(a>10){
e = a * 2;
}else{
e = a * Math.abs(b);
}
...
Run Code Online (Sandbox Code Playgroud)
就像是:
class AutoGenerated {
double a,b,c,d,e,....;
void run1(){
...
a = b * c + sin(d);
...
run2();
}
void run2(){
...
if(a>10){
e = a * 2;
}else{
e = a * Math.abs(b);
}
...
run3();
}
...
}
Run Code Online (Sandbox Code Playgroud)
你知道其他任何更有效的方法吗?请注意,我需要尽可能快地运行代码,因为它将在长循环中执行.我不能求助于编译C,因为互操作性也是一个问题......
我也很感谢能够帮助我的图书馆指南.
尽管其他人提到了它的缺点,但我们在其中一个项目中使用了类似的方法。我们像 @Marco13 建议的那样从单个启动器方法调用多个生成的方法。我们实际上计算(非常精确)生成的字节码的大小,并仅在达到限制时才启动新方法。我们将数学公式转换为 Java 代码,并以 AstTree 形式提供,并且我们有一个特殊的访问者来计算每个表达式的字节码长度。对于这样简单的程序,它在 Java 版本和不同编译器之间相当稳定。所以我们不会创建不必要的方法。在我们的例子中,直接发出字节码是相当困难的,但是您可以尝试使用 ASM 或类似的库为您的语言执行此操作(当然,ASM 会为您计算字节码长度)。
我们通常将数据变量存储在单个double[]数组中(我们不需要其他类型)并将其作为参数传递。这样您就不需要大量的字段(有时我们有数千个变量)。另一方面,与索引高于 127 的字段访问相比,本地数组访问可能需要更多字节码字节。
另一个问题是常量池的大小。我们通常在自动生成的代码中包含许多双精度常量。如果声明许多字段和/或方法,它们的名称也会采用常量池条目。因此有可能达到类常量池的限制。有时我们会遇到这个问题并生成嵌套类来克服这个问题。
其他人也建议调整 JVM 选项。请小心使用这些建议,因为它们不仅会影响这个自动生成的类,还会影响所有其他类(我假设在您的情况下其他代码也在同一个 JVM 中执行)。