Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

修复access-inline插件遇到access$方法中只有LDC指令时的NPE问题 #42

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

Xiaojuanmao
Copy link

复现步骤

  1. 先写一个类,如下:
class TestClass {
  fun func1(): Int {
    return ARG_1 + ARG_2
  }
}

private val ARG_1 = 1
private val ARG_2 = 0
  1. 将Bytex的access-inline与const-inline插件集成,顺序为先执行const,再执行access
    apply plugin: 'bytex.const_inline'
    const_inline {
        enable true
        enableInDebug true
        logLevel "INFO"
        autoFilterReflectionField = true  //使用插件内置的反射检查过滤掉可能的反射常量,建议为true
        //supposesReflectionWithString = false //使用插件内置字符串匹配可能反射常量,建议为false
        skipWithRuntimeAnnotation true //过滤掉带有运行时注解的常量,推荐true
        skipWithAnnotations = [
                //过滤掉被注解注释过的常量,包含class
                "android/support/annotation/Keep",
        ]
        whiteList = [
                //跳过优化的名单
                "com/meizu/cloud/*",
        ]
    }

    apply plugin: 'bytex.access_inline'
    access_inline {
        enable true
        enableInDebug true
        logLevel "DEBUG"
    }

  1. 编译一遍就能看到有如下错误栈:
Caused by: java.lang.NullPointerException
        at com.ss.android.ugc.bytex.access_inline.Context.prepare(Context.java:96)
        at com.ss.android.ugc.bytex.access_inline.AccessInlinePlugin.beforeTransform(AccessInlinePlugin.java:40)
        at com.ss.android.ugc.bytex.common.flow.main.MainTransformFlow.lambda$beforeTransform$5(MainTransformFlow.java:144)
        at com.ss.android.ugc.bytex.transformer.concurrent.Worker.lambda$null$0(Worker.java:59)

原因分析

  1. access-inline插件崩溃在Context.prepare()方法,由于target为null导致
  2. target在PreProcessClassVisitor.refine()方法执行时设置,但在处理access$方法中只包含LDC指令时,会出现没有设置target的情况。(经过const-inline插件优化过后,ARG_2 参数access$方法中的GET STATIC -> LDC)
  3. 如果将ARG_2的值从0改为非0(例如2),变成了运行期常量,上述问题不会有,因为const-inline插件不对其处理。kotlin里private val本不应该被const-inline识别并处理,目前看来由于赋值的是默认值0,ARG_2成了编译期常量

处理
跳过包含LDC指令的access$方法内联

@yangzhiqian
Copy link
Contributor

感谢反馈。我本地已经复现了,const_inline插件破坏了标准了access方法指令,这里access方法判断不严谨。
这里的编译器常量和运行期常量在kotlin代码中也有些特殊,val有时候是编译器常量有时候不是,对插件之间的冲突有些干扰。
看到你的mr中只有判断ldc指令的判断,是不是应该判断target,而不仅仅是ldc?同时这里应该使用MethodNode更合适,可以顺带提一下。

@Xiaojuanmao
Copy link
Author

  1. 之前只判断LDC会导致方法中包含LDC指令的方法内联执行被跳过,已更正为在refine()方法最后对target进行判断
  2. MethodVisitor已替换为MethodNode

@Xiaojuanmao
Copy link
Author

大佬,pull request 求看一眼 Orz

@Xiaojuanmao
Copy link
Author

还有一个对插件的思考,const-inline不会对带有PUT_STATIC指令操作的进行优化,(上面例子中的ARG_1理论上是可以优化的,也被忽略了),从字节码的角度过滤可能成本比较大,可以把这些情况做一个扫描上报,如果优化空间较大,可以从代码规范的角度来做(把ARG_1的写法换成 private val const ARG_1 = 1)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants