我在 Clojure 的 J9 JVM 上遇到了问题。
我对 J9 感兴趣,希望 Clojure 不会限制人们对虚拟机的选择。
问题出现在 Windows 和 Linux 上,J9 JVM 的 "11" 和 "15" 版本,以及包括 1.10.1、1.10.2、1.7 和 1.5.1 在内的多个(所有?)Clojure 版本中。
这个问题是异常或错误,通常起源于 clojure.core;通常是一个荒谬的 NullPointerException,发生在 reduce1
中,并且在 J9 JVM 上由 Leiningen 抛出。
问题是不可预测的。但如果我们设置 J9 "始终编译" (-Xcomp),问题就会稳定出现。看来当 J9 "始终解释" (-Xint) 的时候它运行得好。不知何故,本报告中的 clojure
命令似乎不遵守 -J 选项,所以我修改了 clojure 脚本来传递此次实验所需的 JVM 选项。
我用以下方式安装 clojure:
./linux-install-1.10.2.774.sh --prefix ${HOME}/clo
我从 adoptopenjdk.org 下载了适用于 Linux 的 AdoptOpenJDK,版本 11,J9 JVM。
在第一次运行 clojure
时
${HOME}/clo/bin/clojure
它抛出了 NullPointerException。关于这个问题接下来会讲更多。
尝试了各种 JVM 选项后,我发现 -Xint
JVM 选项允许 clojure
下载各种东西并显示 REPL 提示符。根据 java -X
,这个选项意味着“仅解释模式执行”。要使用 -Xint
,我修改了 clojure
来传递 JVM 选项。(不是 clojure 中 Java 调用的所有部分都遵循 -J 选项。)
第一次成功运行后,随后的 clojure
运行通常都能成功地产生 REPL 提示符。
然而,-Xcomp
JVM 选项每次都会导致错误。它意味着“在第一次调用时强制编译方法”。
我在尝试使用 Leiningen 2.9.5 的 Windows 版本时首次遇到了 J9 问题。我的发现路径中的一部分在 Github 上的一个 issue 中:[链接](https://github.com/technomancy/leiningen/issues/2725)
NullPointerException 的堆栈跟踪如下:
Exception in thread "main" java.lang.NullPointerException
at clojure.core.protocols$naive_seq_reduce.invokeStatic(protocols.clj:62)
at clojure.core.protocols$interface_or_naive_reduce.invokeStatic(protocols.clj:72)
...
at clojure.pprint$pprint.invoke(pprint_base.clj:241)
at clojure.lang.Var.invoke(Var.java:384)
at clojure.main$report_error$fn__9186$fn__9187.invoke(main.clj:603)
at clojure.main$report_error$fn__9186.invoke(main.clj:602)
at clojure.main$report_error.invokeStatic(main.clj:601)
at clojure.main$main.invokeStatic(main.clj:666)
at clojure.main$main.doInvoke(main.clj:616)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.lang.Var.applyTo(Var.java:705)
at clojure.main.main(main.java:40)
在随后的运行中,我遇到了不同的错误
Syntax error macroexpanding clojure.core/defn- at (clojure/tools/cli.cljc:124:1).
null
Full report at:
/tmp/clojure-12652663517358293277.edn
该文件显示
{:clojure.main/message
"Syntax error macroexpanding clojure.core/defn- at (clojure/tools/cli.cljc:124:1).\nnull\n",
:clojure.main/triage
{:clojure.error/phase :macro-syntax-check,
:clojure.error/line 124,
:clojure.error/column 1,
:clojure.error/source "cli.cljc",
:clojure.error/symbol clojure.core/defn-,
:clojure.error/path "clojure/tools/cli.cljc",
:clojure.error/class java.lang.NullPointerException},
:clojure.main/trace
{:via
[{:type clojure.lang.Compiler$CompilerException,
:message
"Syntax error macroexpanding clojure.core/defn- at (clojure/tools/cli.cljc:124:1).",
:data
{:clojure.error/phase :macro-syntax-check,
:clojure.error/line 124,
:clojure.error/column 1,
:clojure.error/source "clojure/tools/cli.cljc",
:clojure.error/symbol clojure.core/defn-},
:at [clojure.lang.Compiler checkSpecs "Compiler.java" 6976]}
{:type java.lang.NullPointerException,
:at [clojure.core$every_QMARK_ invokeStatic "core.clj" 2683]}],
:trace
[[clojure.core$every_QMARK_ invokeStatic "core.clj" 2683]
[clojure.core$every_QMARK_ invoke "core.clj" 2676]
[clojure.spec.alpha$pcat_STAR_ invokeStatic "alpha.clj" 1388]
[clojure.spec.alpha$pcat_STAR_ invoke "alpha.clj" 1387]
[clojure.spec.alpha$deriv invokeStatic "alpha.clj" 1542]
[clojure.spec.alpha$deriv invoke "alpha.clj" 1528]
[clojure.spec.alpha$re_conform invokeStatic "alpha.clj" 1669]
[clojure.spec.alpha$re_conform invoke "alpha.clj" 1660]
[clojure.spec.alpha$regex_spec_impl$reify__2510
conform_STAR_
"alpha.clj"
1710]
[clojure.spec.alpha$conform invokeStatic "alpha.clj" 171]
[clojure.spec.alpha$conform invoke "alpha.clj" 167]
[clojure.spec.alpha$macroexpand_check invokeStatic "alpha.clj" 708]
[clojure.spec.alpha$macroexpand_check invoke "alpha.clj" 704]
[clojure.lang.AFn applyToHelper "AFn.java" 156]
[clojure.lang.AFn applyTo "AFn.java" 144]
[clojure.lang.Var applyTo "Var.java" 705]
[clojure.lang.Compiler checkSpecs "Compiler.java" 6974]
[clojure.lang.Compiler macroexpand1 "Compiler.java" 6992]
[clojure.lang.Compiler macroexpand "Compiler.java" 7079]
[clojure.lang.Compiler eval "Compiler.java" 7165]
[clojure.lang.Compiler load "Compiler.java" 7640]
[clojure.lang.RT loadResourceScript "RT.java" 381]
[clojure.lang.RT loadResourceScript "RT.java" 372]
[clojure.lang.RT load "RT.java" 459]
[clojure.lang.RT load "RT.java" 424]
[clojure.core$load$fn__6857 invoke "core.clj" 6115]
[clojure.core$load invokeStatic "core.clj" 6114]
[clojure.core$load doInvoke "core.clj" 6098]
[clojure.lang.RestFn invoke "RestFn.java" 408]
[clojure.core$load_one invokeStatic "core.clj" 5897]
[clojure.core$load_one invoke "core.clj" 5892]
[clojure.core$load_lib$fn__6797 invoke "core.clj" 5937]
[clojure.core$load_lib invokeStatic "core.clj" 5936]
[clojure.core$load_lib doInvoke "core.clj" 5917]
[clojure.lang.RestFn applyTo "RestFn.java" 142]
[clojure.core$apply invokeStatic "core.clj" 669]
[clojure.core$load_libs invokeStatic "core.clj" 5974]
[clojure.core$load_libs doInvoke "core.clj" 5958]
[clojure.lang.RestFn applyTo "RestFn.java" 137]
[clojure.core$apply invokeStatic "core.clj" 669]
[clojure.core$require invokeStatic "core.clj" 5996]
[clojure.core$require doInvoke "core.clj" 5996]
[clojure.lang.RestFn invoke "RestFn.java" 619]
[clojure.tools.deps.alpha.script.make_classpath2$eval140$loading__6738__auto____141
invoke
"make_classpath2.clj"
9]
[clojure.tools.deps.alpha.script.make_classpath2$eval140
invokeStatic
"make_classpath2.clj"
9]
[clojure.tools.deps.alpha.script.make_classpath2$eval140
invoke
"make_classpath2.clj"
9]
[clojure.lang.Compiler eval "Compiler.java" 7181]
[clojure.lang.Compiler eval "Compiler.java" 7170]
[clojure.lang.Compiler load "Compiler.java" 7640]
[clojure.lang.RT loadResourceScript "RT.java" 381]
[clojure.lang.RT loadResourceScript "RT.java" 372]
[clojure.lang.RT load "RT.java" 459]
[clojure.lang.RT load "RT.java" 424]
[clojure.core$load$fn__6857 invoke "core.clj" 6115]
[clojure.core$load invokeStatic "core.clj" 6114]
[clojure.core$load doInvoke "core.clj" 6098]
[clojure.lang.RestFn invoke "RestFn.java" 408]
[clojure.core$load_one invokeStatic "core.clj" 5897]
[clojure.core$load_one invoke "core.clj" 5892]
[clojure.core$load_lib$fn__6797 invoke "core.clj" 5937]
[clojure.core$load_lib invokeStatic "core.clj" 5936]
[clojure.core$load_lib doInvoke "core.clj" 5917]
[clojure.lang.RestFn applyTo "RestFn.java" 142]
[clojure.core$apply invokeStatic "core.clj" 669]
[clojure.core$load_libs invokeStatic "core.clj" 5974]
[clojure.core$load_libs doInvoke "core.clj" 5958]
[clojure.lang.RestFn applyTo "RestFn.java" 137]
[clojure.core$apply invokeStatic "core.clj" 669]
[clojure.core$require invokeStatic "core.clj" 5996]
[clojure.main$main_opt invokeStatic "main.clj" 514]
[clojure.main$main_opt invoke "main.clj" 510]
[clojure.main$main invokeStatic "main.clj" 664]
[clojure.main$main doInvoke "main.clj" 616]
[clojure.lang.RestFn applyTo "RestFn.java" 137]
[clojure.lang.Var applyTo "Var.java" 705]
[clojure.main main "main.java" 40]],
:phase :macro-syntax-check}}
又经过了一次运行,我得到了又一个不同的错误信息
Exception in thread "main" java.lang.NullPointerException
at clojure.core$reduce1.invokeStatic(core.clj:944)
at clojure.core$reduce1.invokeStatic(core.clj:936)
at clojure.core$merge.invokeStatic(core.clj:3052)
at clojure.core$Throwable__GT_map$base__7474.invoke(core_print.clj:491)
at clojure.core$map$fn__5885.invoke(core.clj:2757)
at clojure.lang.LazySeq.sval(LazySeq.java:42)
at clojure.lang.LazySeq.seq(LazySeq.java:51)
at clojure.lang.RT.seq(RT.java:535)
at clojure.lang.LazilyPersistentVector.create(LazilyPersistentVector.java:44)
at clojure.core$vec.invokeStatic(core.clj:379)
at clojure.core$Throwable__GT_map.invokeStatic(core_print.clj:492)
at clojure.main$report_error.invokeStatic(main.clj:593)
at clojure.main$main.invokeStatic(main.clj:666)
at clojure.main$main.doInvoke(main.clj:616)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.lang.Var.applyTo(Var.java:705)
at clojure.main.main(main.java:40)
这个问题在 Clojure 1.5.1中也可复现
$ java -Xcomp -cp clojure-1.5.1.jar clojure.main
Exception in thread "main" java.lang.ExceptionInInitializerError
at java.base/java.lang.J9VMInternals.ensureError(J9VMInternals.java:185)
at java.base/java.lang.J9VMInternals.recordInitializationFailure(J9VMInternals.java:174)
at java.base/java.lang.Class.forNameImpl(Native Method)
at java.base/java.lang.Class.forName(Class.java:413)
at clojure.lang.RT.loadClassForName(RT.java:2098)
at clojure.lang.RT.load(RT.java:430)
at clojure.lang.RT.load(RT.java:411)
at clojure.core$load$fn__5018.invoke(core.clj:5530)
at clojure.core$load.doInvoke(core.clj:5529)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invoke(core.clj:5336)
at clojure.core$load_lib$fn__4967.invoke(core.clj:5375)
at clojure.core$load_lib.doInvoke(core.clj:5374)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invoke(core.clj:619)
at clojure.core$load_libs.doInvoke(core.clj:5413)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invoke(core.clj:619)
at clojure.core$require.doInvoke(core.clj:5496)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.lang.Var.invoke(Var.java:415)
at clojure.main.main(main.java:36)
Caused by: java.lang.NullPointerException
at clojure.core$reduce1.invoke(core.clj:896)
at clojure.core$expand_method_impl_cache.invoke(core_deftype.clj:474)
at clojure.core$_cache_protocol_fn.invoke(core_deftype.clj:542)
at clojure.core.protocols$fn__5979$G__5974__5992.invoke(protocols.clj:13)
at clojure.core$reduce.invoke(core.clj:6177)
at clojure.core$into.invoke(core.clj:6229)
at clojure.main__init.load(Unknown Source)
at clojure.main__init.<clinit>(Unknown Source)