changeset 16492:e53f8c34880e

8157068: ExceptionInInitializerError if images build patched to use exploded version of jdk.internal.module.SystemModules Reviewed-by: alanb
author mchung
date Thu, 19 May 2016 11:17:35 -0700
parents 123da3a60133
children 3976fadb091d 6efc826d3cd0
files src/java.base/share/classes/java/lang/module/SystemModuleFinder.java src/java.base/share/classes/jdk/internal/jimage/ImageReader.java src/java.base/share/classes/jdk/internal/module/SystemModules.java test/tools/launcher/modules/patch/PatchTest.java test/tools/launcher/modules/patch/basic/PatchTest.java test/tools/launcher/modules/patch/basic/src/test/jdk/test/Main.java test/tools/launcher/modules/patch/basic/src/test/module-info.java test/tools/launcher/modules/patch/basic/src1/java.base/java/text/Annotation.java test/tools/launcher/modules/patch/basic/src1/java.base/java/text/AnnotationBuddy.java test/tools/launcher/modules/patch/basic/src1/jdk.compiler/com/sun/tools/javac/Main.java test/tools/launcher/modules/patch/basic/src1/jdk.compiler/com/sun/tools/javac/MainBuddy.java test/tools/launcher/modules/patch/basic/src1/jdk.naming.dns/com/sun/jndi/dns/DnsClient.java test/tools/launcher/modules/patch/basic/src1/jdk.naming.dns/com/sun/jndi/dns/DnsClientBuddy.java test/tools/launcher/modules/patch/basic/src2/java.base/java/lang2/Object.java test/tools/launcher/modules/patch/basic/src2/jdk.compiler/com/sun/tools/javac2/Main.java test/tools/launcher/modules/patch/basic/src2/jdk.naming.dns/com/sun/jndi/dns2/Zone.java test/tools/launcher/modules/patch/src/test/jdk/test/Main.java test/tools/launcher/modules/patch/src/test/module-info.java test/tools/launcher/modules/patch/src1/java.base/java/text/Annotation.java test/tools/launcher/modules/patch/src1/java.base/java/text/AnnotationBuddy.java test/tools/launcher/modules/patch/src1/jdk.compiler/com/sun/tools/javac/Main.java test/tools/launcher/modules/patch/src1/jdk.compiler/com/sun/tools/javac/MainBuddy.java test/tools/launcher/modules/patch/src1/jdk.naming.dns/com/sun/jndi/dns/DnsClient.java test/tools/launcher/modules/patch/src1/jdk.naming.dns/com/sun/jndi/dns/DnsClientBuddy.java test/tools/launcher/modules/patch/src2/java.base/java/lang2/Object.java test/tools/launcher/modules/patch/src2/jdk.compiler/com/sun/tools/javac2/Main.java test/tools/launcher/modules/patch/src2/jdk.naming.dns/com/sun/jndi/dns2/Zone.java test/tools/launcher/modules/patch/systemmodules/PatchSystemModules.java test/tools/launcher/modules/patch/systemmodules/src/m1/module-info.java test/tools/launcher/modules/patch/systemmodules/src/m1/p1/Main.java test/tools/launcher/modules/patch/systemmodules/src/m2/module-info.java test/tools/launcher/modules/patch/systemmodules/src/m2/p2/Lib.java test/tools/launcher/modules/patch/systemmodules/src1/java.base/jdk/internal/modules/SystemModules.java test/tools/launcher/modules/patch/systemmodules/src1/m2/p2/Lib.java
diffstat 34 files changed, 1075 insertions(+), 596 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/java/lang/module/SystemModuleFinder.java	Thu May 19 09:16:59 2016 -0700
+++ b/src/java.base/share/classes/java/lang/module/SystemModuleFinder.java	Thu May 19 11:17:35 2016 -0700
@@ -45,6 +45,7 @@
 import jdk.internal.jimage.ImageReader;
 import jdk.internal.jimage.ImageReaderFactory;
 import jdk.internal.module.ModuleHashes;
+import jdk.internal.module.ModuleHashes.HashSupplier;
 import jdk.internal.module.SystemModules;
 import jdk.internal.module.ModulePatcher;
 import jdk.internal.perf.PerfCounter;
@@ -84,57 +85,23 @@
         long t0 = System.nanoTime();
         imageReader = ImageReaderFactory.getImageReader();
 
-        String[] moduleNames = SystemModules.MODULE_NAMES;
-        ModuleDescriptor[] descriptors = null;
+        String[] names = moduleNames();
+        ModuleDescriptor[] descriptors = descriptors(names);
 
-        boolean fastLoad = System.getProperty("jdk.installed.modules.disable") == null;
-        if (fastLoad) {
-            // fast loading of ModuleDescriptor of installed modules
-            descriptors = SystemModules.modules();
-        }
-
-        int n = moduleNames.length;
+        int n = names.length;
         moduleCount.add(n);
 
         Set<ModuleReference> mods = new HashSet<>(n);
         Map<String, ModuleReference> map = new HashMap<>(n);
 
         for (int i = 0; i < n; i++) {
-            String mn = moduleNames[i];
-            ModuleDescriptor md;
-            String hash;
-            if (fastLoad) {
-                md = descriptors[i];
-                hash = SystemModules.MODULES_TO_HASH[i];
-            } else {
-                // fallback to read module-info.class
-                // if fast loading of ModuleDescriptors is disabled
-                ImageLocation location = imageReader.findLocation(mn, "module-info.class");
-                md = ModuleDescriptor.read(imageReader.getResourceBuffer(location));
-                hash = null;
-            }
-            if (!md.name().equals(mn))
-                throw new InternalError();
+            ModuleDescriptor md = descriptors[i];
 
             // create the ModuleReference
-
-            URI uri = URI.create("jrt:/" + mn);
-
-            Supplier<ModuleReader> readerSupplier = new Supplier<>() {
-                @Override
-                public ModuleReader get() {
-                    return new ImageModuleReader(mn, uri);
-                }
-            };
-
-            ModuleReference mref =
-                new ModuleReference(md, uri, readerSupplier, hashSupplier(hash));
-
-            // may need a reference to a patched module if -Xpatch specified
-            mref = ModulePatcher.interposeIfNeeded(mref);
+            ModuleReference mref = toModuleReference(md, hashSupplier(i, names[i]));
 
             mods.add(mref);
-            map.put(mn, mref);
+            map.put(names[i], mref);
 
             // counters
             packageCount.add(md.packages().size());
@@ -147,16 +114,114 @@
         initTime.addElapsedTimeFrom(t0);
     }
 
-    private static ModuleHashes.HashSupplier hashSupplier(String hash) {
-        if (hash == null)
-            return null;
+    /*
+     * Returns an array of ModuleDescriptor of the given module names.
+     *
+     * This obtains ModuleDescriptors from SystemModules class that is generated
+     * from the jlink system-modules plugin.  ModuleDescriptors have already
+     * been validated at link time.
+     *
+     * If java.base is patched, or fastpath is disabled for troubleshooting
+     * purpose, it will fall back to find system modules via jrt file system.
+     */
+    private static ModuleDescriptor[] descriptors(String[] names) {
+        // fastpath is enabled by default.
+        // It can be disabled for troubleshooting purpose.
+        boolean disabled =
+            System.getProperty("jdk.system.module.finder.disabledFastPath") != null;
 
-        return new ModuleHashes.HashSupplier() {
+        // fast loading of ModuleDescriptor of system modules
+        if (isFastPathSupported() && !disabled)
+            return SystemModules.modules();
+
+        // if fast loading of ModuleDescriptors is disabled
+        // fallback to read module-info.class
+        ModuleDescriptor[] descriptors = new ModuleDescriptor[names.length];
+        for (int i = 0; i < names.length; i++) {
+            String mn = names[i];
+            ImageLocation loc = imageReader.findLocation(mn, "module-info.class");
+            descriptors[i] = ModuleDescriptor.read(imageReader.getResourceBuffer(loc));
+
+            // add the recorded hashes of tied modules
+            Hashes.add(descriptors[i]);
+        }
+        return descriptors;
+    }
+
+    private static boolean isFastPathSupported() {
+       return SystemModules.MODULE_NAMES.length > 0;
+    }
+
+    private static String[] moduleNames() {
+        if (isFastPathSupported())
+            // module names recorded at link time
+            return SystemModules.MODULE_NAMES;
+
+        // this happens when java.base is patched with java.base
+        // from an exploded image
+        return imageReader.getModuleNames();
+    }
+
+    private static ModuleReference toModuleReference(ModuleDescriptor md,
+                                                     HashSupplier hash)
+    {
+        String mn = md.name();
+        URI uri = URI.create("jrt:/" + mn);
+
+        Supplier<ModuleReader> readerSupplier = new Supplier<>() {
             @Override
-            public String generate(String algorithm) {
-                return hash;
+            public ModuleReader get() {
+                return new ImageModuleReader(mn, uri);
             }
         };
+
+        ModuleReference mref =
+            new ModuleReference(md, uri, readerSupplier, hash);
+
+        // may need a reference to a patched module if -Xpatch specified
+        mref = ModulePatcher.interposeIfNeeded(mref);
+
+        return mref;
+    }
+
+    private static HashSupplier hashSupplier(int index, String name) {
+        if (isFastPathSupported()) {
+            return new HashSupplier() {
+                @Override
+                public String generate(String algorithm) {
+                    return SystemModules.MODULES_TO_HASH[index];
+                }
+            };
+        } else {
+            return Hashes.hashFor(name);
+        }
+    }
+
+    /*
+     * This helper class is only used when SystemModules is patched.
+     * It will get the recorded hashes from module-info.class.
+     */
+    private static class Hashes {
+        static Map<String, String> hashes = new HashMap<>();
+
+        static void add(ModuleDescriptor descriptor) {
+            Optional<ModuleHashes> ohashes = descriptor.hashes();
+            if (ohashes.isPresent()) {
+                hashes.putAll(ohashes.get().hashes());
+            }
+        }
+
+        static HashSupplier hashFor(String name) {
+            if (!hashes.containsKey(name))
+                return null;
+
+            return new HashSupplier() {
+                @Override
+                public String generate(String algorithm) {
+                    return hashes.get(name);
+                }
+            };
+        }
     }
 
     SystemModuleFinder() { }
--- a/src/java.base/share/classes/jdk/internal/jimage/ImageReader.java	Thu May 19 09:16:59 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/jimage/ImageReader.java	Thu May 19 11:17:35 2016 -0700
@@ -149,6 +149,17 @@
         return reader.getEntryNames();
     }
 
+    public String[] getModuleNames() {
+        Objects.requireNonNull(reader, "image file closed");
+        int off = "/modules/".length();
+        return reader.findNode("/modules")
+                     .getChildren()
+                     .stream()
+                     .map(Node::getNameString)
+                     .map(s -> s.substring(off, s.length()))
+                     .toArray(String[]::new);
+    }
+
     public long[] getAttributes(int offset) {
         Objects.requireNonNull(reader, "image file closed");
         return reader.getAttributes(offset);
--- a/src/java.base/share/classes/jdk/internal/module/SystemModules.java	Thu May 19 09:16:59 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/module/SystemModules.java	Thu May 19 11:17:35 2016 -0700
@@ -46,12 +46,12 @@
      * and read module-info.class from the run-time image instead of
      * the fastpath.
      */
-    public static final String[] MODULE_NAMES = new String[1];
+    public static final String[] MODULE_NAMES = new String[0];
 
     /**
      * Hash of system modules.
      */
-    public static String[] MODULES_TO_HASH = new String[1];
+    public static String[] MODULES_TO_HASH = new String[0];
 
     /**
      * Number of packages in the boot layer from the installed modules.
@@ -67,7 +67,7 @@
      * When running an exploded image it returns an empty array.
      */
     public static ModuleDescriptor[] modules() {
-        return new ModuleDescriptor[0];
+        throw new InternalError("should not reach here");
     }
 
 }
--- a/test/tools/launcher/modules/patch/PatchTest.java	Thu May 19 09:16:59 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,196 +0,0 @@
-/*
- * Copyright (c) 2015, 2016, 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
- * @library /lib/testlibrary
- * @modules jdk.compiler
- * @build PatchTest CompilerUtils JarUtils jdk.testlibrary.*
- * @run testng PatchTest
- * @summary Basic test for -Xpatch
- */
-
-import java.io.File;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import static jdk.testlibrary.ProcessTools.*;
-
-import org.testng.annotations.BeforeTest;
-import org.testng.annotations.Test;
-import static org.testng.Assert.*;
-
-
-/**
- * Compiles and launches a test that uses -Xpatch with two directories of
- * classes to override existing and add new classes to modules in the
- * boot layer.
- *
- * The classes overridden or added via -Xpatch all define a public no-arg
- * constructor and override toString to return "hi". This allows the launched
- * test to check that the overridden classes are loaded.
- */
-
-@Test
-public class PatchTest {
-
-    // top-level source directory
-    private static final String TEST_SRC = System.getProperty("test.src");
-
-    // source/destination tree for the test module
-    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
-    private static final Path MODS_DIR = Paths.get("mods");
-
-    // source/destination tree for patch tree 1
-    private static final Path SRC1_DIR = Paths.get(TEST_SRC, "src1");
-    private static final Path PATCHES1_DIR = Paths.get("patches1");
-
-    // source/destination tree for patch tree 2
-    private static final Path SRC2_DIR = Paths.get(TEST_SRC, "src2");
-    private static final Path PATCHES2_DIR = Paths.get("patches2");
-
-    // destination directory for patches packaged as JAR files
-    private static final Path PATCHES_DIR = Paths.get("patches");
-
-
-    // the classes overridden or added with -Xpatch
-    private static final String[] CLASSES = {
-
-        // java.base = boot loader
-        "java.base/java.text.Annotation",           // override class
-        "java.base/java.text.AnnotationBuddy",      // add class to package
-        "java.base/java.lang2.Object",              // new package
-
-        // jdk.naming.dns = platform class loader
-        "jdk.naming.dns/com.sun.jndi.dns.DnsClient",
-        "jdk.naming.dns/com.sun.jndi.dns.DnsClientBuddy",
-        "jdk.naming.dns/com.sun.jndi.dns2.Zone",
-
-        // jdk.compiler = application class loaded
-        "jdk.compiler/com.sun.tools.javac.Main",
-        "jdk.compiler/com.sun.tools.javac.MainBuddy",
-        "jdk.compiler/com.sun.tools.javac2.Main",
-
-    };
-
-
-    @BeforeTest
-    public void setup() throws Exception {
-
-        // javac -d mods/test src/test/**
-        boolean compiled= CompilerUtils.compile(SRC_DIR.resolve("test"),
-                                                MODS_DIR.resolve("test"));
-        assertTrue(compiled, "classes did not compile");
-
-        // javac -Xmodule:$MODULE -d patches1/$MODULE patches1/$MODULE/**
-        // jar cf patches/$MODULE-1.jar -C patches1/$MODULE .
-        for (Path src : Files.newDirectoryStream(SRC1_DIR)) {
-            Path output = PATCHES1_DIR.resolve(src.getFileName());
-            String mn = src.getFileName().toString();
-            compiled  = CompilerUtils.compile(src, output, "-Xmodule:" + mn);
-            assertTrue(compiled, "classes did not compile");
-            JarUtils.createJarFile(PATCHES_DIR.resolve(mn + "-1.jar"), output);
-        }
-
-        // javac -Xmodule:$MODULE -d patches2/$MODULE patches2/$MODULE/**
-        // jar cf patches/$MODULE-2.jar -C patches2/$MODULE .
-        for (Path src : Files.newDirectoryStream(SRC2_DIR)) {
-            Path output = PATCHES2_DIR.resolve(src.getFileName());
-            String mn = src.getFileName().toString();
-            compiled  = CompilerUtils.compile(src, output, "-Xmodule:" + mn);
-            assertTrue(compiled, "classes did not compile");
-            JarUtils.createJarFile(PATCHES_DIR.resolve(mn + "-2.jar"), output);
-        }
-
-    }
-
-    /**
-     * Run test with patches to java.base, jdk.naming.dns and jdk.compiler
-     */
-    void runTest(String basePatches, String dnsPatches, String compilerPatches)
-        throws Exception
-    {
-        // the argument to the test is the list of classes overridden or added
-        String arg = Stream.of(CLASSES).collect(Collectors.joining(","));
-
-        int exitValue
-            =  executeTestJava("-Xpatch:java.base=" + basePatches,
-                               "-Xpatch:jdk.naming.dns=" + dnsPatches,
-                               "-Xpatch:jdk.compiler=" + compilerPatches,
-                               "-XaddExports:java.base/java.lang2=test",
-                               "-XaddExports:jdk.naming.dns/com.sun.jndi.dns=test",
-                               "-XaddExports:jdk.naming.dns/com.sun.jndi.dns2=test",
-                               "-XaddExports:jdk.compiler/com.sun.tools.javac2=test",
-                               "-addmods", "jdk.naming.dns,jdk.compiler",
-                               "-mp", MODS_DIR.toString(),
-                               "-m", "test/jdk.test.Main", arg)
-                .outputTo(System.out)
-                .errorTo(System.out)
-                .getExitValue();
-
-        assertTrue(exitValue == 0);
-    }
-
-
-    /**
-     * Run test with -Xpatch and exploded patches
-     */
-    public void testWithExplodedPatches() throws Exception {
-
-        // patches1/java.base:patches2/java.base
-        String basePatches = PATCHES1_DIR.resolve("java.base")
-                + File.pathSeparator + PATCHES2_DIR.resolve("java.base");
-
-        String dnsPatches = PATCHES1_DIR.resolve("jdk.naming.dns")
-                + File.pathSeparator + PATCHES2_DIR.resolve("jdk.naming.dns");
-
-        String compilerPatches = PATCHES1_DIR.resolve("jdk.compiler")
-                + File.pathSeparator + PATCHES2_DIR.resolve("jdk.compiler");
-
-        runTest(basePatches, dnsPatches, compilerPatches);
-    }
-
-
-    /**
-     * Run test with -Xpatch and patches in JAR files
-     */
-    public void testWitJarPatches() throws Exception {
-
-        // patches/java.base-1.jar:patches/java-base-2.jar
-        String basePatches = PATCHES_DIR.resolve("java.base-1.jar")
-                + File.pathSeparator + PATCHES_DIR.resolve("java.base-2.jar");
-
-        String dnsPatches = PATCHES_DIR.resolve("jdk.naming.dns-1.jar")
-                +  File.pathSeparator + PATCHES_DIR.resolve("jdk.naming.dns-2.jar");
-
-        String compilerPatches = PATCHES_DIR.resolve("jdk.compiler-1.jar")
-                +  File.pathSeparator + PATCHES_DIR.resolve("jdk.compiler-2.jar");
-
-        runTest(basePatches, dnsPatches, compilerPatches);
-
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/patch/basic/PatchTest.java	Thu May 19 11:17:35 2016 -0700
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2015, 2016, 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
+ * @library /lib/testlibrary
+ * @modules jdk.compiler
+ * @build PatchTest CompilerUtils JarUtils jdk.testlibrary.*
+ * @run testng PatchTest
+ * @summary Basic test for -Xpatch
+ */
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static jdk.testlibrary.ProcessTools.*;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+
+/**
+ * Compiles and launches a test that uses -Xpatch with two directories of
+ * classes to override existing and add new classes to modules in the
+ * boot layer.
+ *
+ * The classes overridden or added via -Xpatch all define a public no-arg
+ * constructor and override toString to return "hi". This allows the launched
+ * test to check that the overridden classes are loaded.
+ */
+
+@Test
+public class PatchTest {
+
+    // top-level source directory
+    private static final String TEST_SRC = System.getProperty("test.src");
+
+    // source/destination tree for the test module
+    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+    private static final Path MODS_DIR = Paths.get("mods");
+
+    // source/destination tree for patch tree 1
+    private static final Path SRC1_DIR = Paths.get(TEST_SRC, "src1");
+    private static final Path PATCHES1_DIR = Paths.get("patches1");
+
+    // source/destination tree for patch tree 2
+    private static final Path SRC2_DIR = Paths.get(TEST_SRC, "src2");
+    private static final Path PATCHES2_DIR = Paths.get("patches2");
+
+    // destination directory for patches packaged as JAR files
+    private static final Path PATCHES_DIR = Paths.get("patches");
+
+
+    // the classes overridden or added with -Xpatch
+    private static final String[] CLASSES = {
+
+        // java.base = boot loader
+        "java.base/java.text.Annotation",           // override class
+        "java.base/java.text.AnnotationBuddy",      // add class to package
+        "java.base/java.lang2.Object",              // new package
+
+        // jdk.naming.dns = platform class loader
+        "jdk.naming.dns/com.sun.jndi.dns.DnsClient",
+        "jdk.naming.dns/com.sun.jndi.dns.DnsClientBuddy",
+        "jdk.naming.dns/com.sun.jndi.dns2.Zone",
+
+        // jdk.compiler = application class loaded
+        "jdk.compiler/com.sun.tools.javac.Main",
+        "jdk.compiler/com.sun.tools.javac.MainBuddy",
+        "jdk.compiler/com.sun.tools.javac2.Main",
+
+    };
+
+
+    @BeforeTest
+    public void setup() throws Exception {
+
+        // javac -d mods/test src/test/**
+        boolean compiled= CompilerUtils.compile(SRC_DIR.resolve("test"),
+                                                MODS_DIR.resolve("test"));
+        assertTrue(compiled, "classes did not compile");
+
+        // javac -Xmodule:$MODULE -d patches1/$MODULE patches1/$MODULE/**
+        // jar cf patches/$MODULE-1.jar -C patches1/$MODULE .
+        for (Path src : Files.newDirectoryStream(SRC1_DIR)) {
+            Path output = PATCHES1_DIR.resolve(src.getFileName());
+            String mn = src.getFileName().toString();
+            compiled  = CompilerUtils.compile(src, output, "-Xmodule:" + mn);
+            assertTrue(compiled, "classes did not compile");
+            JarUtils.createJarFile(PATCHES_DIR.resolve(mn + "-1.jar"), output);
+        }
+
+        // javac -Xmodule:$MODULE -d patches2/$MODULE patches2/$MODULE/**
+        // jar cf patches/$MODULE-2.jar -C patches2/$MODULE .
+        for (Path src : Files.newDirectoryStream(SRC2_DIR)) {
+            Path output = PATCHES2_DIR.resolve(src.getFileName());
+            String mn = src.getFileName().toString();
+            compiled  = CompilerUtils.compile(src, output, "-Xmodule:" + mn);
+            assertTrue(compiled, "classes did not compile");
+            JarUtils.createJarFile(PATCHES_DIR.resolve(mn + "-2.jar"), output);
+        }
+
+    }
+
+    /**
+     * Run test with patches to java.base, jdk.naming.dns and jdk.compiler
+     */
+    void runTest(String basePatches, String dnsPatches, String compilerPatches)
+        throws Exception
+    {
+        // the argument to the test is the list of classes overridden or added
+        String arg = Stream.of(CLASSES).collect(Collectors.joining(","));
+
+        int exitValue
+            =  executeTestJava("-Xpatch:java.base=" + basePatches,
+                               "-Xpatch:jdk.naming.dns=" + dnsPatches,
+                               "-Xpatch:jdk.compiler=" + compilerPatches,
+                               "-XaddExports:java.base/java.lang2=test",
+                               "-XaddExports:jdk.naming.dns/com.sun.jndi.dns=test",
+                               "-XaddExports:jdk.naming.dns/com.sun.jndi.dns2=test",
+                               "-XaddExports:jdk.compiler/com.sun.tools.javac2=test",
+                               "-addmods", "jdk.naming.dns,jdk.compiler",
+                               "-mp", MODS_DIR.toString(),
+                               "-m", "test/jdk.test.Main", arg)
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .getExitValue();
+
+        assertTrue(exitValue == 0);
+    }
+
+
+    /**
+     * Run test with -Xpatch and exploded patches
+     */
+    public void testWithExplodedPatches() throws Exception {
+
+        // patches1/java.base:patches2/java.base
+        String basePatches = PATCHES1_DIR.resolve("java.base")
+                + File.pathSeparator + PATCHES2_DIR.resolve("java.base");
+
+        String dnsPatches = PATCHES1_DIR.resolve("jdk.naming.dns")
+                + File.pathSeparator + PATCHES2_DIR.resolve("jdk.naming.dns");
+
+        String compilerPatches = PATCHES1_DIR.resolve("jdk.compiler")
+                + File.pathSeparator + PATCHES2_DIR.resolve("jdk.compiler");
+
+        runTest(basePatches, dnsPatches, compilerPatches);
+    }
+
+
+    /**
+     * Run test with -Xpatch and patches in JAR files
+     */
+    public void testWitJarPatches() throws Exception {
+
+        // patches/java.base-1.jar:patches/java-base-2.jar
+        String basePatches = PATCHES_DIR.resolve("java.base-1.jar")
+                + File.pathSeparator + PATCHES_DIR.resolve("java.base-2.jar");
+
+        String dnsPatches = PATCHES_DIR.resolve("jdk.naming.dns-1.jar")
+                +  File.pathSeparator + PATCHES_DIR.resolve("jdk.naming.dns-2.jar");
+
+        String compilerPatches = PATCHES_DIR.resolve("jdk.compiler-1.jar")
+                +  File.pathSeparator + PATCHES_DIR.resolve("jdk.compiler-2.jar");
+
+        runTest(basePatches, dnsPatches, compilerPatches);
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/patch/basic/src/test/jdk/test/Main.java	Thu May 19 11:17:35 2016 -0700
@@ -0,0 +1,74 @@
+/**
+ * Copyright (c) 2015, 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.
+ */
+
+/**
+ * Used with -Xpatch to exercise the replacement or addition of classes
+ * in modules that are linked into the runtime image.
+ */
+
+package jdk.test;
+
+import java.lang.reflect.Module;
+
+public class Main {
+
+    public static void main(String[] args) throws Exception {
+
+        for (String moduleAndClass : args[0].split(",")) {
+            String mn = moduleAndClass.split("/")[0];
+            String cn = moduleAndClass.split("/")[1];
+
+            // load class
+            Class<?> c = Class.forName(cn);
+
+            // check in expected module
+            Module m = c.getModule();
+            assertEquals(m.getName(), mn);
+
+            // instantiate object
+            Main.class.getModule().addReads(m);
+            Object obj = c.newInstance();
+
+            // check that the expected version of the class is loaded
+            System.out.print(moduleAndClass);
+            String s = obj.toString();
+            System.out.println(" says " + s);
+            assertEquals(s, "hi");
+
+            // check Module getResourceAsStream
+            String rn = cn.replace('.', '/') + ".class";
+            assertNotNull(m.getResourceAsStream(rn));
+        }
+    }
+
+
+    static void assertEquals(Object o1, Object o2) {
+        if (!o1.equals(o2))
+            throw new RuntimeException("assertion failed");
+    }
+
+    static void assertNotNull(Object o) {
+        if (o == null)
+            throw new RuntimeException("unexpected null");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/patch/basic/src/test/module-info.java	Thu May 19 11:17:35 2016 -0700
@@ -0,0 +1,25 @@
+/**
+ * Copyright (c) 2015, 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.
+ */
+
+module test {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/patch/basic/src1/java.base/java/text/Annotation.java	Thu May 19 11:17:35 2016 -0700
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+package java.text;
+
+public class Annotation {
+    public String toString() { return "hi"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/patch/basic/src1/java.base/java/text/AnnotationBuddy.java	Thu May 19 11:17:35 2016 -0700
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+package java.text;
+
+public class AnnotationBuddy {
+    public String toString() { return "hi"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/patch/basic/src1/jdk.compiler/com/sun/tools/javac/Main.java	Thu May 19 11:17:35 2016 -0700
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+package com.sun.tools.javac;
+
+public class Main {
+    public String toString() { return "hi"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/patch/basic/src1/jdk.compiler/com/sun/tools/javac/MainBuddy.java	Thu May 19 11:17:35 2016 -0700
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+package com.sun.tools.javac;
+
+public class MainBuddy {
+    public String toString() { return "hi"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/patch/basic/src1/jdk.naming.dns/com/sun/jndi/dns/DnsClient.java	Thu May 19 11:17:35 2016 -0700
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+package com.sun.jndi.dns;
+
+public class DnsClient {
+    public String toString() { return "hi"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/patch/basic/src1/jdk.naming.dns/com/sun/jndi/dns/DnsClientBuddy.java	Thu May 19 11:17:35 2016 -0700
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+package com.sun.jndi.dns;
+
+public class DnsClientBuddy {
+    public String toString() { return "hi"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/patch/basic/src2/java.base/java/lang2/Object.java	Thu May 19 11:17:35 2016 -0700
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2015, 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.
+ */
+
+package java.lang2;
+
+public class Object {
+    public String toString() { return "hi"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/patch/basic/src2/jdk.compiler/com/sun/tools/javac2/Main.java	Thu May 19 11:17:35 2016 -0700
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2015, 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.
+ */
+
+package com.sun.tools.javac2;
+
+public class Main {
+    public String toString() { return "hi"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/patch/basic/src2/jdk.naming.dns/com/sun/jndi/dns2/Zone.java	Thu May 19 11:17:35 2016 -0700
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2015, 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.
+ */
+
+package com.sun.jndi.dns2;
+
+public class Zone {
+    public String toString() { return "hi"; }
+}
--- a/test/tools/launcher/modules/patch/src/test/jdk/test/Main.java	Thu May 19 09:16:59 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +0,0 @@
-/**
- * Copyright (c) 2015, 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.
- */
-
-/**
- * Used with -Xpatch to exercise the replacement or addition of classes
- * in modules that are linked into the runtime image.
- */
-
-package jdk.test;
-
-import java.lang.reflect.Module;
-
-public class Main {
-
-    public static void main(String[] args) throws Exception {
-
-        for (String moduleAndClass : args[0].split(",")) {
-            String mn = moduleAndClass.split("/")[0];
-            String cn = moduleAndClass.split("/")[1];
-
-            // load class
-            Class<?> c = Class.forName(cn);
-
-            // check in expected module
-            Module m = c.getModule();
-            assertEquals(m.getName(), mn);
-
-            // instantiate object
-            Main.class.getModule().addReads(m);
-            Object obj = c.newInstance();
-
-            // check that the expected version of the class is loaded
-            System.out.print(moduleAndClass);
-            String s = obj.toString();
-            System.out.println(" says " + s);
-            assertEquals(s, "hi");
-
-            // check Module getResourceAsStream
-            String rn = cn.replace('.', '/') + ".class";
-            assertNotNull(m.getResourceAsStream(rn));
-        }
-    }
-
-
-    static void assertEquals(Object o1, Object o2) {
-        if (!o1.equals(o2))
-            throw new RuntimeException("assertion failed");
-    }
-
-    static void assertNotNull(Object o) {
-        if (o == null)
-            throw new RuntimeException("unexpected null");
-    }
-}
--- a/test/tools/launcher/modules/patch/src/test/module-info.java	Thu May 19 09:16:59 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-/**
- * Copyright (c) 2015, 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.
- */
-
-module test {
-}
--- a/test/tools/launcher/modules/patch/src1/java.base/java/text/Annotation.java	Thu May 19 09:16:59 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,28 +0,0 @@
-/*
- * Copyright (c) 2015, 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.
- */
-
-package java.text;
-
-public class Annotation {
-    public String toString() { return "hi"; }
-}
--- a/test/tools/launcher/modules/patch/src1/java.base/java/text/AnnotationBuddy.java	Thu May 19 09:16:59 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,28 +0,0 @@
-/*
- * Copyright (c) 2015, 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.
- */
-
-package java.text;
-
-public class AnnotationBuddy {
-    public String toString() { return "hi"; }
-}
--- a/test/tools/launcher/modules/patch/src1/jdk.compiler/com/sun/tools/javac/Main.java	Thu May 19 09:16:59 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,28 +0,0 @@
-/*
- * Copyright (c) 2015, 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.
- */
-
-package com.sun.tools.javac;
-
-public class Main {
-    public String toString() { return "hi"; }
-}
--- a/test/tools/launcher/modules/patch/src1/jdk.compiler/com/sun/tools/javac/MainBuddy.java	Thu May 19 09:16:59 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,28 +0,0 @@
-/*
- * Copyright (c) 2015, 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.
- */
-
-package com.sun.tools.javac;
-
-public class MainBuddy {
-    public String toString() { return "hi"; }
-}
--- a/test/tools/launcher/modules/patch/src1/jdk.naming.dns/com/sun/jndi/dns/DnsClient.java	Thu May 19 09:16:59 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,28 +0,0 @@
-/*
- * Copyright (c) 2015, 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.
- */
-
-package com.sun.jndi.dns;
-
-public class DnsClient {
-    public String toString() { return "hi"; }
-}
--- a/test/tools/launcher/modules/patch/src1/jdk.naming.dns/com/sun/jndi/dns/DnsClientBuddy.java	Thu May 19 09:16:59 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,28 +0,0 @@
-/*
- * Copyright (c) 2015, 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.
- */
-
-package com.sun.jndi.dns;
-
-public class DnsClientBuddy {
-    public String toString() { return "hi"; }
-}
--- a/test/tools/launcher/modules/patch/src2/java.base/java/lang2/Object.java	Thu May 19 09:16:59 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,28 +0,0 @@
-/**
- * Copyright (c) 2015, 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.
- */
-
-package java.lang2;
-
-public class Object {
-    public String toString() { return "hi"; }
-}
--- a/test/tools/launcher/modules/patch/src2/jdk.compiler/com/sun/tools/javac2/Main.java	Thu May 19 09:16:59 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,28 +0,0 @@
-/**
- * Copyright (c) 2015, 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.
- */
-
-package com.sun.tools.javac2;
-
-public class Main {
-    public String toString() { return "hi"; }
-}
--- a/test/tools/launcher/modules/patch/src2/jdk.naming.dns/com/sun/jndi/dns2/Zone.java	Thu May 19 09:16:59 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,28 +0,0 @@
-/**
- * Copyright (c) 2015, 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.
- */
-
-package com.sun.jndi.dns2;
-
-public class Zone {
-    public String toString() { return "hi"; }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/patch/systemmodules/PatchSystemModules.java	Thu May 19 11:17:35 2016 -0700
@@ -0,0 +1,225 @@
+/**
+ * Copyright (c) 2016, 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 8157068
+ * @summary Patch java.base and user module with Hashes attribute tied with
+ *          other module.
+ * @library /lib/testlibrary
+ * @modules jdk.compiler
+ * @build CompilerUtils
+ * @run testng PatchSystemModules
+ */
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Stream;
+
+import jdk.testlibrary.FileUtils;
+import jdk.testlibrary.JDKToolFinder;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+
+import static jdk.testlibrary.ProcessTools.executeCommand;
+import static org.testng.Assert.*;
+
+public class PatchSystemModules {
+    private static final String JAVA_HOME = System.getProperty("java.home");
+
+    private static final Path TEST_SRC = Paths.get(System.getProperty("test.src"));
+    private static final Path PATCH_SRC_DIR = TEST_SRC.resolve("src1");
+
+    private static final Path JMODS = Paths.get(JAVA_HOME, "jmods");
+    private static final Path MODS_DIR = Paths.get("mods");
+    private static final Path JARS_DIR = Paths.get("jars");
+    private static final Path PATCH_DIR = Paths.get("patches");
+    private static final Path IMAGE = Paths.get("image");
+
+    private static final String JAVA_BASE = "java.base";
+    private final String[] modules = new String[] { "m1", "m2" };
+
+    @BeforeTest
+    private void setup() throws Throwable {
+        Path src = TEST_SRC.resolve("src");
+        for (String name : modules) {
+            assertTrue(CompilerUtils.compile(src.resolve(name),
+                                             MODS_DIR,
+                                             "-modulesourcepath", src.toString()));
+        }
+
+        // compile patched source
+        assertTrue(CompilerUtils.compile(PATCH_SRC_DIR.resolve(JAVA_BASE),
+                                         PATCH_DIR.resolve(JAVA_BASE),
+                                         "-Xmodule:java.base"));
+        assertTrue(CompilerUtils.compile(PATCH_SRC_DIR.resolve("m2"),
+                                         PATCH_DIR.resolve("m2")));
+
+        // create an image with only m1 and m2
+        if (Files.exists(JMODS)) {
+            // create an image with m1,m2
+            createImage();
+        }
+    }
+
+    @Test
+    public void test() throws Throwable {
+        Path patchedJavaBase = PATCH_DIR.resolve(JAVA_BASE);
+        Path patchedM2 = PATCH_DIR.resolve("m2");
+
+        Path home = Paths.get(JAVA_HOME);
+        runTest(home,
+                "-mp", MODS_DIR.toString(),
+                "-m", "m1/p1.Main", "1");
+        runTest(home,
+                "-Xpatch:java.base=" + patchedJavaBase.toString(),
+                "-mp", MODS_DIR.toString(),
+                "-m", "m1/p1.Main", "1");
+
+        runTest(home,
+                "-Xpatch:m2=" + patchedM2.toString(),
+                "-mp", MODS_DIR.toString(),
+                "-m", "m1/p1.Main", "2");
+    }
+
+    @Test
+    public void testImage() throws Throwable {
+        if (Files.notExists(JMODS))
+            return;
+
+        Path patchedJavaBase = PATCH_DIR.resolve(JAVA_BASE);
+        Path patchedM2 = PATCH_DIR.resolve("m2");
+
+        runTest(IMAGE,
+                "-m", "m1/p1.Main", "1");
+        runTest(IMAGE,
+                "-Xpatch:java.base=" + patchedJavaBase.toString(),
+                "-m", "m1/p1.Main", "1");
+        runTest(IMAGE,
+                "-Xpatch:m2=" + patchedM2.toString(),
+                "-m", "m1/p1.Main", "2");
+    }
+
+    @Test
+    public void upgradeTiedModule() throws Throwable {
+        if (Files.notExists(JMODS))
+            return;
+
+        Path m1 = MODS_DIR.resolve("m1.jar");
+
+        // create another m1.jar
+        jar("--create",
+            "--file=" + m1.toString(),
+            "-C", MODS_DIR.resolve("m1").toString(), ".");
+
+        // Fail to upgrade m1.jar with mismatched hash
+        runTestWithExitCode(getJava(IMAGE),
+                "-upgrademodulepath", m1.toString(),
+                "-m", "m1/p1.Main");
+
+        runTestWithExitCode(getJava(IMAGE),
+                "-Xpatch:java.base=" + PATCH_DIR.resolve(JAVA_BASE).toString(),
+                "-upgrademodulepath", m1.toString(),
+                "-m", "m1/p1.Main", "1");
+    }
+
+    private void runTestWithExitCode(String... options) throws Throwable {
+        assertTrue(executeCommand(options)
+                        .outputTo(System.out)
+                        .errorTo(System.out)
+                        .shouldContain("differs to expected hash")
+                        .getExitValue() != 0);
+    }
+
+    private void runTest(Path image, String... opts) throws Throwable {
+        String[] options =
+            Stream.concat(Stream.of(getJava(image)),
+                          Stream.of(opts))
+                  .toArray(String[]::new);
+
+        ProcessBuilder pb = new ProcessBuilder(options);
+        int exitValue =  executeCommand(pb)
+                            .outputTo(System.out)
+                            .errorTo(System.out)
+                            .getExitValue();
+
+        assertTrue(exitValue == 0);
+    }
+
+    static void createImage() throws Throwable {
+        FileUtils.deleteFileTreeUnchecked(JARS_DIR);
+        FileUtils.deleteFileTreeUnchecked(IMAGE);
+
+        Files.createDirectories(JARS_DIR);
+        Path m1 = JARS_DIR.resolve("m1.jar");
+        Path m2 = JARS_DIR.resolve("m2.jar");
+
+        // hash m1 in m2's Hashes attribute
+        jar("--create",
+            "--file=" + m1.toString(),
+            "-C", MODS_DIR.resolve("m1").toString(), ".");
+
+        jar("--create",
+            "--file=" + m2.toString(),
+            "--modulepath", JARS_DIR.toString(),
+            "--hash-modules", "m1",
+            "-C", MODS_DIR.resolve("m2").toString(), ".");
+
+
+        String mpath = JARS_DIR.toString() + File.pathSeparator + JMODS.toString();
+        execTool("jlink", "--modulepath", mpath,
+                 "--addmods", "m1",
+                 "--output", IMAGE.toString());
+    }
+
+    static void jar(String... args) throws Throwable {
+        execTool("jar", args);
+    }
+
+    static void execTool(String tool, String... args) throws Throwable {
+        String path = JDKToolFinder.getJDKTool(tool);
+        List<String> commands = new ArrayList<>();
+        commands.add(path);
+        Stream.of(args).forEach(commands::add);
+        ProcessBuilder pb = new ProcessBuilder(commands);
+        int exitValue =  executeCommand(pb)
+            .outputTo(System.out)
+            .errorTo(System.out)
+            .shouldNotContain("no module is recorded in hash")
+            .getExitValue();
+
+        assertTrue(exitValue == 0);
+    }
+
+    static String getJava(Path image) {
+        boolean isWindows = System.getProperty("os.name").toLowerCase().startsWith("win");
+        Path java = image.resolve("bin").resolve(isWindows ? "java.exe" : "java");
+        if (Files.notExists(java))
+            throw new RuntimeException(java + " not found");
+        return java.toAbsolutePath().toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/patch/systemmodules/src/m1/module-info.java	Thu May 19 11:17:35 2016 -0700
@@ -0,0 +1,26 @@
+/**
+ * Copyright (c) 2016, 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.
+ */
+
+module m1 {
+    requires m2;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/patch/systemmodules/src/m1/p1/Main.java	Thu May 19 11:17:35 2016 -0700
@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) 2016, 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.
+ */
+
+package p1;
+
+public class Main {
+    public static void main(String[] args) throws Exception {
+        int version = p2.Lib.version();
+        int expected = args.length == 0 ? 1 : Integer.parseInt(args[0]);
+
+        if (version != expected)
+            throw new RuntimeException(version + " != " + expected + " (expected)");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/patch/systemmodules/src/m2/module-info.java	Thu May 19 11:17:35 2016 -0700
@@ -0,0 +1,26 @@
+/**
+ * Copyright (c) 2016, 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.
+ */
+
+module m2 {
+    exports p2;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/patch/systemmodules/src/m2/p2/Lib.java	Thu May 19 11:17:35 2016 -0700
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2016, 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.
+ */
+
+package p2;
+
+public class Lib {
+    public static int version() {
+        return 1;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/patch/systemmodules/src1/java.base/jdk/internal/modules/SystemModules.java	Thu May 19 11:17:35 2016 -0700
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+package jdk.internal.module;
+
+/*
+ * Test -Xpatch:java.base=jdk/modules/java.base to override
+ * java.base with an exploded image
+ */
+public final class SystemModules {
+    public static final String[] MODULE_NAMES = new String[0];
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/patch/systemmodules/src1/m2/p2/Lib.java	Thu May 19 11:17:35 2016 -0700
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2016, 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.
+ */
+
+package p2;
+
+public class Lib {
+    public static int version() {
+        return 2;
+    }
+}