请在2024年Clojure状态调查!中分享您的想法。

欢迎!请参阅关于页面了解有关如何工作的更多信息。

+52投票
Clojure
已关闭

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字节码对这些情况进行了某些复杂的异常表处理,但没有修改Clojure编译器就无法完成这些操作。

方法:一种可能的方法是在Java的synchronized块中调用传入的body,这避免了无法平衡的字节码问题,但可能对性能有未知的影响。

补丁:clj-1472-3.patch

另请参阅:与java synchronized块的字节码比较,出现了许多不同之处。
https://gist.github.com/AdamClements/2ae6c4919964b71eb470

审查人:由Alex Miller审查 - 我认为这是一个可行的解决方案,可以修复问题,由于它使用的频率不高,我不太担心它是一个性能问题。我将标记我认为另一种处理方法是使locking成为一个特殊形式,并具有编译器支持,但我不知道这是否值得做,因此我将把它留给Rich来决定。

已标记为“fixed”。

41 条回答

0 投票
by

评论者:eraserhd

使用clj-1472-3.patch,我有时可以成功构建。其他时候我会遇到这个错误

`
致命错误:com.oracle.svm.core.util.VMError$HostedError: 具有可重定位指针的对象必须是不可变的

    at com.oracle.svm.core.util.VMError.guarantee(VMError.java:85)                                                      
    at com.oracle.svm.hosted.image.NativeImageHeap.choosePartition(NativeImageHeap.java:492)                            
    at com.oracle.svm.hosted.image.NativeImageHeap.addObjectToBootImageHeap(NativeImageHeap.java:451)                   
    at com.oracle.svm.hosted.image.NativeImageHeap.addObject(NativeImageHeap.java:271)                                  
    at com.oracle.svm.hosted.image.NativeImageCodeCache.addConstantToHeap(NativeImageCodeCache.java:369)                
    at com.oracle.svm.hosted.image.NativeImageCodeCache.addConstantsToHeap(NativeImageCodeCache.java:356)               
    at com.oracle.svm.hosted.NativeImageGenerator.doRun(NativeImageGenerator.java:882)                                  
    at com.oracle.svm.hosted.NativeImageGenerator.lambda$run$0(NativeImageGenerator.java:401)                           
    at java.util.concurrent.ForkJoinTask$AdaptedRunnableAction.exec(ForkJoinTask.java:1386)                             
    at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)                                                  
    at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)                                      
    at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)                                              
    at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)                                     

`

我正在使用Graal rc10,我可以找到的最简代码是生成该错误:

`
(ns rep.core
(:gen-class))

(defn- foo [s]
(locking s

42))

(defn -main
[ & args]
(foo))
`

在非参数对象上锁定可以解决这个问题。

这看起来可能是Graal的问题,所以我会在那里报告。

0 投票
by
_评论者:alexmiller_\

好的,请更新。我们可能还有很长时间才会发布下一个可能包含此内容的版本,因此获得更多反馈是很有用的。
0 投票
by

评论者:bronsa

如果可能的话,我会反对将 locked 转换为一个新的特殊形式。这将使任何与分析相关的库与未来版本不兼容,并可能在依赖升级中引起问题

0 投票
by

评论者:eraserhd

使用刚刚发布的Graal VM rc11,clj-1472-3.patch可以正常运行,没有问题。

0 投票
by

评论者:jare

在从Clojure 1.9迁移到1.10时,使用GraalVM原生编译开始遇到这个错误
最小复现示例是

`
(ns clj10-graal-repro.core
(:require [clojure.spec.alpha :as s])
(:gen-class))

(s/def ::foo (s/coll-of string?))

(defn -main
[ & args]
(println (s/valid? ::foo ["bar"]))
(println *clojure-version*)
`

我认为问题是Clojure 1.10依赖于spec.alpha 0.2.176版本,该版本(链接:[https://github.com/clojure/spec.alpha/commit/31165fec69ff86129a1ada8b3f50864922dfc88a](https://github.com/clojure/spec.alpha/commit/31165fec69ff86129a1ada8b3f50864922dfc88a)文本:使用了锁机制)

更多详情在CLJ-2482

0 投票

评论者:gshayban

我添加了一个补丁(链接:^CLJ-1472-reentrant-finally.patch),它使得锁定宏产生的控制流与javac发出的同步块完全相同。这需要来自编译器的一些帮助。

针对以下代码

synchronized (o) { int i = 400L; }

javac输出

0: aload_0

   1: dup
   2: astore_1
   3: monitorenter
   4: ldc2_w        #7           // BEGIN TRY       // long 400l
   7: lstore_2
   8: aload_1
   9: monitorexit               // END TRY
  10: goto          20           // GOTO RET
  13: astore        4         // BEGIN FINALLY
  15: aload_1                     // store exception
  16: monitorexit           // END FINALLY
  17: aload         4             // rethrow
  19: athrow
  20: return
Exception table:
   from    to  target type
       4    10    13   any
      13    17    13   any

注意

  1. finally块是其自身的异常处理器在异常表中
  2. monitorenter位于try体区域外
  3. 通常,finally体被复制到try体中(就像在正常的TryExpr中一样)

我在Graal 19.0.2上测试了此补丁版本的Clojure,通过aot编译之前评论的示例,然后调用Graal

native-image -cp src:clojure.jar --initialize-at-build-time=clojure --no-server -H:+ReportUnsupportedElementsAtRuntime --no-fallback clj10_graal_repro.core

它成功生成了一个在编译过程中没有错误的二进制文件。然而,Graal用户可能会发现,生成的二进制文件无法运行
找不到clojure/core/server__init.class

可能是由于Clojure 1.10.1延迟初始化clojure.core.server和用户

0 投票
0 投票

评论者:gshayban

那个补丁以一种微妙的方式崩溃了——修复中。

0 投票

评论者:gshayban

(链接:^CLJ-1472-reentrant-finally2.patch)

0 投票
参考:[https://clojure.atlassian.net/browse/CLJ-1472](https://clojure.atlassian.net/browse/CLJ-1472)(由adamclements报告)
0 投票
by

大家好,

我在使用Clojure Spec的一个项目中遇到了这个问题。我创建了一个简单的项目来重现这个问题:[https://github.com/alzadude/cljc-hello-world/tree/graalvm-spec-issue](https://github.com/alzadude/cljc-hello-world/tree/graalvm-spec-issue)

我试图使用Graal的native-image功能,并应用到Clojure补丁来创建一个可运行的二进制文件。然而,当我使用修改过的Clojure jar文件时,我仍然收到了“不平衡监视器”错误。我做错了什么?

谢谢!

1 使用补丁构建Clojure

cd /mnt/d/Projects/clojure
patch -p1 < /mnt/c/Users/alex/Downloads/CLJ-1472-reentrant-finally2.patch
mvn clean
mvn -Plocal install -Dmaven.test.skip=true

2 尝试使用clj/deps.edn创建Graalvm原生化镜像

cd /mnt/d/Projects/cljc-hello-world
GRAALVM_HOME=/usr/local/graalvm-ce-19.2.0.1/ clojure -Anative-image

即使在应用补丁后,我还是得到了“不平衡监视器”错误

Cleaning target
Creating target/classes
  Compiling hello-world.core
Creating target/cljc-hello-world
ERROR! Warning: Aborting stand-alone image build. unbalanced monitors: mismatch at monitorexit, 96|LoadField#lockee__5436__auto__ != 3|LoadField#lockee__5436__auto__
Detailed message:
Call path from entry point to clojure.spec.gen.alpha$dynaload$fn__2628.invoke():
        at clojure.spec.gen.alpha$dynaload$fn__2628.invoke(alpha.clj:21)
        at clojure.lang.AFn.run(AFn.java:22)
        at java.lang.Thread.run(Thread.java:748)
        at com.oracle.svm.core.thread.JavaThreads.threadStartRoutine(JavaThreads.java:460)
        at com.oracle.svm.core.posix.thread.PosixJavaThreads.pthreadStartRoutine(PosixJavaThreads.java:193)
        at com.oracle.svm.core.code.IsolateEnterStub.PosixJavaThreads_pthreadStartRoutine_e1f4a8c0039f8337338252cd8734f63a79b5e3df(generated:0)

Warning: Use -H:+ReportExceptionStackTraces to print stacktrace of underlying exception
Warning: Image 'target/cljc-hello-world' is a fallback image that requires a JDK for execution (use --no-fallback to suppress fallback image generation).

3 尝试使用native-image和显式类路径创建Graalvm原生化镜像,以排除deps.edn/cambada等问题

cd /mnt/d/Projects/cljc-hello-world
clojure -Auberjar
/usr/local/graalvm-ce-19.2.0.1/bin/native-image --class-path ../clojure/target/clojure-1.11.0-master-SNAPSHOT.jar --report-unsupported-elements-at-runtime --initialize-at-build-time -jar ./target/cljc-hello-world-1.0.0-SNAPSHOT-standalone.jar -H:Name=./target/cljc-hello-world

我仍然得到了“不平衡监视器”错误

Build on Server(pid: 10328, port: 64314)*
[./target/cljc-hello-world:10328]    classlist:   5,817.52 ms
[./target/cljc-hello-world:10328]        (cap):   2,576.68 ms
[./target/cljc-hello-world:10328]        setup:   3,923.40 ms
[./target/cljc-hello-world:10328]     analysis:  11,800.59 ms
Warning: Aborting stand-alone image build. unbalanced monitors: mismatch at monitorexit, 96|LoadField#lockee__5436__auto__ != 3|LoadField#lockee__5436__auto__
Detailed message:
Call path from entry point to clojure.spec.gen.alpha$dynaload$fn__2628.invoke():
        at clojure.spec.gen.alpha$dynaload$fn__2628.invoke(alpha.clj:21)
        at clojure.lang.AFn.run(AFn.java:22)
        at java.lang.Thread.run(Thread.java:748)
        at com.oracle.svm.core.thread.JavaThreads.threadStartRoutine(JavaThreads.java:460)
        at com.oracle.svm.core.posix.thread.PosixJavaThreads.pthreadStartRoutine(PosixJavaThreads.java:193)
        at com.oracle.svm.core.code.IsolateEnterStub.PosixJavaThreads_pthreadStartRoutine_e1f4a8c0039f8337338252cd8734f63a79b5e3df(generated:0)

Warning: Use -H:+ReportExceptionStackTraces to print stacktrace of underlying exception
Build on Server(pid: 10328, port: 64314)
[./target/cljc-hello-world:10328]    classlist:     217.19 ms
[./target/cljc-hello-world:10328]        (cap):   1,244.81 ms
[./target/cljc-hello-world:10328]        setup:   1,535.89 ms
[./target/cljc-hello-world:10328]   (typeflow):   1,309.40 ms
[./target/cljc-hello-world:10328]    (objects):   1,430.65 ms
[./target/cljc-hello-world:10328]   (features):     120.57 ms
[./target/cljc-hello-world:10328]     analysis:   2,906.19 ms
[./target/cljc-hello-world:10328]     (clinit):      88.70 ms
[./target/cljc-hello-world:10328]     universe:     250.93 ms
[./target/cljc-hello-world:10328]      (parse):     315.62 ms
[./target/cljc-hello-world:10328]     (inline):     739.40 ms
[./target/cljc-hello-world:10328]    (compile):   3,100.68 ms
[./target/cljc-hello-world:10328]      compile:   4,401.60 ms
[./target/cljc-hello-world:10328]        image:     296.36 ms
[./target/cljc-hello-world:10328]        write:     195.80 ms
[./target/cljc-hello-world:10328]      [total]:   9,868.80 ms
Warning: Image './target/cljc-hello-world' is a fallback image that requires a JDK for execution (use --no-fallback to suppress fallback image generation).
...