问题:我有一个方法可以编译超过8000字节的Java字节码。 HotSpot有一个神奇的限制,使得JIT不会超过8000字节的方法。 (是的,有一个巨大的方法是合理的。这是一个标记器循环。)该方法在库中,我不希望要求库的用户必须配置HotSpot来停用魔术限制。
观察:反编译字节码表明Eclipse Java Compiler生成了许多无意义的getos。 (javac甚至更糟。)也就是说,有些只能从跳跃中获得。显然,跳转到goto的跳转应该直接跳到goto跳转的地方,并且goto应该被消除。
问题:Java 5类文件是否有一个字节码优化器可以展平无意义的跳转链,然后删除不必要的getos?
编辑:我的意思是这样的模式:
8698: goto 8548
8701: goto 0
显然,第二个goto只能通过跳转到8701到达,这可能是直接跳转到0。
在第二次调查中,这种可疑模式更为常见:
4257: if_icmpne 4263
4260: goto 8704
4263: aload_0
显然,有人希望编译器将“不等于”比较反转为“相等”比较,跳转到8704并消除goto。
答案 0 :(得分:1)
我感觉到你的痛苦。我必须编写一个解析器,它有大约5kloc的if(str.equals(...))代码。我按照parse1,parse2等的方式划分了几个方法。如果parse1没有得到解析的答案,则调用parse2等。这不一定是最佳实践,但它确实做了你需要的
答案 1 :(得分:0)
一种方法可以编译超过8000个字节?有人理解这个代码吗?是可以测试的吗?尝试使用有意义的名称将其拆分为多个(私有?)方法,而不是与优化器争吵!
好的,也许有合法的大型方法。但很抱歉,这个问题没有提示。
答案 2 :(得分:0)
如果不使用调试符号(即javac中的-g标志)进行编译,是否会有所不同?这可能会使方法低于魔法限制。
答案 3 :(得分:0)
将方法重构为子方法是不可能的?无论如何,现代JIT都会内联这些电话。
答案 4 :(得分:0)
如果它是一个标记化器循环,那么使用数据驱动的映射集和适当的一些反射来做它会更好吗?
因此,您将令牌匹配存储在一个结构中,该结构将它们映射到有关该令牌的语法和实现相关功能的方法的数据。查找可以在结构上进行优化,避免大循环。
这引入了保持数据和实现保持同步的问题,但您可以使用doclet或可能的注释从代码库生成数据。
如果不确切知道你的大方法是做什么的,我们只能尝试以你认为最好的方式进行优化(而且无论如何显然都不可能)。
答案 5 :(得分:0)
如果在类上运行字节码收缩器/混淆器,性能会提高吗?例如,yguard,proguard,......
也许您可以使用asm编写一个类文件后处理器,因为您的用例非常具体。
即使你删除了所有无意义的怪物,这是否会让你处于魔力限制之下?
答案 6 :(得分:0)
我之前听说过的bytecode libraries提及BCEL和ASM的列表,以及其他许多人在做各种事情。