AOT compilation can cause java.lang.NoSuchFieldError: __thunk__0__
Description
Environment
Activity
import July 14, 2017 at 12:47 PM
Comment made by: aroemers
I'm not sure the issue is (only) due to having an AOT compiled library. I started rewriting parts of the slf4j-timbre library, in order to remove the need for AOT [1]. But I noticed the problem in that version remains when the TimbreLoggerAdapter
loads the slf4j-timbre.adapter
namespace, instead of a Clojure namespace, during compilation. So as soon as a SLF4J log statement is performed during compilation, the `_thunk_` issue still ensued when running the result.
A workaround however is to require
the slf4j-timbre.adapter
namespace as one of the first in the AOT compiled namespaces. This also works with the current AOT compiled version of slf4j-timbre library. So maybe solving this issue has more to do with transitive loading of namespaces through Java classes during AOT compilation, instead of with AOT compiled libraries per se?
Alex Miller January 26, 2016 at 3:28 PM
I hear you. Unfortuantely, I'm not sure there's any way to detect this is what is happening in a generic way and produce a better error. The same kinds of weirdness can happen in Java as well when using a mixture of library versions.
Ryan Fowler January 26, 2016 at 3:11 PM
The problem for me is the error message. It's fine that I can't depend on AOT compiled libraries. It doesn't seem ok that the error message when I do this is "java.lang.NoSuchFieldError: _thunk0_" or "java.lang.RuntimeException: Method code too large!"
Nicola Mometto January 26, 2016 at 2:56 PM
I don't think there's anything that we can do other than pushing https://clojure.atlassian.net/browse/CLJ-322#icft=CLJ-322 and discouraging users to publish AOT compiled libs
Alex Miller January 26, 2016 at 2:54 PM
Publishing a jar with AOT'ed dependencies is for sure a problem. I realize this is a bit painful due to https://clojure.atlassian.net/browse/CLJ-322#icft=CLJ-322 (which I'm hoping to actually make some headway on this year).
Is there something else that should be done on this ticket?
In some very specific situation that I don't understand, the aot compiler can create class files with an inconsistent idea of a field called _thunk0_.
I've created a project at https://github.com/ryfow/weird-aot that reproduces the problem with `lein run`.
The ingredients for reproduction seem to be slf4j-timbre, tools.analyzer, and core.async.
I suspect that slf4j-timbre being aot compiled but not directly loaded by clojure code is a factor.
Note that the weird-aot timbre version differs from the version compiled in slf4j-timbre.
It's unclear to me why tools.analyzer and core.async are required to exhibit the problem.
Here's the stacktrace I get when I run `lein run` on the weird-aot project.
Exception.txt
Exception in thread "main" java.lang.NoSuchFieldError: __thunk__0__, compiling:(/private/var/folders/2q/tk7cywk93217_d4pxn_5kft40000gn/T/form-init7490372454812250103.clj:1:125) at clojure.lang.Compiler.load(Compiler.java:7239) at clojure.lang.Compiler.loadFile(Compiler.java:7165) at clojure.main$load_script.invoke(main.clj:275) at clojure.main$init_opt.invoke(main.clj:280) at clojure.main$initialize.invoke(main.clj:308) at clojure.main$null_opt.invoke(main.clj:343) at clojure.main$main.doInvoke(main.clj:421) at clojure.lang.RestFn.invoke(RestFn.java:421) at clojure.lang.Var.invoke(Var.java:383) at clojure.lang.AFn.applyToHelper(AFn.java:156) at clojure.lang.Var.applyTo(Var.java:700) at clojure.main.main(main.java:37) Caused by: java.lang.NoSuchFieldError: __thunk__0__ at clojure.tools.analyzer.jvm.utils__init.load(Unknown Source) at clojure.tools.analyzer.jvm.utils__init.<clinit>(Unknown Source) at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:340) at clojure.lang.RT.classForName(RT.java:2154) at clojure.lang.RT.classForName(RT.java:2163) at clojure.lang.RT.loadClassForName(RT.java:2182) at clojure.lang.RT.load(RT.java:436) at clojure.lang.RT.load(RT.java:412) at clojure.core$load$fn__5448.invoke(core.clj:5866) at clojure.core$load.doInvoke(core.clj:5865) at clojure.lang.RestFn.invoke(RestFn.java:408) at clojure.core$load_one.invoke(core.clj:5671) at clojure.core$load_lib$fn__5397.invoke(core.clj:5711) at clojure.core$load_lib.doInvoke(core.clj:5710) at clojure.lang.RestFn.applyTo(RestFn.java:142) at clojure.core$apply.invoke(core.clj:632) at clojure.core$load_libs.doInvoke(core.clj:5749) at clojure.lang.RestFn.applyTo(RestFn.java:137) at clojure.core$apply.invoke(core.clj:632) at clojure.core$require.doInvoke(core.clj:5832) at clojure.lang.RestFn.invoke(RestFn.java:703) at clojure.tools.analyzer.jvm$loading__5340__auto____1677.invoke(jvm.clj:9) at clojure.tools.analyzer.jvm__init.load(Unknown Source) at clojure.tools.analyzer.jvm__init.<clinit>(Unknown Source) at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:340) at clojure.lang.RT.classForName(RT.java:2154) at clojure.lang.RT.classForName(RT.java:2163) at clojure.lang.RT.loadClassForName(RT.java:2182) at clojure.lang.RT.load(RT.java:436) at clojure.lang.RT.load(RT.java:412) at clojure.core$load$fn__5448.invoke(core.clj:5866) at clojure.core$load.doInvoke(core.clj:5865) at clojure.lang.RestFn.invoke(RestFn.java:408) at clojure.core$load_one.invoke(core.clj:5671) at clojure.core$load_lib$fn__5397.invoke(core.clj:5711) at clojure.core$load_lib.doInvoke(core.clj:5710) at clojure.lang.RestFn.applyTo(RestFn.java:142) at clojure.core$apply.invoke(core.clj:632) at clojure.core$load_libs.doInvoke(core.clj:5749) at clojure.lang.RestFn.applyTo(RestFn.java:137) at clojure.core$apply.invoke(core.clj:632) at clojure.core$require.doInvoke(core.clj:5832) at clojure.lang.RestFn.invoke(RestFn.java:421) at weird_aot.core$loading__5340__auto____81.invoke(core.clj:1) at weird_aot.core__init.load(Unknown Source) at weird_aot.core__init.<clinit>(Unknown Source) at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:340) at clojure.lang.RT.classForName(RT.java:2154) at clojure.lang.RT.classForName(RT.java:2163) at clojure.lang.RT.loadClassForName(RT.java:2182) at clojure.lang.RT.load(RT.java:436) at clojure.lang.RT.load(RT.java:412) at clojure.core$load$fn__5448.invoke(core.clj:5866) at clojure.core$load.doInvoke(core.clj:5865) at clojure.lang.RestFn.invoke(RestFn.java:408) at clojure.core$load_one.invoke(core.clj:5671) at clojure.core$load_lib$fn__5397.invoke(core.clj:5711) at clojure.core$load_lib.doInvoke(core.clj:5710) at clojure.lang.RestFn.applyTo(RestFn.java:142) at clojure.core$apply.invoke(core.clj:632) at clojure.core$load_libs.doInvoke(core.clj:5749) at clojure.lang.RestFn.applyTo(RestFn.java:137) at clojure.core$apply.invoke(core.clj:632) at clojure.core$require.doInvoke(core.clj:5832) at clojure.lang.RestFn.invoke(RestFn.java:408) at user$eval65$fn__67.invoke(form-init7490372454812250103.clj:1) at user$eval65.invoke(form-init7490372454812250103.clj:1) at clojure.lang.Compiler.eval(Compiler.java:6782) at clojure.lang.Compiler.eval(Compiler.java:6772) at clojure.lang.Compiler.load(Compiler.java:7227) ... 11 more