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和locking中的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 - 我认为这是一个可行的方案,可以解决这个问题,由于使用频率不高,我并不担心这会是一个性能问题。我将会标记这个问题,我认为另一种处理方法是让locking成为一个具有编译器支持的特称,但我不确定这是否值得去做,所以我会留给 Rich 决定。