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,因为它在编译时验证失败(在 /data/app/com.clojure_on_android-1/base.apk 中声明了 'clojure.core.server$stop_server')
原因: 从 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和lock代码中的try/finally块的组合创建了ART标记为不平衡monitorenter/monitorexit字节码的路径。特别是,monitorenter和monitorexit本身可以抛出(在null锁定对象上)。Java字节码执行一些非常技巧性的异常表处理来覆盖这些情况,这些情况(afaict)如果不修改Clojure编译器,就不可能做到。
方法:一个可能的方法是将锁定让在Java同步块中调用传入的主体。这通过将问题交给Java来避免复杂的字节码,但具有未知的影响。
补丁:clj-1472-3.patch
另请参阅:将字节码与java同步块进行比较,可以发现许多不同之处
https://gist.github.com/AdamClements/2ae6c4919964b71eb470
筛过的人:Alex Miller - 我认为这是一个可行的方案,可以修复问题,由于它的使用频率不高,我并不是很担心它会成为性能问题。我将标记我认为另一种处理方法是使locking成为具有编译器支持的特设形式,但我不确定这是否值得做,所以我会留给Rich决定。