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本身可以抛出(在空锁定对象上)。Java字节码对这些情况做了一些复杂的异常表处理,这在没有修改Clojure编译器的情况下是不可能做到的。
方法:一种可能的方法是让锁定在Java的synchronized块上下文中调用传入的主体。这避免了由Java处理字节码问题,但有未知的性能影响。
修复:clj-1472-3.patch
另请参阅:与java synchronized块的字节码比较显示出许多不同之处
https://gist.github.com/AdamClements/2ae6c4919964b71eb470
审核人:Alex Miller - 我认为这是一种可行的解决方案,可以解决这个问题,由于其使用频率不高,我并不担心它是性能问题。我将标记这一点,我认为另一种处理方式是将 锁定
制作成具有编译器支持的特特殊形式,但我不确定这是否值得做,所以我把这个问题留给Rich来做决定。