diff --git a/doc/bug-8240567.md b/doc/bug-8240567.md new file mode 100644 index 0000000000000..7059b52fd17d7 --- /dev/null +++ b/doc/bug-8240567.md @@ -0,0 +1,161 @@ +# Bug fix for bug-8240567.md + +This describes the fix for [JDK-8240567](https://bugs.openjdk.org/browse/JDK-8240567). + +When jlink is run, the method `SystemModulesPlugin.SystemModulesClassGenerator.genModuleDescriptorsMethod` is executed. +This method generates a method calling the construction of a `ModuleDescriptor` for each module used. In case +many modules are used, this method gets larger than 64kb, which is out of the limits of JDK. + +The idea of the fix is to move the calls down one call level to helper methods and let +`genModuleDescriptorsMethod` call these helper methods. The challenge is that no Java code is generated, +but directly Java byte code. + +## Preconditions + +To work on this fix, following pre-conditions need to be fulfilled: + +- Get [jtreg](https://openjdk.org/projects/code-tools/jtreg/intro.html) build locally on your machine. +- Configure the JDK build with jtreg (`./configure --with-boot-jdk=... --with-jtreg=/.../jtreg/build/images/jtreg`) + +## Determining correct Java byte code + +To determine the correct Java byte code, following minimal Java code is used: + +```java +import java.lang.module.ModuleDescriptor; + +class MethodCalls { + + public void method0(ModuleDescriptor[] moduleDescriptors) { + moduleDescriptors[0] = null; + return; + } + + public void method1(ModuleDescriptor[] moduleDescriptors) { + moduleDescriptors[1] = null; + return; + } + + public ModuleDescriptor[] moduleDescriptors() { + ModuleDescriptor[] result = new ModuleDescriptor[10]; + method0(result); + method1(result); + return result; + } + + public static void main (String args[]) { + MethodCalls methodCalls = new MethodCalls(); + ModuleDescriptor[] result = methodCalls.moduleDescriptors(); + System.out.println(result[0]); + } +} +``` + +This content is stored in `MethodCalls.java`. After compiling with `javac`, one can generate the byte code +output using `javap`. + +```terminal +javap -c MethodCalls +``` + +The output is as follows: + +```text +Compiled from "MethodCalls.java" +class MethodCalls { + MethodCalls(); + Code: + 0: aload_0 + 1: invokespecial #1 // Method java/lang/Object."":()V + 4: return + + public void method0(java.lang.module.ModuleDescriptor[]); + Code: + 0: aload_1 + 1: iconst_0 + 2: aconst_null + 3: aastore + 4: return + + public void method1(java.lang.module.ModuleDescriptor[]); + Code: + 0: aload_1 + 1: iconst_1 + 2: aconst_null + 3: aastore + 4: return + + public java.lang.module.ModuleDescriptor[] moduleDescriptors(); + Code: + 0: bipush 10 + 2: anewarray #7 // class java/lang/module/ModuleDescriptor + 5: astore_1 + 6: aload_0 + 7: aload_1 + 8: invokevirtual #9 // Method method0:([Ljava/lang/module/ModuleDescriptor;)V + 11: aload_0 + 12: aload_1 + 13: invokevirtual #15 // Method method1:([Ljava/lang/module/ModuleDescriptor;)V + 16: aload_1 + 17: areturn + + public static void main(java.lang.String[]); + Code: + 0: new #10 // class MethodCalls + 3: dup + 4: invokespecial #18 // Method "":()V + 7: astore_1 + 8: aload_1 + 9: invokevirtual #19 // Method moduleDescriptors:()[Ljava/lang/module/ModuleDescriptor; + 12: astore_2 + 13: getstatic #23 // Field java/lang/System.out:Ljava/io/PrintStream; + 16: aload_2 + 17: iconst_0 + 18: aaload + 19: invokevirtual #29 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V + 22: return +} +``` + +Thus, the sequence to call a method is + +``` +aload_0 +aload_1 +invokevirtual #9 +``` + +`#9` needs to be replaced by the reference of the method to be called. + +## Test case + +The class `JLink100Modules` contains the test case for the issue. With following command one can compile and run that +test class: + +```terminal +make test TEST="test/jdk/tools/jlink/JLink100Modules.java" +``` + +The test currently fails. + +The generated java modules can be investigated in following directory: + +``` +build\windows-x86_64-server-release\test-support\jtreg_test_jdk_tools_jlink_JLink100Modules_java\tools\jlink\JLink100Modules\bug8240567 +``` + +## Manually executing jlink + +One can manually execute jlink + +``` +build\windows-x86_64-server-release\images\jdk\bin\jlink.exe --output C:\TEMP\out-jlink --module-path build\windows-x86_64-server-release\test-support\jtreg_test_jdk_tools_jlink_JLink100Modules_java\tools\jlink\JLink100Modules\bug8240567\out --add-modules bug8240567x +``` + +In case the output is as follows, the patch did not work out properly: + +``` +Fehler: jdk.internal.org.objectweb.asm.MethodTooLargeException: Method too large: jdk/internal/module/SystemModules$all.moduleDescriptorsSub1 ([Ljava/lang/module/ModuleDescriptor;)V +``` + +With that command, one can do a cycle through code adaption and checking with jlink.