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)。
似乎在locking
中使用monitor-enter、monitor-exit和try/finally块的组合创建了一些路径,ART将其标记为不平衡的monitorenter/monitorexit字节码。尤其是,monitorenter和monitorexit本身可以抛出异常(在null锁定对象上)。Java字节码对这些情况进行了复杂的异常表处理,这(据我所知)是不可能在不修改Clojure编译器的情况下做到的。
方法:一种可能的方法是在Java的synchronized块中调用传递的body,以此在锁定上下文中调用。这种方法避免了困难字节码的问题,但不知道其性能影响。
补丁:clj-1472-3.patch
另请参阅:将字节码与Java synchronized块的比较显示出许多不同的地方
https://gist.github.com/AdamClements/2ae6c4919964b71eb470
筛选:由Alex Miller筛选 - 我认为这是一个可行的解决方案,可以修复问题。由于其使用频率不高,我认为这不太可能成为性能问题。我将标记我认为另一种处理方法是使locking
成为一个特殊形式并有编译器支持,但我不确定这是否值得去做,所以我将把它留给Rich来决定。