Android ART在字节码运行时进行验证,并在使用锁定宏时失败。错误看起来像是CLJ-1829中看到的(在这种情况下,clojure.core.server/stop-server调用了锁定宏)
10-16 14:49:26.801 2008-2008/? E/AndroidRuntime: java.lang.VerifyError: 驳回类 clojure.core.server$stop_server,因为它验证失败('clojure.core.server$stop_server' 的声明出现在 /data/app/com.clojure_on_android-1/base.apk 中)
原因:从一个Android问题讨论中(https://code.google.com/p/android_issues/detail?id=80823),这似乎是因为在JVM规范中更加严格地执行“结构化锁定”规定(https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-2.html#jvms-2.11.10)。
锁定宏中的 monitor-enter、monitor-exit 和 try/finally 块的混合似乎创建了一些ART被标记为不平衡 monitorenter/monitorexit 字节码路径。特别是,monitorenter 和 monitorexit 本身可能会抛出异常(在null锁定对象上)。Java字节码对这些情况进行了一些复杂的异常表处理,这些处理(据我所知)没有修改Clojure编译器是无法进行的。
方法:一个可能的方法是使锁定在Java的synchronized块中调用传递的身体。这避免了通过将其交给Java处理的复杂字节码问题,但具有未知的影响。
补丁:clj-1472-3.patch
另请参阅:与Java synchronized块相比的字节码分析发现了一些差异。
https://gist.github.com/AdamClements/2ae6c4919964b71eb470
审核人:亚历克斯·米勒 - 我认为这是一个可行的方案,可以解决问题。由于其使用频率不高,我并不特别担心它会成为性能问题。我将标记这一点,我认为处理这种方式的一个方法是使锁定
成为一个特殊的格式,并具有编译器支持,但我不确定这是否值得去做,所以我将留给瑞奇来决定。