I have an unusual requirement: My application generates Java code automatically from a very long script (written in a dynamically-typed language). The script is so long that I hit the maximum method size of 65k of the JVM.
The script consists only of simple instructions on primitive types (no call to other functions besides mathematical ones). It may look like:
...
a = b * c + sin(d)
...
if a>10 then
e = a * 2
else
e = a * abs(b)
end
...
... which is transformed as:
...
double a = b * c + Math.sin(d);
...
double e;
if(a>10){
e = a * 2;
}else{
e = a * Math.abs(b);
}
...
Something like:
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();
}
...
}
Do you know of any other way that would be more efficient? Note that I need the code to run as fast as possible as it will be executed in long loops. I cannot resort to compiling to C, as interoperability is also an issue...
I would also appreciate pointers to libraries that might help me.
We are using the similar approach in one of the projects despite its disadvantages mentioned by other people. We call the multiple generated methods from single launcher method like @Marco13 suggests. We actually calculate (pretty precisely) the size of the generated bytecode and start a new method only when limit is reached. Our math formulas which we translate to Java code are available as AstTree and we have a special visitor which counts the bytecode length per each expression. For such simple programs it's quite stable across Java versions and different compilers. So we don't create methods more than necessary. In our case it's quite hard to emit the bytecode directly, but you can try to do it for your language using ASM or similar library (this way, of course, ASM will calculate the bytecode length for you).
We usually store the data variables in single double[]
array (we don't need other types) and pass it as parameter. This way you don't need the enormous number of fields (sometimes we have thousands of variables). On the other hand local array access may take more bytecode bytes compared to field access for index higher than 127.
Another concern is the constant pool size. We usually have many double constants in the autogenerated code. If you declare many fields and/or methods, their names also take the constant pool entries. So it's possible to hit the class constant pool limit. Sometimes we hit it and generate nested classes to overcome this problem.
Other people suggest to tweak JVM options as well. Use these advices carefully as they will affect not only this autogenerated class, but every other class as well (I assume that other code is also executed in the same JVM in your case).