1/*
2 * Copyright (c) 2013, 2017, 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
24package sun.hotspot.tools.ctw;
25
26import java.lang.management.ManagementFactory;
27
28import java.io.*;
29import java.nio.file.Files;
30import java.nio.file.Paths;
31
32import java.util.Arrays;
33import java.util.List;
34import java.util.concurrent.*;
35
36public class CompileTheWorld {
37    // in case when a static constructor changes System::out and System::err
38    // we hold these values of output streams
39    static PrintStream OUT = System.out;
40    static final PrintStream ERR = System.err;
41    /**
42     * Entry point. Compiles classes in {@code paths}
43     *
44     * @param paths paths to jar/zip, dir contains classes, or to .lst file
45     *              contains list of classes to compile
46     */
47    public static void main(String[] paths) {
48        if (paths.length == 0) {
49            throw new IllegalArgumentException("Expect a path to a compile target.");
50        }
51        String logfile = Utils.LOG_FILE;
52        PrintStream os = null;
53        if (logfile != null) {
54            try {
55                os = new PrintStream(Files.newOutputStream(Paths.get(logfile)));
56            } catch (IOException io) {
57            }
58        }
59        if (os != null) {
60            OUT = os;
61        }
62
63        boolean passed = false;
64
65        try {
66            try {
67                if (ManagementFactory.getCompilationMXBean() == null) {
68                    throw new RuntimeException(
69                            "CTW can not work in interpreted mode");
70                }
71            } catch (java.lang.NoClassDefFoundError e) {
72                // compact1, compact2 support
73            }
74            ExecutorService executor = createExecutor();
75            long start = System.currentTimeMillis();
76            try {
77                Arrays.stream(paths)
78                      .map(PathHandler::create)
79                      .flatMap(List::stream)
80                      .forEach(p -> {
81                          try {
82                              p.process(executor);
83                          } finally {
84                              p.close();
85                          }
86                        });
87            } finally {
88                await(executor);
89            }
90            CompileTheWorld.OUT.printf("Done (%d classes, %d methods, %d ms)%n",
91                    PathHandler.getProcessedClassCount(),
92                    Compiler.getMethodCount(),
93                    System.currentTimeMillis() - start);
94            passed = true;
95        } catch (Throwable t){
96            t.printStackTrace(ERR);
97        } finally {
98            try {
99                OUT.close();
100            } catch (Throwable ignore) {
101            }
102            // <clinit> might have started new threads
103            System.exit(passed ? 0 : 1);
104        }
105    }
106
107    private static ExecutorService createExecutor() {
108        final int threadsCount = Math.min(
109                Runtime.getRuntime().availableProcessors(),
110                Utils.CI_COMPILER_COUNT);
111        ExecutorService result;
112        if (threadsCount > 1) {
113            result = new ThreadPoolExecutor(threadsCount, threadsCount,
114                    /* keepAliveTime */ 0L, TimeUnit.MILLISECONDS,
115                    new ArrayBlockingQueue<>(threadsCount),
116                    new ThreadPoolExecutor.CallerRunsPolicy());
117        } else {
118            result = new CurrentThreadExecutor();
119        }
120        return result;
121    }
122
123    private static void await(ExecutorService executor) {
124        executor.shutdown();
125        while (!executor.isTerminated()) {
126            try {
127                executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
128            } catch (InterruptedException ie) {
129                Thread.currentThread().interrupt();
130                break;
131            }
132        }
133    }
134
135    private static class CurrentThreadExecutor extends AbstractExecutorService {
136        private boolean isShutdown;
137
138        @Override
139        public void shutdown() {
140            this.isShutdown = true;
141        }
142
143        @Override
144        public List<Runnable> shutdownNow() {
145            return null;
146        }
147
148        @Override
149        public boolean isShutdown() {
150            return isShutdown;
151        }
152
153        @Override
154        public boolean isTerminated() {
155            return isShutdown;
156        }
157
158        @Override
159        public boolean awaitTermination(long timeout, TimeUnit unit)
160                throws InterruptedException {
161            return isShutdown;
162        }
163
164        @Override
165        public void execute(Runnable command) {
166            command.run();
167        }
168    }
169}
170
171