ASM编译问题"stack overflow"

背景

最先在腾讯Matrix中遇到这个编译问题, 当时认为是首包方法数超过了65536.
然而, 不断精简首包方法数依然不能解决. 因此确认和方法数无关.没法解决, 只得放弃使用腾讯Matrixjava

使用ASM开发自研的插件, 也遇到一样的"stack overflow"问题, 致使编译失败. 问题报错以下:
数组





问题跟踪

既然是自研的代码, 有足够的自由空间, 那必定能够着手解决这个问题.jvm

根据异常堆栈提示, 在"ExecutionStack.java:168"位置抛出异常:
学习


看起来, 是由于某个计算的结果值超过了stack.length. 就主动抛出了异常"overflow"gradle

那么这个stack是什么? 其length是从哪里来的?
继续跟代码可知是ExecutionStack初始化是给到的:
插件

继续翻代码, 发现这段:
3d

是Frame类初始化时传入的值. 而这个 (int maxLocals, int maxStack)有点眼熟:
ASM里注入方法时的 这个visitMaxs方法, 参数名一致, 彷佛问题就是出在这里. 可是还须要验证.



摸索修改

首先, visitMaxs()是在ASM中的, 而ExecutionStack是gradle中的, 二者来源其实并不一样.
顺代码梳理, 应该很花时间. 简单网搜了下, 都和jvm的==方法栈长度==有关, 看起来有点联系.code

其次, gradle的源码是不能改的, 深刻的学习jvm得花点时间.
只有ASM的这个visitMaxs()方法, 咱们能够重写. 那就从visitMaxs()入手吧
重写visitMaxs()的关键就是传入正确的maxStack, 和maxLocals. 那么==问题的关键就是如何正确传入这两个值==
使用AS的ASM Bytecode Outline插件能够查看java文件的字节码, 以此确认正确的值: cdn

确认值以后重写visitMaxs()方法:
blog

尝试编译, 成功!





根本缘由

解决后总结根本缘由:

  1. 利用ASM插桩更改了方法的实际栈深度, 可是没有同步更新正确的深度值
  2. ASM提供了ClassReader.EXPAND_FRAMES 和 ClassWriter.COMPUTE_MAXS来计算方法栈深度,
    可是在某些状况下, ==ASM没有计算出正确的方法栈深度==, 还很消耗编译时间.
  3. 这个问题, 和方法数超过65536没有任何关系.

PS: 另外还有一种状况, 也是visitMaxs()传入的参数不正确致使的:

小结

经验上看, 利用ASM插桩碰到和数组长度相关的编译异常, 能够优先确认visitMaxs()传入的值是否正确.

相关文章
相关标签/搜索