8178291: Add CTW test for boot module
authoriignatyev
Thu, 13 Apr 2017 11:23:37 -0700
changeset 46383 24999171edf9
parent 46382 5520c435279b
child 46384 dacebddcdea0
8178291: Add CTW test for boot module Reviewed-by: kvn
hotspot/test/applications/ctw/Modules.java
hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/CompileTheWorld.java
hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/CtwRunner.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/applications/ctw/Modules.java	Thu Apr 13 11:23:37 2017 -0700
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2017, 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
+ * @summary run CTW for all classes from boot "modules" jimage -- lib/modules.
+ *
+ * @library /test/lib / /testlibrary/ctw/src
+ * @modules java.base/jdk.internal.jimage
+ *          java.base/jdk.internal.misc
+ *          java.base/jdk.internal.reflect
+ *
+ * @build sun.hotspot.WhiteBox
+ * @run driver ClassFileInstaller sun.hotspot.WhiteBox
+ *                                sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run driver/timeout=0 sun.hotspot.tools.ctw.CtwRunner modules
+ */
+
--- a/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/CompileTheWorld.java	Thu Apr 13 09:42:10 2017 -0400
+++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/CompileTheWorld.java	Thu Apr 13 11:23:37 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, 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
@@ -87,6 +87,8 @@
                     Compiler.getMethodCount(),
                     System.currentTimeMillis() - start);
             passed = true;
+        } catch (Throwable t){
+            t.printStackTrace(ERR);
         } finally {
             // <clinit> might have started new threads
             System.exit(passed ? 0 : 1);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/CtwRunner.java	Thu Apr 13 11:23:37 2017 -0700
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2017, 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 sun.hotspot.tools.ctw;
+
+import jdk.test.lib.Utils;
+import jdk.test.lib.process.ProcessTools;
+
+import java.io.IOException;
+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.concurrent.TimeUnit;
+import java.util.function.Predicate;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+/**
+ * Runs CompileTheWorld for exact one target. If an error occurs during
+ * compilation of class N, this driver class saves error information and
+ * restarts CTW from class N + 1. All saved errors are reported at the end.
+ * <pre>
+ * Usage: <target to compile>
+ * </pre>
+ */
+public class CtwRunner {
+    private static final Predicate<String> IS_CLASS_LINE = Pattern.compile(
+            "^\\[\\d+\\]\\s*\\S+\\s*$").asPredicate();
+
+    public static void main(String[] args) throws Exception {
+        if (args.length != 1) {
+            throw new Error("Usage: <artifact to compile>");
+        }
+        new CtwRunner(args[0]).run();
+    }
+
+    private final List<Throwable> errors;
+    private final Path targetPath;
+    private final String targetName;
+
+    private CtwRunner(String target) {
+        if (target.equals("modules")) {
+            targetPath = Paths
+                    .get(Utils.TEST_JDK)
+                    .resolve("lib")
+                    .resolve(target);
+        } else {
+            targetPath = Paths.get(target).toAbsolutePath();
+        }
+        targetName = targetPath.getFileName().toString();
+        errors = new ArrayList<>();
+    }
+
+
+    private void run() {
+        startCtwforAllClasses();
+        if (!errors.isEmpty()) {
+            StringBuilder sb = new StringBuilder();
+            sb.append("There were ")
+              .append(errors.size())
+              .append(" errors:[");
+            System.err.println(sb.toString());
+            for (Throwable e : errors) {
+                sb.append("{")
+                  .append(e.getMessage())
+                  .append("}");
+                e.printStackTrace(System.err);
+                System.err.println();
+            }
+            sb.append("]");
+            throw new AssertionError(sb.toString());
+        }
+    }
+
+
+    private void startCtwforAllClasses() {
+        long classStart = 0;
+        boolean done = false;
+        while (!done) {
+            String[] cmd = cmd(classStart);
+            try {
+                ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
+                        /* addTestVmAndJavaOptions = */ true,
+                        cmd);
+                String commandLine = pb.command()
+                        .stream()
+                        .collect(Collectors.joining(" "));
+                String phase = phaseName(classStart);
+                Path out = Paths.get(".", phase + ".out");
+                System.out.printf("%s %dms START : [%s]%n" +
+                        "cout/cerr are redirected to %s%n",
+                        phase, TimeUnit.NANOSECONDS.toMillis(System.nanoTime()),
+                        commandLine, out);
+                int exitCode = pb.redirectErrorStream(true)
+                        .redirectOutput(out.toFile())
+                        .start()
+                        .waitFor();
+                System.out.printf("%s %dms END : exit code = %d%n",
+                        phase, TimeUnit.NANOSECONDS.toMillis(System.nanoTime()),
+                        exitCode);
+                long lastClassIndex = getLastClassIndex(out);
+                if (exitCode == 0) {
+                    done = true;
+                } else {
+                    if (lastClassIndex == 0) {
+                        errors.add(new Error(phase + ": failed during preload"
+                                + " with classStart = " + classStart));
+                        // skip one class
+                        ++classStart;
+                    } else {
+                        errors.add(new Error(phase + ": failed during"
+                                + " compilation of class #" + lastClassIndex));
+                        // continue with the next class
+                        classStart = lastClassIndex + 1;
+                    }
+                }
+            } catch (Exception e) {
+                throw new Error("failed to run from " + classStart, e);
+            }
+        }
+    }
+
+    private long getLastClassIndex(Path errFile) {
+        long result = 0;
+        try {
+            String line = Files.newBufferedReader(errFile)
+                    .lines()
+                    .filter(IS_CLASS_LINE)
+                    .reduce((a, b) -> b).orElse(null);
+            if (line != null) {
+                int open = line.indexOf('[') + 1;
+                int close = line.indexOf(']');
+                result = Long.parseLong(line.substring(open, close));
+            }
+        } catch (IOException ioe) {
+            throw new Error("can not read " + errFile + " : "
+                    + ioe.getMessage(), ioe);
+        }
+        return result;
+    }
+
+    private String[] cmd(long classStart) {
+        String phase = phaseName(classStart);
+        return new String[]{
+                "-Xbatch",
+                "-XX:-UseCounterDecay",
+                "-XX:-ShowMessageBoxOnError",
+                "-XX:+UnlockDiagnosticVMOptions",
+                // define phase start
+                "-DCompileTheWorldStartAt=" + classStart,
+                // CTW library uses WhiteBox API
+                "-XX:+WhiteBoxAPI", "-Xbootclasspath/a:.",
+                // export jdk.internal packages used by CTW library
+                "--add-exports", "java.base/jdk.internal.jimage=ALL-UNNAMED",
+                "--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED",
+                "--add-exports", "java.base/jdk.internal.reflect=ALL-UNNAMED",
+                // enable diagnostic logging
+                "-XX:+LogCompilation",
+                // use phase specific log and hs_err file
+                String.format("-XX:LogFile=hotspot_%s_%%p.log", phase),
+                String.format("-XX:ErrorFile=hs_err_%s_%%p.log", phase),
+                // MethodHandle MUST NOT be compiled
+                "-XX:CompileCommand=exclude,java/lang/invoke/MethodHandle.*",
+                // CTW entry point
+                CompileTheWorld.class.getName(),
+                targetPath.toString(),
+        };
+    }
+
+    private String phaseName(long classStart) {
+        return String.format("%s_%d", targetName, classStart);
+    }
+
+}