--- /dev/null 2017-01-21 22:54:52.877512947 -0800 +++ new/src/jdk.compiler/share/classes/com/sun/tools/javac/launcher/Main.java 2018-04-12 12:51:16.180970527 -0700 @@ -0,0 +1,513 @@ +/* + * Copyright (c) 2018, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.launcher; + +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.net.URI; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.InvalidPathException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +import javax.lang.model.element.NestingKind; +import javax.lang.model.element.TypeElement; +import javax.tools.FileObject; +import javax.tools.ForwardingJavaFileManager; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileManager.Location; +import javax.tools.JavaFileObject; +import javax.tools.SimpleJavaFileObject; +import javax.tools.StandardJavaFileManager; +import javax.tools.StandardLocation; + +import com.sun.source.util.JavacTask; +import com.sun.source.util.TaskEvent; +import com.sun.source.util.TaskListener; +import com.sun.tools.javac.api.JavacTool; +import com.sun.tools.javac.code.Source; +import com.sun.tools.javac.resources.LauncherProperties.Errors; +import com.sun.tools.javac.util.JCDiagnostic.Error; + +import jdk.internal.misc.VM; + +import static javax.tools.JavaFileObject.Kind.SOURCE; + +/** + * Compiles a source file, and executes the main method it contains. + * + *
This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own + * risk. This code and its internal interfaces are subject to change + * or deletion without notice.
+ */ +public class Main { + /** + * An exception used to report errors. + */ + public class Fault extends Exception { + private static final long serialVersionUID = 1L; + Fault(Error error) { + super(Main.this.getMessage(error)); + } + } + + /** + * Compiles a source file, and executes the main method it contains. + * + *This is normally invoked from the Java launcher, either when + * the {@code --source} option is used, or when the first argument + * that is not part of a runtime option ends in {@code .java}. + * + *
The first entry in the {@code args} array is the source file + * to be compiled and run; all subsequent entries are passed as + * arguments to the main method of the first class found in the file. + * + *
If any problem occurs before executing the main class, it will + * be reported to the standard error stream, and the the JVM will be + * terminated by calling {@code System.exit} with a non-zero return code. + * + * @param args the arguments + * @throws Throwable if the main method throws an exception + */ + public static void main(String... args) throws Throwable { + try { + new Main(System.err).run(VM.getRuntimeArguments(), args); + } catch (Fault f) { + System.err.println(f.getMessage()); + System.exit(1); + } catch (InvocationTargetException e) { + // leave VM to handle the stacktrace, in the standard manner + throw e.getTargetException(); + } + } + + /** Stream for reporting errors, such as compilation errors. */ + private PrintWriter out; + + /** + * Creates an instance of this class, providing a stream to which to report + * any errors. + * + * @param out the stream + */ + public Main(PrintStream out) { + this(new PrintWriter(new OutputStreamWriter(out), true)); + } + + /** + * Creates an instance of this class, providing a stream to which to report + * any errors. + * + * @param out the stream + */ + public Main(PrintWriter out) { + this.out = out; + } + + /** + * Compiles a source file, and executes the main method it contains. + * + *
The first entry in the {@code args} array is the source file + * to be compiled and run; all subsequent entries are passed as + * arguments to the main method of the first class found in the file. + * + *
Options for {@code javac} are obtained by filtering the runtime arguments. + * + *
If the main method throws an exception, it will be propagated in an
+ * {@code InvocationTargetException}. In that case, the stack trace of the
+ * target exception will be truncated such that the main method will be the
+ * last entry on the stack. In other words, the stack frames leading up to the
+ * invocation of the main method will be removed.
+ *
+ * @param runtimeArgs the runtime arguments
+ * @param args the arguments
+ * @throws Fault if a problem is detected before the main method can be executed
+ * @throws InvocationTargetException if the main method throws an exception
+ */
+ public void run(String[] runtimeArgs, String[] args) throws Fault, InvocationTargetException {
+ Path file = getFile(args);
+
+ Map If the first two bytes are {@code #!}, indicating a "magic number" of an executable
+ * text file, the rest of the first line up to but not including the newline is ignored.
+ * All characters after the first two are read in the
+ * {@link Charset#defaultCharset default platform encoding}.
+ *
+ * @param file the file
+ * @return a file object containing the content of the file
+ * @throws Fault if an error occurs while reading the file
+ */
+ private JavaFileObject readFile(Path file) throws Fault {
+ // use a BufferedInputStream to guarantee that we can use mark and reset.
+ try (BufferedInputStream in = new BufferedInputStream(Files.newInputStream(file))) {
+ in.mark(2);
+ int magic = (in.read() << 8) + in.read();
+ boolean shebang = magic == (('#' << 8) + '!');
+ if (!shebang) {
+ in.reset();
+ }
+ try (BufferedReader r = new BufferedReader(new InputStreamReader(in, Charset.defaultCharset()))) {
+ StringBuilder sb = new StringBuilder();
+ if (shebang) {
+ r.readLine();
+ sb.append("\n"); // preserve line numbers
+ }
+ char[] buf = new char[1024];
+ int n;
+ while ((n = r.read(buf, 0, buf.length)) != -1) {
+ sb.append(buf, 0, n);
+ }
+ return new SimpleJavaFileObject(file.toUri(), SOURCE) {
+ @Override
+ public String getName() {
+ return file.toString();
+ }
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+ return sb;
+ }
+ @Override
+ public boolean isNameCompatible(String simpleName, JavaFileObject.Kind kind) {
+ return (kind == JavaFileObject.Kind.SOURCE)
+ && !simpleName.equals("package-info");
+ }
+ @Override
+ public String toString() {
+ return "JavacSourceLauncher[" + file + "]";
+ }
+ };
+ }
+ } catch (IOException e) {
+ throw new Fault(Errors.CantReadFile(file, e));
+ }
+ }
+
+ /**
+ * Returns the subset of the runtime arguments that are relevant to {@code javac}.
+ * Generally, the relevant options are those for setting paths and for configuring the
+ * module system.
+ *
+ * @param runtimeArgs the runtime arguments
+ * @return the subset of the runtime arguments
+ **/
+ private List Class files (of kind {@JavaFileObject.Kind.CLASS CLASS} written to
+ * {@link StandardLocation#CLASS_OUTPUT} will be written to an in-memory cache.
+ * All other file manager operations will be delegated to a specified file manager.
+ */
+ static class MemoryFileManager extends ForwardingJavaFileManager The classloader uses the standard parent-delegation model, just providing
+ * {@code findClass} to find classes in the in-memory cache.
+ */
+ static class MemoryClassLoader extends ClassLoader {
+ private final Map