jdk/test/jdk/internal/jimage/VerifyJimage.java
changeset 27565 729f9700483a
child 30820 0d4717a011d3
equal deleted inserted replaced
27564:eaaa79b68cd5 27565:729f9700483a
       
     1 /*
       
     2  * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  */
       
    23 
       
    24 import java.io.File;
       
    25 import java.io.IOException;
       
    26 import java.io.UncheckedIOException;
       
    27 import java.nio.file.DirectoryStream;
       
    28 import java.nio.file.Files;
       
    29 import java.nio.file.Path;
       
    30 import java.nio.file.Paths;
       
    31 import java.nio.file.attribute.BasicFileAttributes;
       
    32 import java.util.ArrayList;
       
    33 import java.util.Arrays;
       
    34 import java.util.Deque;
       
    35 import java.util.List;
       
    36 import java.util.Set;
       
    37 import java.util.concurrent.ConcurrentLinkedDeque;
       
    38 import java.util.concurrent.ExecutorService;
       
    39 import java.util.concurrent.Executors;
       
    40 import java.util.concurrent.TimeUnit;
       
    41 import java.util.concurrent.atomic.AtomicInteger;
       
    42 import java.util.stream.Collectors;
       
    43 import java.util.stream.Stream;
       
    44 
       
    45 import jdk.internal.jimage.BasicImageReader;
       
    46 import jdk.internal.jimage.ImageLocation;
       
    47 
       
    48 /*
       
    49  * @test
       
    50  * @summary Verify jimage
       
    51  * @run main/othervm VerifyJimage
       
    52  */
       
    53 
       
    54 /**
       
    55  * This test runs in two modes:
       
    56  * (1) No argument: it verifies the jimage by loading all classes in the runtime
       
    57  * (2) path of exploded modules: it compares bytes of each file in the exploded
       
    58  *     module with the entry in jimage
       
    59  *
       
    60  * FIXME: exception thrown when findLocation from jimage by multiple threads
       
    61  * -Djdk.test.threads=<n> to specify the number of threads.
       
    62  */
       
    63 public class VerifyJimage {
       
    64     private static final Deque<String> failed = new ConcurrentLinkedDeque<>();
       
    65 
       
    66     public static void main(String... args) throws Exception {
       
    67         long start = System.nanoTime();
       
    68         int numThreads = Integer.getInteger("jdk.test.threads", 1);
       
    69         List<JImageReader> readers = newJImageReaders();
       
    70         VerifyJimage verify = new VerifyJimage(readers, numThreads);
       
    71         if (args.length == 0) {
       
    72             // load classes from jimage
       
    73             verify.loadClasses();
       
    74         } else {
       
    75             Path dir = Paths.get(args[0]);
       
    76             if (Files.notExists(dir) || !Files.isDirectory(dir)) {
       
    77                 throw new RuntimeException("Invalid argument: " + dir);
       
    78             }
       
    79             verify.compareExplodedModules(dir);
       
    80         }
       
    81         verify.waitForCompletion();
       
    82         long end = System.nanoTime();
       
    83         int entries = readers.stream()
       
    84                              .mapToInt(JImageReader::entries)
       
    85                              .sum();
       
    86         System.out.format("%d entries %d files verified: %d ms %d errors%n",
       
    87                           entries, verify.count.get(),
       
    88                           TimeUnit.NANOSECONDS.toMillis(end - start), failed.size());
       
    89         for (String f : failed) {
       
    90             System.err.println(f);
       
    91         }
       
    92     }
       
    93 
       
    94     private final AtomicInteger count = new AtomicInteger(0);
       
    95     private final List<JImageReader> readers;
       
    96     private final ExecutorService pool;
       
    97 
       
    98     VerifyJimage(List<JImageReader> readers, int numThreads) {
       
    99         this.readers = readers;
       
   100         this.pool = Executors.newFixedThreadPool(numThreads);
       
   101     }
       
   102 
       
   103     private void waitForCompletion() throws InterruptedException {
       
   104         pool.shutdown();
       
   105         pool.awaitTermination(20, TimeUnit.SECONDS);
       
   106     }
       
   107 
       
   108     private void compareExplodedModules(Path dir) throws IOException {
       
   109         System.out.println("comparing jimage with " + dir);
       
   110 
       
   111         try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
       
   112             for (Path mdir : stream) {
       
   113                 if (Files.isDirectory(mdir)) {
       
   114                     pool.execute(new Runnable() {
       
   115                         @Override
       
   116                         public void run() {
       
   117                             try {
       
   118                                 Files.find(mdir, Integer.MAX_VALUE, (Path p, BasicFileAttributes attr)
       
   119                                            -> !Files.isDirectory(p) &&
       
   120                                               !mdir.relativize(p).toString().startsWith("_") &&
       
   121                                               !p.getFileName().toString().equals("MANIFEST.MF"))
       
   122                                      .forEach(p -> compare(mdir, p, readers));
       
   123                             } catch (IOException e) {
       
   124                                 throw new UncheckedIOException(e);
       
   125                             }
       
   126                         }
       
   127                     });
       
   128                 }
       
   129             }
       
   130         }
       
   131     }
       
   132 
       
   133     private final List<String> BOOT_RESOURCES = Arrays.asList(
       
   134         "java.base/META-INF/services/java.nio.file.spi.FileSystemProvider"
       
   135     );
       
   136     private final List<String> EXT_RESOURCES = Arrays.asList(
       
   137         "jdk.zipfs/META-INF/services/java.nio.file.spi.FileSystemProvider"
       
   138     );
       
   139     private final List<String> APP_RESOURCES = Arrays.asList(
       
   140         "jdk.hotspot.agent/META-INF/services/com.sun.jdi.connect.Connector",
       
   141         "jdk.jdi/META-INF/services/com.sun.jdi.connect.Connector"
       
   142     );
       
   143 
       
   144     private void compare(Path mdir, Path p, List<JImageReader> readers) {
       
   145         String entry = mdir.relativize(p).toString().replace(File.separatorChar, '/');
       
   146 
       
   147         count.incrementAndGet();
       
   148         String file = mdir.getFileName().toString() + "/" + entry;
       
   149         if (APP_RESOURCES.contains(file)) {
       
   150             // skip until the service config file is merged
       
   151             System.out.println("Skipped " + file);
       
   152             return;
       
   153         }
       
   154 
       
   155         String jimage;
       
   156         if (BOOT_RESOURCES.contains(file)) {
       
   157             jimage = "bootmodules.jimage";
       
   158         } else if (EXT_RESOURCES.contains(file)) {
       
   159             jimage = "extmodules.jimage";
       
   160         } else {
       
   161             jimage = "";
       
   162         }
       
   163         JImageReader reader = readers.stream()
       
   164                 .filter(r -> r.findLocation(entry) != null)
       
   165                 .filter(r -> jimage.isEmpty() || r.imageName().equals(jimage))
       
   166                 .findFirst().orElse(null);
       
   167         if (reader == null) {
       
   168             failed.add(entry + " not found: " + p.getFileName().toString());
       
   169         } else {
       
   170             reader.compare(entry, p);
       
   171         }
       
   172     }
       
   173 
       
   174     private void loadClasses() {
       
   175         ClassLoader loader = ClassLoader.getSystemClassLoader();
       
   176         for (JImageReader reader : readers) {
       
   177             Arrays.stream(reader.getEntryNames())
       
   178                     .filter(n -> n.endsWith(".class"))
       
   179                     .forEach(n -> {
       
   180                         String cn = n.substring(0, n.length()-6).replace('/', '.');
       
   181                         count.incrementAndGet();
       
   182                         try {
       
   183                             Class.forName(cn, false, loader);
       
   184                         } catch (ClassNotFoundException e) {
       
   185                             failed.add(reader.imageName() + ": " + cn + " not found");
       
   186                         }
       
   187                     });
       
   188         }
       
   189     }
       
   190 
       
   191 
       
   192    private static List<JImageReader> newJImageReaders() throws IOException {
       
   193         String home = System.getProperty("java.home");
       
   194         Path mlib = Paths.get(home, "lib", "modules");
       
   195         try (Stream<Path> paths = Files.list(mlib)) {
       
   196             Set<Path> jimages = paths.filter(p -> p.toString().endsWith(".jimage"))
       
   197                                      .collect(Collectors.toSet());
       
   198             List<JImageReader> result = new ArrayList<>();
       
   199             for (Path jimage: jimages) {
       
   200                 result.add(new JImageReader(jimage));
       
   201                 System.out.println("opened " + jimage);
       
   202             }
       
   203             return result;
       
   204         }
       
   205     }
       
   206 
       
   207     static class JImageReader extends BasicImageReader {
       
   208         final Path jimage;
       
   209         JImageReader(Path p) throws IOException {
       
   210             super(p.toString());
       
   211             this.jimage = p;
       
   212         }
       
   213 
       
   214         String imageName() {
       
   215             return jimage.getFileName().toString();
       
   216         }
       
   217 
       
   218         int entries() {
       
   219             return getHeader().getLocationCount();
       
   220         }
       
   221 
       
   222         void compare(String entry, Path p) {
       
   223             try {
       
   224                 byte[] bytes = Files.readAllBytes(p);
       
   225                 byte[] imagebytes = getResource(entry);
       
   226                 if (!Arrays.equals(bytes, imagebytes)) {
       
   227                     failed.add(imageName() + ": bytes differs than " + p.toString());
       
   228                 }
       
   229             } catch (IOException e) {
       
   230                 throw new UncheckedIOException(e);
       
   231             }
       
   232         }
       
   233     }
       
   234 }