8354083: Support --add-reads with -XX:+AOTClassLinking

Reviewed-by: iklam, alanb
This commit is contained in:
Calvin Cheung 2025-05-15 21:14:42 +00:00
parent fe790cb319
commit efdbb6afce
9 changed files with 446 additions and 280 deletions

View File

@ -584,6 +584,7 @@ Modules::ArchivedProperty Modules::_archived_props[] = {
{"jdk.module.addmods", true}, // --add-modules
{"jdk.module.enable.native.access", true}, // --enable-native-access
{"jdk.module.addopens", true}, // --add-opens
{"jdk.module.addreads", true}, // --add-reads
};
constexpr size_t Modules::num_archived_props() {

View File

@ -331,8 +331,7 @@ bool Arguments::is_incompatible_cds_internal_module_property(const char* propert
bool Arguments::internal_module_property_helper(const char* property, bool check_for_cds) {
if (strncmp(property, MODULE_PROPERTY_PREFIX, MODULE_PROPERTY_PREFIX_LEN) == 0) {
const char* property_suffix = property + MODULE_PROPERTY_PREFIX_LEN;
if (matches_property_suffix(property_suffix, ADDREADS, ADDREADS_LEN) ||
matches_property_suffix(property_suffix, PATCH, PATCH_LEN) ||
if (matches_property_suffix(property_suffix, PATCH, PATCH_LEN) ||
matches_property_suffix(property_suffix, LIMITMODS, LIMITMODS_LEN) ||
matches_property_suffix(property_suffix, UPGRADE_PATH, UPGRADE_PATH_LEN) ||
matches_property_suffix(property_suffix, ILLEGAL_NATIVE_ACCESS, ILLEGAL_NATIVE_ACCESS_LEN)) {
@ -343,6 +342,7 @@ bool Arguments::internal_module_property_helper(const char* property, bool check
// CDS notes: these properties are supported by CDS archived full module graph.
if (matches_property_suffix(property_suffix, ADDEXPORTS, ADDEXPORTS_LEN) ||
matches_property_suffix(property_suffix, ADDOPENS, ADDOPENS_LEN) ||
matches_property_suffix(property_suffix, ADDREADS, ADDREADS_LEN) ||
matches_property_suffix(property_suffix, PATH, PATH_LEN) ||
matches_property_suffix(property_suffix, ADDMODS, ADDMODS_LEN) ||
matches_property_suffix(property_suffix, ENABLE_NATIVE_ACCESS, ENABLE_NATIVE_ACCESS_LEN)) {

View File

@ -141,8 +141,7 @@ public final class ModuleBootstrap {
private static boolean canUseArchivedBootLayer() {
return getProperty("jdk.module.upgrade.path") == null &&
getProperty("jdk.module.patch.0") == null && // --patch-module
getProperty("jdk.module.limitmods") == null && // --limit-modules
getProperty("jdk.module.addreads.0") == null; // --add-reads
getProperty("jdk.module.limitmods") == null; // --limit-modules
}
/**

View File

@ -422,7 +422,6 @@ hotspot_appcds_dynamic = \
-runtime/cds/appcds/customLoader \
-runtime/cds/appcds/dynamicArchive \
-runtime/cds/appcds/jigsaw/ExactOptionMatch.java \
-runtime/cds/appcds/jigsaw/modulepath/AddExports.java \
-runtime/cds/appcds/jigsaw/modulepath/ModulePathAndFMG.java \
-runtime/cds/appcds/jigsaw/modulepath/OptimizeModuleHandlingTest.java \
-runtime/cds/appcds/loaderConstraints/DynamicLoaderConstraintsTest.java \
@ -543,8 +542,6 @@ hotspot_aot_classlinking = \
-runtime/cds/appcds/jigsaw/classpathtests/EmptyClassInBootClassPath.java \
-runtime/cds/appcds/jigsaw/ExactOptionMatch.java \
-runtime/cds/appcds/jigsaw/JigsawOptionsCombo.java \
-runtime/cds/appcds/jigsaw/modulepath/AddExports.java \
-runtime/cds/appcds/jigsaw/modulepath/AddOpens.java \
-runtime/cds/appcds/jigsaw/modulepath/AddModules.java \
-runtime/cds/appcds/jigsaw/modulepath/JvmtiAddPath.java \
-runtime/cds/appcds/jigsaw/modulepath/MainModuleOnly.java \

View File

@ -45,7 +45,9 @@ import jdk.test.lib.cds.SimpleCDSAppTester;
import jdk.test.lib.process.OutputAnalyzer;
public class AddExports {
static final Path SRC = Paths.get(System.getProperty("test.src")).resolve("src");
static final String SEP = File.separator;
static final Path SRC = Paths.get(System.getProperty("test.src")).
resolve( ".." + SEP + "jigsaw" + SEP + "modulepath" + SEP + "src");
static final Path nonModuleNeedsJdkAddExportDir = SRC.resolve("com.nomodule.needsjdkaddexport");
static final String nonModuleNeedsJdkAddExportJar = "nonModuleNeedsJdkAddExport.jar";

View File

@ -0,0 +1,234 @@
/*
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
/**
* @test
* @requires vm.cds
* @requires vm.cds.supports.aot.class.linking
* @comment work around JDK-8345635
* @requires !vm.jvmci.enabled
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds
* @run driver AddOpens
* @summary sanity test the --add-opens option
*/
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import jdk.test.lib.cds.CDSTestUtils;
import jdk.test.lib.cds.CDSAppTester;
import jdk.test.lib.cds.SimpleCDSAppTester;
import jdk.test.lib.process.OutputAnalyzer;
public class AddOpens {
private static final String SEP = File.separator;
private static final Path USER_DIR = Paths.get(CDSTestUtils.getOutputDir());
private static final Path SRC_DIR = Paths.get(System.getProperty("test.src")).
resolve( ".." + SEP + "jigsaw" + SEP + "modulepath" + SEP + "src");
private static final Path MODS_DIR = Paths.get("mods");
// the module name of the test module
private static final String TEST_MODULE1 = "com.simple";
// the module main class
private static final String MAIN_CLASS = "com.simple.Main";
private static Path moduleDir = null;
private static Path moduleDir2 = null;
private static Path destJar = null;
private static String addOpensArg = "java.base/java.lang=" + TEST_MODULE1;
private static String addOpensAllUnnamed = "java.base/java.lang=ALL-UNNAMED";
private static String extraOpts[][] =
{{"-Xlog:cds", "-Xlog:cds"},
{"--add-opens", addOpensArg}};
private static String expectedOutput[] =
{ "[class,load] com.simple.Main source: shared objects file",
"method.setAccessible succeeded!"};
public static void buildTestModule() throws Exception {
// javac -d mods/$TESTMODULE --module-path MOD_DIR src/$TESTMODULE/**
JarBuilder.compileModule(SRC_DIR.resolve(TEST_MODULE1),
MODS_DIR.resolve(TEST_MODULE1),
MODS_DIR.toString());
moduleDir = Files.createTempDirectory(USER_DIR, "mlib");
moduleDir2 = Files.createTempDirectory(USER_DIR, "mlib2");
Path srcJar = moduleDir.resolve(TEST_MODULE1 + ".jar");
destJar = moduleDir2.resolve(TEST_MODULE1 + ".jar");
String classes = MODS_DIR.resolve(TEST_MODULE1).toString();
JarBuilder.createModularJar(srcJar.toString(), classes, MAIN_CLASS);
Files.copy(srcJar, destJar);
}
static int testCount = 0;
static void printComment(String comment) {
testCount ++;
System.out.println("======================================================================");
System.out.println("TESTCASE " + testCount + ": " + comment);
System.out.println("======================================================================");
}
static SimpleCDSAppTester test(String comment, SimpleCDSAppTester tester) throws Exception {
printComment(comment);
return tester
.setAssemblyChecker((OutputAnalyzer out) -> {
out.shouldContain("Full module graph = enabled");
})
.setProductionChecker((OutputAnalyzer out) -> {
out.shouldContain(expectedOutput[0]);
out.shouldContain(expectedOutput[1]);
})
.runStaticWorkflow()
.runAOTWorkflow();
}
static class Tester1 extends CDSAppTester {
public Tester1(String testName) {
super(testName);
}
@Override
public String[] vmArgs(RunMode runMode) {
if (runMode == RunMode.DUMP_STATIC) {
return new String[] { "-Xlog:cds" };
} else {
return new String[] {
"--add-opens", addOpensArg, "-Xlog:class+load=trace",
};
}
}
@Override
public String classpath(RunMode runMode) {
return destJar.toString();
}
@Override
public String modulepath(RunMode runMode) {
return moduleDir.toString();
}
@Override
public String[] appCommandLine(RunMode runMode) {
if (runMode == RunMode.TRAINING ||
runMode == RunMode.ASSEMBLY ||
runMode == RunMode.DUMP_STATIC) {
return new String[] {
"-m", TEST_MODULE1,
};
} else {
return new String[] {
"-m", TEST_MODULE1, "with_add_opens",
};
}
}
@Override
public void checkExecution(OutputAnalyzer out, RunMode runMode) throws Exception {
if (runMode == RunMode.PRODUCTION) {
out.shouldContain(expectedOutput[0]);
out.shouldContain(expectedOutput[1]);
} else if (runMode == RunMode.ASSEMBLY) {
out.shouldContain("full module graph: enabled");
}
}
}
static class Tester2 extends CDSAppTester {
public Tester2(String testName) {
super(testName);
}
@Override
public String[] vmArgs(RunMode runMode) {
return new String[] {
"--add-opens", addOpensAllUnnamed, "-Xlog:class+load=trace",
};
}
@Override
public String classpath(RunMode runMode) {
return destJar.toString();
}
@Override
public String[] appCommandLine(RunMode runMode) {
if (runMode == RunMode.TRAINING ||
runMode == RunMode.ASSEMBLY ||
runMode == RunMode.DUMP_STATIC) {
return new String[] {
MAIN_CLASS,
};
} else {
return new String[] {
MAIN_CLASS, "with_add_opens",
};
}
}
@Override
public void checkExecution(OutputAnalyzer out, RunMode runMode) throws Exception {
if (runMode == RunMode.PRODUCTION) {
out.shouldContain(expectedOutput[0]);
out.shouldContain(expectedOutput[1]);
} else if (runMode == RunMode.ASSEMBLY) {
out.shouldContain("full module graph: enabled");
}
}
}
public static void main(String... args) throws Exception {
// compile the modules and create the modular jar files
buildTestModule();
String appClasses[] = {MAIN_CLASS};
OutputAnalyzer output;
test("Same --add-opens during ASSEMBLY/DUMP_STATIC and PRODUCTION RunMode",
SimpleCDSAppTester.of("same-add-opens")
.classpath(destJar.toString())
.addVmArgs("--add-opens", addOpensArg, "-Xlog:class+load=trace")
.modulepath(moduleDir.toString())
.appCommandLine("-m", TEST_MODULE1, "with_add_opens"));
printComment("no --add-opens during DUMP_STATIC RunMode; --add-opens during PRODUCTION RunMode");
Tester1 t1 = new Tester1("no-add-opens-in-DUMP_STATIC");
t1.run("AOT");
t1.run("STATIC");
printComment("--add-opens ALL-UNNAMED during ASSEMBLY/DUMP_STATIC and PRODUCTION RunMode");
Tester2 t2 = new Tester2("add-opens-ALL-UNNAMED");
t2.run("AOT");
t2.run("STATIC");
}
}

View File

@ -0,0 +1,205 @@
/*
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
/**
* @test
* @bug 8354083
* @requires vm.cds
* @requires vm.cds.supports.aot.class.linking
* @comment work around JDK-8345635
* @requires !vm.jvmci.enabled
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds
* @run driver AddReads
* @summary sanity test the --add-reads option
*/
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import jdk.test.lib.cds.CDSTestUtils;
import jdk.test.lib.cds.CDSAppTester;
import jdk.test.lib.cds.SimpleCDSAppTester;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.Asserts;
public class AddReads {
private static final String SEP = File.separator;
private static final Path USER_DIR = Paths.get(CDSTestUtils.getOutputDir());
private static final Path SRC_DIR = Paths.get(System.getProperty("test.src")).
resolve( ".." + SEP + "jigsaw" + SEP + "modulepath" + SEP + "src");
private static final Path MODS_DIR = Paths.get("mods");
// the module name of the test module
private static final String MAIN_MODULE = "com.norequires";
private static final String SUB_MODULE = "org.astro";
// the module main class
private static final String MAIN_CLASS = "com.norequires.Main";
private static final String APP_CLASS = "org.astro.World";
private static final String sharedClassA =
"[class,load] com.norequires.Main source: shared objects file";
private static final String sharedClassB =
"[class,load] org.astro.World source: shared objects file";
private static final String fmgEnabled = "full module graph: enabled";
private static final String fmgDisabled = "full module graph: disabled";
private static final String cannotAccess =
"class com.norequires.Main (in module com.norequires) cannot access class org.astro.World (in module org.astro)";
private static Path moduleDir = null;
private static Path subJar = null;
private static Path mainJar = null;
public static void buildTestModule() throws Exception {
// javac -d mods/$TESTMODULE src/$TESTMODULE/**
JarBuilder.compileModule(SRC_DIR.resolve(SUB_MODULE),
MODS_DIR.resolve(SUB_MODULE),
null);
Asserts.assertTrue(CompilerUtils
.compile(SRC_DIR.resolve(MAIN_MODULE),
MODS_DIR.resolve(MAIN_MODULE),
"-cp", MODS_DIR.resolve(SUB_MODULE).toString(),
"--add-reads", "com.norequires=ALL-UNNAMED"));
moduleDir = Files.createTempDirectory(USER_DIR, "mlib");
subJar = moduleDir.resolve(SUB_MODULE + ".jar");
String classes = MODS_DIR.resolve(SUB_MODULE).toString();
JarBuilder.createModularJar(subJar.toString(), classes, null);
mainJar = moduleDir.resolve(MAIN_MODULE + ".jar");
classes = MODS_DIR.resolve(MAIN_MODULE).toString();
JarBuilder.createModularJar(mainJar.toString(), classes, MAIN_CLASS);
}
static int testCount = 0;
static void printComment(String comment) {
testCount ++;
System.out.println("======================================================================");
System.out.println("TESTCASE " + testCount + ": " + comment);
System.out.println("======================================================================");
}
static SimpleCDSAppTester test(String comment, SimpleCDSAppTester tester) throws Exception {
printComment(comment);
return tester
.setAssemblyChecker((OutputAnalyzer out) -> {
out.shouldContain("Full module graph = enabled");
})
.setProductionChecker((OutputAnalyzer out) -> {
out.shouldContain("use_full_module_graph = true; java.base");
})
.runStaticWorkflow()
.runAOTWorkflow();
}
static class Tester extends CDSAppTester {
public Tester(String testName) {
super(testName);
}
@Override
public String[] vmArgs(RunMode runMode) {
if (runMode == RunMode.TRAINING ||
runMode == RunMode.ASSEMBLY ||
runMode == RunMode.DUMP_STATIC) {
return new String[] {
"--add-modules", SUB_MODULE,
"--add-reads", "com.norequires=" + SUB_MODULE,
"-Xlog:class+load,cds,class+path=info",
};
} else {
return new String[] {
"--add-modules", SUB_MODULE,
"--add-reads", "com.norequires=ALL-UNNAMED",
"-Xlog:class+load,cds,class+path=info",
};
}
}
@Override
public String classpath(RunMode runMode) {
return subJar.toString();
}
@Override
public String[] appCommandLine(RunMode runMode) {
return new String[] {
"-m", MAIN_MODULE,
};
}
@Override
public String modulepath(RunMode runMode) {
return moduleDir.toString();
}
@Override
public void checkExecution(OutputAnalyzer out, RunMode runMode) throws Exception {
if (runMode == RunMode.PRODUCTION) {
out.shouldContain("full module graph: disabled");
out.shouldContain("Mismatched values for property jdk.module.addreads: runtime com.norequires=ALL-UNNAMED dump time com.norequires=org.astro");
} else if (runMode == RunMode.ASSEMBLY) {
out.shouldContain("full module graph: enabled");
} else {
out.shouldHaveExitValue(0);
}
}
}
public static void main(String... args) throws Exception {
// compile the modules and create the modular jar files
buildTestModule();
test("FMG should be enabled with '--add-reads com.norequires=org.astro'",
SimpleCDSAppTester.of("add-reads")
.modulepath(moduleDir.toString())
.addVmArgs("--add-modules", SUB_MODULE,
"--add-reads", "com.norequires=" + SUB_MODULE,
"-Xlog:class+load,cds,class+path=info")
.appCommandLine("-m", MAIN_MODULE));
test("FMG should be enabled with '--add-reads com.norequires=org.astro'",
SimpleCDSAppTester.of("add-reads-with-classpath")
.classpath(subJar.toString())
.modulepath(moduleDir.toString())
.addVmArgs("--add-modules", SUB_MODULE,
"--add-reads", "com.norequires=" + SUB_MODULE,
"-Xlog:class+load,cds,class+path=info")
.appCommandLine("-m", MAIN_MODULE));
printComment("FMG should be enabled with '--add-reads com.norequires=ALL-UNNAMED");
Tester t = new Tester("add-reads-ALL-UNNAMED");
t.setCheckExitValue(false);
t.run("AOT");
t.run("STATIC");
}
}

View File

@ -1,132 +0,0 @@
/*
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
/**
* @test
* @requires vm.cds
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds
* @run driver AddOpens
* @summary sanity test the --add-opens option
*/
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import jdk.test.lib.cds.CDSTestUtils;
import jdk.test.lib.process.OutputAnalyzer;
public class AddOpens {
private static final Path USER_DIR = Paths.get(CDSTestUtils.getOutputDir());
private static final String TEST_SRC = System.getProperty("test.src");
private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
private static final Path MODS_DIR = Paths.get("mods");
// the module name of the test module
private static final String TEST_MODULE1 = "com.simple";
// the module main class
private static final String MAIN_CLASS = "com.simple.Main";
private static Path moduleDir = null;
private static Path moduleDir2 = null;
private static Path destJar = null;
private static String addOpensArg = "java.base/java.lang=" + TEST_MODULE1;
private static String addOpensAllUnnamed = "java.base/java.lang=ALL-UNNAMED";
private static String extraOpts[][] =
{{"-Xlog:cds", "-Xlog:cds"},
{"--add-opens", addOpensArg}};
private static String expectedOutput[] =
{ "[class,load] com.simple.Main source: shared objects file",
"method.setAccessible succeeded!"};
public static void buildTestModule() throws Exception {
// javac -d mods/$TESTMODULE --module-path MOD_DIR src/$TESTMODULE/**
JarBuilder.compileModule(SRC_DIR.resolve(TEST_MODULE1),
MODS_DIR.resolve(TEST_MODULE1),
MODS_DIR.toString());
moduleDir = Files.createTempDirectory(USER_DIR, "mlib");
moduleDir2 = Files.createTempDirectory(USER_DIR, "mlib2");
Path srcJar = moduleDir.resolve(TEST_MODULE1 + ".jar");
destJar = moduleDir2.resolve(TEST_MODULE1 + ".jar");
String classes = MODS_DIR.resolve(TEST_MODULE1).toString();
JarBuilder.createModularJar(srcJar.toString(), classes, MAIN_CLASS);
Files.copy(srcJar, destJar);
}
public static void main(String... args) throws Exception {
// compile the modules and create the modular jar files
buildTestModule();
String appClasses[] = {MAIN_CLASS};
OutputAnalyzer output;
for (int i = 0; i < 2; i++) {
// create an archive with both -cp and --module-path, and with the
// --add-opens option if i == 1, in the command line.
// Only the class in the modular jar in the --module-path will be archived;
// the class in the modular jar in the -cp won't be archived.
output = TestCommon.createArchive(
destJar.toString(), appClasses,
extraOpts[i][0], extraOpts[i][1],
"--module-path", moduleDir.toString(),
"-m", TEST_MODULE1);
TestCommon.checkDump(output);
// run with the archive using the same command line as in dump time
// plus the "--add-opens java.base/java.lang=com.simple" option.
// The main class should be loaded from the archive.
// The setaccessible(true) on the ClassLoader.defineClass method should
// be successful.
TestCommon.run( "-Xlog:class+load=trace",
"-cp", destJar.toString(),
"--add-opens", addOpensArg,
"--module-path", moduleDir.toString(),
"-m", TEST_MODULE1, "with_add_opens")
.assertNormalExit(expectedOutput[0], expectedOutput[1]);
}
// Test --add-opens to ALL-UNNAMED modules
output = TestCommon.createArchive(
destJar.toString(), appClasses,
"--add-opens", addOpensAllUnnamed,
MAIN_CLASS);
TestCommon.checkDump(output);
TestCommon.run( "-Xlog:class+load=trace",
"-cp", destJar.toString(),
"--add-opens", addOpensAllUnnamed,
MAIN_CLASS, "with_add_opens")
.assertNormalExit(expectedOutput[0], expectedOutput[1]);
}
}

View File

@ -1,140 +0,0 @@
/*
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
/**
* @test
* @requires vm.cds
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds
* @run driver AddReads
* @summary sanity test the --add-reads option
*/
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import jdk.test.lib.cds.CDSTestUtils;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.Asserts;
public class AddReads {
private static final Path USER_DIR = Paths.get(CDSTestUtils.getOutputDir());
private static final String TEST_SRC = System.getProperty("test.src");
private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
private static final Path MODS_DIR = Paths.get("mods");
// the module name of the test module
private static final String MAIN_MODULE = "com.norequires";
private static final String SUB_MODULE = "org.astro";
// the module main class
private static final String MAIN_CLASS = "com.norequires.Main";
private static final String APP_CLASS = "org.astro.World";
private static Path moduleDir = null;
private static Path subJar = null;
private static Path mainJar = null;
public static void buildTestModule() throws Exception {
// javac -d mods/$TESTMODULE src/$TESTMODULE/**
JarBuilder.compileModule(SRC_DIR.resolve(SUB_MODULE),
MODS_DIR.resolve(SUB_MODULE),
null);
Asserts.assertTrue(CompilerUtils
.compile(SRC_DIR.resolve(MAIN_MODULE),
MODS_DIR.resolve(MAIN_MODULE),
"-cp", MODS_DIR.resolve(SUB_MODULE).toString(),
"--add-reads", "com.norequires=ALL-UNNAMED"));
moduleDir = Files.createTempDirectory(USER_DIR, "mlib");
subJar = moduleDir.resolve(SUB_MODULE + ".jar");
String classes = MODS_DIR.resolve(SUB_MODULE).toString();
JarBuilder.createModularJar(subJar.toString(), classes, null);
mainJar = moduleDir.resolve(MAIN_MODULE + ".jar");
classes = MODS_DIR.resolve(MAIN_MODULE).toString();
JarBuilder.createModularJar(mainJar.toString(), classes, MAIN_CLASS);
}
public static void main(String... args) throws Exception {
// compile the modules and create the modular jar files
buildTestModule();
String appClasses[] = {MAIN_CLASS, APP_CLASS};
// create an archive with the classes in the modules built in the
// previous step
OutputAnalyzer output = TestCommon.createArchive(
null, appClasses,
"--module-path", moduleDir.toString(),
"--add-modules", SUB_MODULE,
"--add-reads", "com.norequires=org.astro",
"-m", MAIN_MODULE);
TestCommon.checkDump(output);
String prefix[] = {"-Djava.class.path=", "-Xlog:class+load=trace",
"--add-modules", SUB_MODULE,
"--add-reads", "com.norequires=org.astro"};
// run the com.norequires module with the archive with the same args
// used during dump time.
// The classes should be loaded from the archive.
TestCommon.runWithModules(prefix,
null, // --upgrade-module-path
moduleDir.toString(), // --module-path
MAIN_MODULE) // -m
.assertNormalExit(out -> {
out.shouldContain("[class,load] com.norequires.Main source: shared objects file")
.shouldContain("[class,load] org.astro.World source: shared objects file");
});
// create an archive with -cp pointing to the jar file containing the
// org.astro module and --module-path pointing to the main module
output = TestCommon.createArchive(
subJar.toString(), appClasses,
"--module-path", moduleDir.toString(),
"--add-modules", SUB_MODULE,
"--add-reads", "com.norequires=org.astro",
"-m", MAIN_MODULE);
TestCommon.checkDump(output);
// run the com.norequires module with the archive with the sub-module
// in the -cp and with -add-reads=com.norequires=ALL-UNNAMED
// The main class should be loaded from the archive.
// The org.astro.World should be loaded from the jar.
String prefix2[] = {"-cp", subJar.toString(), "-Xlog:class+load=trace",
"--add-reads", "com.norequires=ALL-UNNAMED"};
TestCommon.runWithModules(prefix2,
null, // --upgrade-module-path
moduleDir.toString(), // --module-path
MAIN_MODULE) // -m
.assertNormalExit(out -> {
out.shouldContain("[class,load] com.norequires.Main source: shared objects file")
.shouldMatch(".class.load. org.astro.World source:.*org.astro.jar");
});
}
}