1

我正在尝试在混合 Clojure/Java Leiningen 项目中使用HotswapAgent/DCEVM,以避免在重新编译 Java 源代码后必须重新启动 REPL(我已经知道其他方法,例如 JRebel 和 Virgil)。

简而言之,问题是LinkageError在重新加载我重新编译的 Java 类后得到了一个,并且似乎该类没有被重新加载。

为了提供更多详细信息,我~/.lein/profiles.clj在配置文件中进行了设置,以便我们使用此处:repl找到的当前版本的 DCEVM JVM来运行 REPL。这是的相关部分:profiles.clj

{:repl
 {:plugins [[cider/cider-nrepl "0.22.4"]]
  :dependencies [[org.clojure/tools.nrepl "0.2.13"]]

  :java-cmd "/home/jonas/local/dcevm-11.0.6+1/bin/java"

  ... ;; Rest of profiles.clj

为了重现该问题,我使用以下代码设置了一个最小的 Leiningen Clojure 和 Java 混合项目,其中包含一个小型 Java 类AD

public class AD {
    public double _value;
    public double _deriv;

    public static int EXPONENT = 4;

    public AD(double value, double deriv) {
        _value = value;
        _deriv = deriv;
    }

    public AD mul(AD x) {
        return new AD(_value*x._value, _value*x._deriv + _deriv*x._value);
    }

    public AD raiseToPower() {
        AD result = new AD(1.0, 0.0);
        for (int i = 0; i < EXPONENT; i++) {
            result = result.mul(this);
        }
        return result;
    }

    public String toString() {
        return "AD(value=" + _value + ", deriv=" + _deriv + ")";
    }
}

以及一小段导入此类的 Clojure 代码:

(ns dcevm-complex-demo.ad
  (:import AD))

(defn variable [x]
  (AD. (double x) 1.0))

(defn raise-to-power
  "Evaluates f(x) = x^n and f'(x), n being the AD/EXPONENT static variable"
  [^AD ad-x]
  (.raiseToPower ad-x))

然后我在 Emacs/CIDER 中启动 Clojure REPL,加载dcevm-complex-demo.ad命名空间并评估(raise-to-power (variable 3.0))产生结果的表达式AD(value=81.0, deriv=108.0)。然后我修改Java源代码,例如,我将行更改public static int EXPONENT = 4;为并在终端中public static int EXPONENT = 3;重新编译使用。lein javacREPL 中的一条消息告诉我该类AD已重新加载。但是当我重新评估表达式时,(raise-to-power (variable 3.0))我会期望得到结果AD(value=27.0, deriv=27.0),但我得到了这个错误:

dcevm-complex-demo.ad/raise-to-power (ad.clj:10) 处的执行错误 (LinkageError)。加载器约束违规:解析方法“AD AD.raiseToPower()”时,当前类 dcevm_complex_demo/ad$raise_to_power 的类加载器 clojure.lang.DynamicClassLoader @7c53a0c2 和方法定义类 AD 的类加载器“app” , 对于签名中使用的 AD 类型具有不同的 Class 对象(dcevm_complex_demo.ad$raise_to_power 在加载器 clojure.lang.DynamicClassLoader @7c53a0c2 的未命名模块中,父加载器 clojure.lang.DynamicClassLoader @1217a2dd;AD 在加载器的未命名模块中'应用程序')

这是完整的 REPL 交互的样子:

REPL 交互

我怎样才能使类的重新加载AD工作?我怀疑我可能必须更改函数clojure.lang.RT.baseLoader()clojure/lang/RT.java),但我不太确定如何去做。

4

1 回答 1

0

dcevm8 和 dcvm11 中的 lambda 重新定义都存在问题。此问题已在 dcevm v11.0.7+1 中得到解决。根据您的日志,它可能会有所帮助。 https://github.com/TravaOpenJDK/trava-jdk-11-dcevm/releases/tag/dcevm-11.0.7+1

于 2020-06-03T11:57:14.563 回答