修补 java.base 会导致 java.lang.LinkageError

Haa*_*ang 4 java classpath java-platform-module-system java-module java-11

-Xbootclasspath/p:path我正在尝试在 Java 11 中做同样的事情,这些事情可以在 java 9 之前的版本中完成。

作为一个简单的示例,我修改了其中一种valueOf方法java.lang.Integer并使用以下方法编译了该项目:

javac --module-source-path=src/java.base --patch-module java.base=src/java.base -d mods $(find src -name '*.java')

然后我使用以下命令运行了一个简单的示例:

java --patch-module java.base=<pathToMyModifiedJavaBaseClasses> -p lib -m my.moduleA/my.moduleA.Main

这很有效,我看到显示的修改(我从 中所做的简单打印valueOf)。

然而,当我尝试做同样的事情时,java.lang.ClassLoader执行程序时出现以下错误(编译有效):

Error occurred during initialization of boot layer java.lang.LinkageError: loader 'bootstrap' attempted duplicate class definition for java.lang.invoke.SimpleMethodHandle.

我什至不需要进行更改java.lang.ClassLoader。我的补丁文件夹中该类的绝对存在似乎引发了此错误。(我只想在类的底部添加一个字段)

ClassLoader注意:我只是认为当使用 Eclipse 编译该类时它可以工作。我知道的少数差异之一是 Eclipse 编译器似乎尚未遵循JEP 280invokedynamic但是字节码中也有指令javac,所以我怀疑这就是问题所在。

Hol*_*ger 5

您确实已经指出了正确的方向。当您使用当前版本的 Eclipse 编译该类时,它会起作用,因为该编译器尚未遵循JEP 280,因此它不\xe2\x80\x99t 用于invokedynamic字符串连接。

\n\n

这并不意味着使用invokedynamicinClassLoader一般来说是有问题的。仅在包引导期间执行的某些关键代码路径中存在问题,java.lang.invoke并且显然,此类在此代码路径上确实使用了字符串连接。

\n\n

在这种情况下,您可以通过选项\njavac强制使用旧的字符串连接代码。查看JDK 附带的字节码,该类似乎已使用此选项进行编译。事实上,查看一些示例,似乎整个模块都是使用该选项编译的,与eg 相比,eg 的类用于字符串连接。
-XDstringConcat=inlineClassLoader.classjava.basejava.desktopinvokedynamic

\n\n

所以结论是,要修补java.base模块中的类(在 OpenJDK 及其衍生产品中),请 -XDstringConcat=inline在使用javac.

\n

  • 事实上,这个标志似乎是专门为 java.base 模块(以及其他几个模块)添加的:http://hg.openjdk.java.net/jdk/jdk/file/fedc89081b57/make/CompileJavaModules。 GMK#l41 (3认同)