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 的同步块上下文中调用传入的身体,这样就能避免麻烦的字节码问题,但是对性能的影响尚不清楚。
补丁: clj-1472-3.patch
也参见: 将字节码与 Java synchronized 块进行比较表明存在许多差异
https://gist.github.com/AdamClements/2ae6c4919964b71eb470
审核者: Alex Miller - 我认为这是一种可行的方案,可以解决问题,而且由于使用频率不高,我对它成为性能问题的担忧不大。我将指出我认为另一种处理方法是使 锁定
成为一个特殊形式,并带有编译器支持,但我不确定这样做是否值得,所以我会让 Rich 决定。