Android ART 在字节码上运行编译时验证,并在使用锁宏时失败。错误类似于 CLJ-1829(在这种情况下,clojure.core.server/stop-server 调用锁宏)。
10-16 14:49:26.801 2008-2008/? E/AndroidRuntime: java.lang.VerifyError: Rejecting class clojure.core.server$stop_server because it failed compile-time verification (declaration of 'clojure.core.server$stop_server' appears in /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)。
似乎在 locking
中的 monitor-enter、monitor-exit 和 try/finally 块中,ART 将这些路径标记为未平衡 monitorenter/monitorexit 字节码。特别是,monitorenter 和 monitorexit 本身可以抛出异常(在 null 锁定对象上)。Java 字节码对这些情况进行了一些复杂的异常表处理,这些处理(afaict)在没有修改 Clojure 编译器的情况下不可能完成。
方法:一种可能的方法是将锁定调用的传递体放在 Java 的 synchronized 块的上下文中执行。这通过将其移交给 Java 来避免了复杂的字节码问题,但具有未知的影响。
补丁:clj-1472-3.patch
另见:与 java synchronized 块相比的字节码检查显示出许多差异
https://gist.github.com/AdamClements/2ae6c4919964b71eb470
审查人员:Alex Miller - 我认为这是一个可行的解决方案,可以修复该问题,由于这种使用的不频繁,我认为这不会成为性能问题。我将标记我认为另一种处理方法是将 locking 制作成具有编译器支持的特称形式,但我不确定这是否值得去做,所以我将把这个交给 Rich 去决定。