changeset 26264:a09fedde76be

8044859: javac duplicates option processing when using Compiler API Reviewed-by: mcimadamore, vromero, jlahoda
author jjg
date Fri, 22 Aug 2014 16:28:16 -0700
parents 5ce1fe94b270
children 46aacfffd3b5
files langtools/make/build.properties langtools/src/jdk.compiler/share/classes/com/sun/source/util/JavacTask.java langtools/src/jdk.compiler/share/classes/com/sun/tools/doclint/DocLint.java langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/BasicJavacTask.java langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTool.java langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Arguments.java langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Main.java langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java langtools/test/tools/javac/6410653/T6410653.java langtools/test/tools/javac/6457284/T6457284.java langtools/test/tools/javac/T6358166.java langtools/test/tools/javac/T6358168.java langtools/test/tools/javac/T8009640/CheckRejectProfileBCPOptionsIfUsedTogetherTest.java langtools/test/tools/javac/api/6410643/T6410643.java langtools/test/tools/javac/api/T6357331.java langtools/test/tools/javac/api/TestJavacTaskScanner.java langtools/test/tools/javac/api/TestJavacTask_Lock.java langtools/test/tools/javac/api/TestResolveError.java langtools/test/tools/javac/api/taskListeners/CompileEvent.java langtools/test/tools/javac/api/taskListeners/EventsBalancedTest.java langtools/test/tools/javac/failover/CheckAttributedTree.java langtools/test/tools/javac/options/modes/AtFilesTest.java langtools/test/tools/javac/options/modes/DocLintTest.java langtools/test/tools/javac/options/modes/FSInfoTest.java langtools/test/tools/javac/options/modes/InfoOptsTest.java langtools/test/tools/javac/options/modes/NoOperandsTest.java langtools/test/tools/javac/options/modes/OutputDirTest.java langtools/test/tools/javac/options/modes/ProfileBootClassPathTest.java langtools/test/tools/javac/options/modes/ProfileTargetTest.java langtools/test/tools/javac/options/modes/SourceTargetTest.java langtools/test/tools/javac/options/modes/StdOutTest.java langtools/test/tools/javac/options/modes/Tester.java langtools/test/tools/javac/profiles/ProfileOptionTest.java langtools/test/tools/javac/versions/Versions.java
diffstat 37 files changed, 2070 insertions(+), 867 deletions(-) [+]
line wrap: on
line diff
--- a/langtools/make/build.properties	Fri Aug 22 12:25:01 2014 +0200
+++ b/langtools/make/build.properties	Fri Aug 22 16:28:16 2014 -0700
@@ -44,7 +44,7 @@
 target.java = ${target.java.home}/bin/java
 
 # Version info -- override as needed
-jdk.version = 1.8.0
+jdk.version = 1.9.0
 build.number = b00
 milestone = internal
 
--- a/langtools/src/jdk.compiler/share/classes/com/sun/source/util/JavacTask.java	Fri Aug 22 12:25:01 2014 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/source/util/JavacTask.java	Fri Aug 22 16:28:16 2014 -0700
@@ -141,6 +141,7 @@
      * Returns a type mirror of the tree node determined by the specified path.
      * This method has been superceded by methods on
      * {@link com.sun.source.util.Trees Trees}.
+     *
      * @param path the path
      * @return the type mirror
      * @see com.sun.source.util.Trees#getTypeMirror
@@ -149,12 +150,14 @@
 
     /**
      * Returns a utility object for dealing with program elements.
-     * @return the utility object for dealing with program elements
+     *
+     * @return a utility object for dealing with program elements
      */
     public abstract Elements getElements();
 
     /**
      * Returns a utility object for dealing with type mirrors.
+     *
      * @return the utility object for dealing with type mirrors
      */
     public abstract Types getTypes();
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/doclint/DocLint.java	Fri Aug 22 12:25:01 2014 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/doclint/DocLint.java	Fri Aug 22 16:28:16 2014 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -29,14 +29,11 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Queue;
-import java.util.Set;
 
 import javax.lang.model.element.Name;
-import javax.tools.JavaFileObject;
 import javax.tools.StandardLocation;
 
 import com.sun.source.doctree.DocCommentTree;
@@ -114,6 +111,9 @@
 
     /**
      * Simple API entry point.
+     * @param args Options and operands for doclint
+     * @throws BadArgs if an error is detected in any args
+     * @throws IOException if there are problems with any of the file arguments
      */
     public void run(String... args) throws BadArgs, IOException {
         PrintWriter out = new PrintWriter(System.out);
@@ -128,12 +128,14 @@
         env = new Env();
         processArgs(args);
 
-        if (needHelp)
+        boolean noFiles = javacFiles.isEmpty();
+        if (needHelp) {
             showHelp(out);
-
-        if (javacFiles.isEmpty()) {
-            if (!needHelp)
-                out.println(localize("dc.main.no.files.given"));
+            if (noFiles)
+                return;
+        } else if (noFiles) {
+            out.println(localize("dc.main.no.files.given"));
+            return;
         }
 
         JavacTool tool = JavacTool.create();
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/BasicJavacTask.java	Fri Aug 22 12:25:01 2014 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/BasicJavacTask.java	Fri Aug 22 16:28:16 2014 -0700
@@ -25,9 +25,10 @@
 
 package com.sun.tools.javac.api;
 
-import java.io.IOException;
 import java.util.Collection;
+import java.util.LinkedHashSet;
 import java.util.Locale;
+import java.util.Set;
 
 import javax.annotation.processing.Processor;
 import javax.lang.model.element.Element;
@@ -39,11 +40,19 @@
 import com.sun.source.tree.CompilationUnitTree;
 import com.sun.source.tree.Tree;
 import com.sun.source.util.JavacTask;
+import com.sun.source.util.Plugin;
 import com.sun.source.util.TaskListener;
+import com.sun.tools.doclint.DocLint;
+import com.sun.tools.javac.main.JavaCompiler;
 import com.sun.tools.javac.model.JavacElements;
 import com.sun.tools.javac.model.JavacTypes;
+import com.sun.tools.javac.processing.JavacProcessingEnvironment;
 import com.sun.tools.javac.tree.JCTree;
 import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.Log;
+import com.sun.tools.javac.util.PropagatedException;
+import com.sun.tools.javac.util.ServiceLoader;
 
 /**
  * Provides basic functionality for implementations of JavacTask.
@@ -71,17 +80,17 @@
     }
 
     @Override
-    public Iterable<? extends CompilationUnitTree> parse() throws IOException {
+    public Iterable<? extends CompilationUnitTree> parse() {
         throw new IllegalStateException();
     }
 
     @Override
-    public Iterable<? extends Element> analyze() throws IOException {
+    public Iterable<? extends Element> analyze() {
         throw new IllegalStateException();
     }
 
     @Override
-    public Iterable<? extends JavaFileObject> generate() throws IOException {
+    public Iterable<? extends JavaFileObject> generate() {
         throw new IllegalStateException();
     }
 
@@ -123,32 +132,72 @@
 
     @Override
     public Elements getElements() {
+        if (context == null)
+            throw new IllegalStateException();
         return JavacElements.instance(context);
     }
 
     @Override
     public Types getTypes() {
+        if (context == null)
+            throw new IllegalStateException();
         return JavacTypes.instance(context);
     }
 
+    @Override
     public void setProcessors(Iterable<? extends Processor> processors) {
         throw new IllegalStateException();
     }
 
+    @Override
     public void setLocale(Locale locale) {
         throw new IllegalStateException();
     }
 
+    @Override
     public Boolean call() {
         throw new IllegalStateException();
     }
 
     /**
-     * For internal use only.  This method will be
-     * removed without warning.
+     * For internal use only.
+     * This method will be removed without warning.
+     * @return the context
      */
     public Context getContext() {
         return context;
     }
 
+    public void initPlugins(Set<List<String>> pluginOpts) {
+        if (pluginOpts.isEmpty())
+            return;
+
+        Set<List<String>> pluginsToCall = new LinkedHashSet<>(pluginOpts);
+        JavacProcessingEnvironment pEnv = JavacProcessingEnvironment.instance(context);
+        ClassLoader cl = pEnv.getProcessorClassLoader();
+        ServiceLoader<Plugin> sl = ServiceLoader.load(Plugin.class, cl);
+        for (Plugin plugin : sl) {
+            for (List<String> p : pluginsToCall) {
+                if (plugin.getName().equals(p.head)) {
+                    pluginsToCall.remove(p);
+                    try {
+                        plugin.init(this, p.tail.toArray(new String[p.tail.size()]));
+                    } catch (RuntimeException ex) {
+                        throw new PropagatedException(ex);
+                    }
+                }
+            }
+        }
+        for (List<String> p: pluginsToCall) {
+            Log.instance(context).error("msg.plugin.not.found", p.head);
+        }
+    }
+
+    public void initDocLint(List<String> docLintOpts) {
+        if (docLintOpts.isEmpty())
+            return;
+
+        new DocLint().init(this, docLintOpts.toArray(new String[docLintOpts.size()]));
+        JavaCompiler.instance(context).keepComments = true;
+    }
 }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java	Fri Aug 22 12:25:01 2014 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java	Fri Aug 22 16:28:16 2014 -0700
@@ -25,33 +25,32 @@
 
 package com.sun.tools.javac.api;
 
-import java.io.File;
-import java.io.IOException;
 import java.nio.CharBuffer;
 import java.util.*;
+import java.util.concurrent.Callable;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import javax.annotation.processing.Processor;
 import javax.lang.model.element.Element;
 import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.TypeMirror;
 import javax.tools.*;
 
 import com.sun.source.tree.*;
-import com.sun.source.util.*;
 import com.sun.tools.javac.code.*;
-import com.sun.tools.javac.code.Symbol.*;
+import com.sun.tools.javac.code.Symbol.ClassSymbol;
 import com.sun.tools.javac.comp.*;
-import com.sun.tools.javac.file.JavacFileManager;
 import com.sun.tools.javac.main.*;
 import com.sun.tools.javac.main.JavaCompiler;
-import com.sun.tools.javac.model.*;
 import com.sun.tools.javac.parser.Parser;
 import com.sun.tools.javac.parser.ParserFactory;
+import com.sun.tools.javac.processing.AnnotationProcessingError;
 import com.sun.tools.javac.tree.*;
-import com.sun.tools.javac.tree.JCTree.*;
+import com.sun.tools.javac.tree.JCTree.JCClassDecl;
+import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.Log.PrefixKind;
+import com.sun.tools.javac.util.Log.WriterKind;
 
 /**
  * Provides access to functionality specific to the JDK Java Compiler, javac.
@@ -65,82 +64,45 @@
  * @author Jonathan Gibbons
  */
 public class JavacTaskImpl extends BasicJavacTask {
-    private Main compilerMain;
+    private final Arguments args;
     private JavaCompiler compiler;
     private Locale locale;
-    private String[] args;
-    private String[] classNames;
-    private List<JavaFileObject> fileObjects;
     private Map<JavaFileObject, JCCompilationUnit> notYetEntered;
     private ListBuffer<Env<AttrContext>> genList;
     private final AtomicBoolean used = new AtomicBoolean();
     private Iterable<? extends Processor> processors;
 
-    private Main.Result result = null;
-
-    JavacTaskImpl(Main compilerMain,
-                String[] args,
-                String[] classNames,
-                Context context,
-                List<JavaFileObject> fileObjects) {
-        super(null, false);
-        this.compilerMain = compilerMain;
-        this.args = args;
-        this.classNames = classNames;
-        this.context = context;
-        this.fileObjects = fileObjects;
-        setLocale(Locale.getDefault());
-        // null checks
-        compilerMain.getClass();
-        args.getClass();
-        fileObjects.getClass();
+    JavacTaskImpl(Context context) {
+        super(context, true);
+        args = Arguments.instance(context);
     }
 
-    JavacTaskImpl(Main compilerMain,
-                Iterable<String> args,
-                Context context,
-                Iterable<String> classes,
-                Iterable<? extends JavaFileObject> fileObjects) {
-        this(compilerMain, toArray(args), toArray(classes), context, toList(fileObjects));
-    }
-
-    static private String[] toArray(Iterable<String> iter) {
-        ListBuffer<String> result = new ListBuffer<>();
-        if (iter != null)
-            for (String s : iter)
-                result.append(s);
-        return result.toArray(new String[result.length()]);
-    }
-
-    static private List<JavaFileObject> toList(Iterable<? extends JavaFileObject> fileObjects) {
-        if (fileObjects == null)
-            return List.nil();
-        ListBuffer<JavaFileObject> result = new ListBuffer<>();
-        for (JavaFileObject fo : fileObjects)
-            result.append(fo);
-        return result.toList();
-    }
-
-    public Main.Result doCall() {
-        if (!used.getAndSet(true)) {
-            initContext();
-            notYetEntered = new HashMap<>();
-            compilerMain.setAPIMode(true);
-            compiler = JavaCompiler.instance(context);
-            compiler.keepComments = true;
-            compiler.genEndPos = true;
-            result = compilerMain.compile(args, classNames, context, fileObjects, processors);
-            cleanup();
-            return result;
-        } else {
-            throw new IllegalStateException("multiple calls to method 'call'");
-        }
-    }
-
+    @Override // @DefinedBy(COMPILER_API)
     public Boolean call() {
         return doCall().isOK();
     }
 
+    /* Internal version of call exposing Main.Result. */
+    public Main.Result doCall() {
+        try {
+            return handleExceptions(new Callable<Main.Result>() {
+                @Override
+                public Main.Result call() throws Exception {
+                    prepareCompiler(false);
+                    compiler.compile(args.getFileObjects(), args.getClassNames(), processors);
+                    return (compiler.errorCount() > 0) ? Main.Result.ERROR : Main.Result.OK; // FIXME?
+                }
+            }, Main.Result.SYSERR, Main.Result.ABNORMAL);
+        } finally {
+            try {
+                cleanup();
+            } catch (ClientCodeException e) {
+                throw new RuntimeException(e.getCause());
+            }
+        }
+    }
+
+    @Override // @DefinedBy(COMPILER_API)
     public void setProcessors(Iterable<? extends Processor> processors) {
         processors.getClass(); // null check
         // not mt-safe
@@ -149,46 +111,79 @@
         this.processors = processors;
     }
 
+    @Override // @DefinedBy(COMPILER_API)
     public void setLocale(Locale locale) {
         if (used.get())
             throw new IllegalStateException();
         this.locale = locale;
     }
 
-    private void prepareCompiler() throws IOException {
+    private <T> T handleExceptions(Callable<T> c, T sysErrorResult, T abnormalErrorResult) {
+        try {
+            return c.call();
+        } catch (FatalError ex) {
+            Log log = Log.instance(context);
+            Options options = Options.instance(context);
+            log.printRawLines(ex.getMessage());
+            if (ex.getCause() != null && options.isSet("dev")) {
+                ex.getCause().printStackTrace(log.getWriter(WriterKind.NOTICE));
+            }
+            return sysErrorResult;
+        } catch (AnnotationProcessingError | ClientCodeException e) {
+            // AnnotationProcessingError is thrown from JavacProcessingEnvironment,
+            // to forward errors thrown from an annotation processor
+            // ClientCodeException is thrown from ClientCodeWrapper,
+            // to forward errors thrown from user-supplied code for Compiler API
+            // as specified by javax.tools.JavaCompiler#getTask
+            // and javax.tools.JavaCompiler.CompilationTask#call
+            throw new RuntimeException(e.getCause());
+        } catch (PropagatedException e) {
+            throw e.getCause();
+        } catch (IllegalStateException e) {
+            throw e;
+        } catch (Exception | Error ex) {
+            // Nasty.  If we've already reported an error, compensate
+            // for buggy compiler error recovery by swallowing thrown
+            // exceptions.
+            if (compiler == null || compiler.errorCount() == 0
+                    || Options.instance(context).isSet("dev")) {
+                Log log = Log.instance(context);
+                log.printLines(PrefixKind.JAVAC, "msg.bug", JavaCompiler.version());
+                ex.printStackTrace(log.getWriter(WriterKind.NOTICE));
+            }
+            return abnormalErrorResult;
+        }
+    }
+
+    private void prepareCompiler(boolean forParse) {
         if (used.getAndSet(true)) {
             if (compiler == null)
-                throw new IllegalStateException();
+                throw new PropagatedException(new IllegalStateException());
         } else {
-            initContext();
-            compilerMain.log = Log.instance(context);
-            compilerMain.setOptions(Options.instance(context));
-            compilerMain.filenames = new LinkedHashSet<>();
-            compilerMain.deferredFileManagerOptions = new LinkedHashMap<>();
-            // The following line is conceptually wrong. It should not refer to args
-            // which may include inappropriate file manager options.
-            // (Ideally, args should not even be passed into JavacTaskImpl at all.)
-            // The "no filenames in args" check should have been handled by the use of
-            // the GrumpyHelper in JavacTool.getTask, but processArgs also has some
-            // additional checking, which should be factored out and called separately.
-            // If we fix this, then filenames and deferredFileManagerOptions in Main
-            // can revert to being protected or private, not public.
-            Collection<File> filenames = compilerMain.processArgs(CommandLine.parse(args), classNames);
-            if (filenames != null && !filenames.isEmpty())
-                throw new IllegalArgumentException("Malformed arguments " + toString(filenames, " "));
+            args.validate();
+
+            //initialize compiler's default locale
+            context.put(Locale.class, locale);
+
+            // hack
+            JavacMessages messages = context.get(JavacMessages.messagesKey);
+            if (messages != null && !messages.getCurrentLocale().equals(locale))
+                messages.setCurrentLocale(locale);
+
+            initPlugins(args.getPluginOpts());
+            initDocLint(args.getDocLintOpts());
+
+            // init JavaCompiler and queues
             compiler = JavaCompiler.instance(context);
             compiler.keepComments = true;
             compiler.genEndPos = true;
-            // NOTE: this value will be updated after annotation processing
-            compiler.initProcessAnnotations(processors);
             notYetEntered = new HashMap<>();
-            for (JavaFileObject file: fileObjects)
-                notYetEntered.put(file, null);
-            genList = new ListBuffer<>();
-            // endContext will be called when all classes have been generated
-            // TODO: should handle the case after each phase if errors have occurred
-            args = null;
-            classNames = null;
+            if (forParse) {
+                compiler.initProcessAnnotations(processors);
+                for (JavaFileObject file: args.getFileObjects())
+                    notYetEntered.put(file, null);
+                genList = new ListBuffer<>();
+            }
         }
     }
 
@@ -203,47 +198,28 @@
         return sb.toString();
     }
 
-    private void initContext() {
-        context.put(JavacTask.class, this);
-        //initialize compiler's default locale
-        context.put(Locale.class, locale);
-    }
-
     void cleanup() {
         if (compiler != null)
             compiler.close();
         compiler = null;
-        compilerMain = null;
-        args = null;
-        classNames = null;
         context = null;
-        fileObjects = null;
         notYetEntered = null;
     }
 
-    /**
-     * Construct a JavaFileObject from the given file.
-     *
-     * <p><b>TODO: this method is useless here</b></p>
-     *
-     * @param file a file
-     * @return a JavaFileObject from the standard file manager.
-     */
-    public JavaFileObject asJavaFileObject(File file) {
-        JavacFileManager fm = (JavacFileManager)context.get(JavaFileManager.class);
-        return fm.getRegularFile(file);
+    @Override // @DefinedBy(TREE_API)
+    public Iterable<? extends CompilationUnitTree> parse() {
+        return handleExceptions(new Callable<Iterable<? extends CompilationUnitTree>>() {
+            @Override
+            public Iterable<? extends CompilationUnitTree> call() {
+                return parseInternal();
+            }
+        }, List.<CompilationUnitTree>nil(), List.<CompilationUnitTree>nil());
     }
 
-    /**
-     * Parse the specified files returning a list of abstract syntax trees.
-     *
-     * @throws java.io.IOException TODO
-     * @return a list of abstract syntax trees
-     */
-    public Iterable<? extends CompilationUnitTree> parse() throws IOException {
+    private Iterable<? extends CompilationUnitTree> parseInternal() {
         try {
-            prepareCompiler();
-            List<JCCompilationUnit> units = compiler.parseFiles(fileObjects);
+            prepareCompiler(true);
+            List<JCCompilationUnit> units = compiler.parseFiles(args.getFileObjects());
             for (JCCompilationUnit unit: units) {
                 JavaFileObject file = unit.getSourceFile();
                 if (notYetEntered.containsKey(file))
@@ -263,11 +239,10 @@
     /**
      * Translate all the abstract syntax trees to elements.
      *
-     * @throws IOException TODO
      * @return a list of elements corresponding to the top level
      * classes in the abstract syntax trees
      */
-    public Iterable<? extends TypeElement> enter() throws IOException {
+    public Iterable<? extends TypeElement> enter() {
         return enter(null);
     }
 
@@ -275,17 +250,15 @@
      * Translate the given abstract syntax trees to elements.
      *
      * @param trees a list of abstract syntax trees.
-     * @throws java.io.IOException TODO
      * @return a list of elements corresponding to the top level
      * classes in the abstract syntax trees
      */
     public Iterable<? extends TypeElement> enter(Iterable<? extends CompilationUnitTree> trees)
-        throws IOException
     {
         if (trees == null && notYetEntered != null && notYetEntered.isEmpty())
             return List.nil();
 
-        prepareCompiler();
+        prepareCompiler(true);
 
         ListBuffer<JCCompilationUnit> roots = null;
 
@@ -296,8 +269,8 @@
             // list to be entered.
             if (notYetEntered.size() > 0) {
                 if (!parsed)
-                    parse(); // TODO would be nice to specify files needed to be parsed
-                for (JavaFileObject file: fileObjects) {
+                    parseInternal(); // TODO would be nice to specify files needed to be parsed
+                for (JavaFileObject file: args.getFileObjects()) {
                     JCCompilationUnit unit = notYetEntered.remove(file);
                     if (unit != null) {
                         if (roots == null)
@@ -347,13 +320,14 @@
         }
     }
 
-    /**
-     * Complete all analysis.
-     * @throws IOException TODO
-     */
-    @Override
-    public Iterable<? extends Element> analyze() throws IOException {
-        return analyze(null);
+    @Override // @DefinedBy(TREE_API)
+    public Iterable<? extends Element> analyze() {
+        return handleExceptions(new Callable<Iterable<? extends Element>>() {
+            @Override
+            public Iterable<? extends Element> call() {
+                return analyze(null);
+            }
+        }, List.<Element>nil(), List.<Element>nil());
     }
 
     /**
@@ -363,11 +337,12 @@
      * If null is specified, all outstanding classes will be analyzed.
      *
      * @param classes a list of class elements
+     * @return the elements that were analyzed
      */
     // This implementation requires that we open up privileges on JavaCompiler.
     // An alternative implementation would be to move this code to JavaCompiler and
     // wrap it here
-    public Iterable<? extends Element> analyze(Iterable<? extends TypeElement> classes) throws IOException {
+    public Iterable<? extends Element> analyze(Iterable<? extends TypeElement> classes) {
         enter(null);  // ensure all classes have been entered
 
         final ListBuffer<Element> results = new ListBuffer<>();
@@ -376,6 +351,7 @@
                 handleFlowResults(compiler.flow(compiler.attribute(compiler.todo)), results);
             } else {
                 Filter f = new Filter() {
+                    @Override
                     public void process(Env<AttrContext> env) {
                         handleFlowResults(compiler.flow(compiler.attribute(env)), results);
                     }
@@ -406,14 +382,14 @@
             genList.addAll(queue);
         }
 
-
-    /**
-     * Generate code.
-     * @throws IOException TODO
-     */
-    @Override
-    public Iterable<? extends JavaFileObject> generate() throws IOException {
-        return generate(null);
+    @Override // @DefinedBy(TREE_API)
+    public Iterable<? extends JavaFileObject> generate() {
+        return handleExceptions(new Callable<Iterable<? extends JavaFileObject>>() {
+            @Override
+            public Iterable<? extends JavaFileObject> call() {
+                return generate(null);
+            }
+        }, List.<JavaFileObject>nil(), List.<JavaFileObject>nil());
     }
 
     /**
@@ -424,8 +400,9 @@
      * If null is specified, code will be generated for all outstanding classes.
      *
      * @param classes a list of class elements
+     * @return the files that were generated
      */
-    public Iterable<? extends JavaFileObject> generate(Iterable<? extends TypeElement> classes) throws IOException {
+    public Iterable<? extends JavaFileObject> generate(Iterable<? extends TypeElement> classes) {
         final ListBuffer<JavaFileObject> results = new ListBuffer<>();
         try {
             analyze(null);  // ensure all classes have been parsed, entered, and analyzed
@@ -436,6 +413,7 @@
             }
             else {
                 Filter f = new Filter() {
+                        @Override
                         public void process(Env<AttrContext> env) {
                             compiler.generate(compiler.desugar(ListBuffer.of(env)), results);
                         }
@@ -454,26 +432,6 @@
         return results;
     }
 
-    public TypeMirror getTypeMirror(Iterable<? extends Tree> path) {
-        // TODO: Should complete attribution if necessary
-        Tree last = null;
-        for (Tree node : path)
-            last = node;
-        return ((JCTree)last).type;
-    }
-
-    public JavacElements getElements() {
-        if (context == null)
-            throw new IllegalStateException();
-        return JavacElements.instance(context);
-    }
-
-    public JavacTypes getTypes() {
-        if (context == null)
-            throw new IllegalStateException();
-        return JavacTypes.instance(context);
-    }
-
     public Iterable<? extends Tree> pathFor(CompilationUnitTree unit, Tree node) {
         return TreeInfo.pathFor((JCTree) node, (JCTree.JCCompilationUnit) unit).reverse();
     }
@@ -503,6 +461,10 @@
     /**
      * For internal use only.  This method will be
      * removed without warning.
+     * @param expr the type expression to be analyzed
+     * @param scope the scope in which to analyze the type expression
+     * @return the type
+     * @throws IllegalArgumentException if the type expression of null or empty
      */
     public Type parseType(String expr, TypeElement scope) {
         if (expr == null || expr.equals(""))
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTool.java	Fri Aug 22 12:25:01 2014 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTool.java	Fri Aug 22 16:28:16 2014 -0700
@@ -33,23 +33,20 @@
 import java.nio.charset.Charset;
 import java.util.Collections;
 import java.util.EnumSet;
-import java.util.Iterator;
 import java.util.Locale;
 import java.util.Set;
+
 import javax.lang.model.SourceVersion;
 import javax.tools.*;
 
 import com.sun.source.util.JavacTask;
 import com.sun.tools.javac.file.JavacFileManager;
-import com.sun.tools.javac.main.Main;
+import com.sun.tools.javac.main.Arguments;
 import com.sun.tools.javac.main.Option;
-import com.sun.tools.javac.main.OptionHelper;
-import com.sun.tools.javac.main.OptionHelper.GrumpyHelper;
 import com.sun.tools.javac.util.ClientCodeException;
 import com.sun.tools.javac.util.Context;
 import com.sun.tools.javac.util.Log;
-import com.sun.tools.javac.util.Log.PrefixKind;
-import com.sun.tools.javac.util.Options;
+import com.sun.tools.javac.util.PropagatedException;
 
 /**
  * TODO: describe com.sun.tools.javac.api.Tool
@@ -81,6 +78,7 @@
         return new JavacTool();
     }
 
+    @Override // @DefinedBy(COMPILER_API)
     public JavacFileManager getStandardFileManager(
         DiagnosticListener<? super JavaFileObject> diagnosticListener,
         Locale locale,
@@ -96,7 +94,7 @@
         return new JavacFileManager(context, true, charset);
     }
 
-    @Override
+    @Override // @DefinedBy(COMPILER_API)
     public JavacTask getTask(Writer out,
                              JavaFileManager fileManager,
                              DiagnosticListener<? super JavaFileObject> diagnosticListener,
@@ -109,6 +107,7 @@
                 context);
     }
 
+    /* Internal version of getTask, allowing context to be provided. */
     public JavacTask getTask(Writer out,
                              JavaFileManager fileManager,
                              DiagnosticListener<? super JavaFileObject> diagnosticListener,
@@ -120,14 +119,17 @@
         try {
             ClientCodeWrapper ccw = ClientCodeWrapper.instance(context);
 
-            if (options != null)
+            if (options != null) {
                 for (String option : options)
                     option.getClass(); // null check
+            }
+
             if (classes != null) {
                 for (String cls : classes)
                     if (!SourceVersion.isName(cls)) // implicit null check
                         throw new IllegalArgumentException("Not a valid class name: " + cls);
             }
+
             if (compilationUnits != null) {
                 compilationUnits = ccw.wrapJavaFileObjects(compilationUnits); // implicit null check
                 for (JavaFileObject cu : compilationUnits) {
@@ -153,82 +155,17 @@
 
             context.put(JavaFileManager.class, fileManager);
 
-            processOptions(context, fileManager, options);
-            Main compiler = new Main("javacTask", context.get(Log.outKey));
-            return new JavacTaskImpl(compiler, options, context, classes, compilationUnits);
+            Arguments args = Arguments.instance(context);
+            args.init("javac", options, classes, compilationUnits);
+            return new JavacTaskImpl(context);
+        } catch (PropagatedException ex) {
+            throw ex.getCause();
         } catch (ClientCodeException ex) {
             throw new RuntimeException(ex.getCause());
         }
     }
 
-    private void processOptions(Context context,
-                                       JavaFileManager fileManager,
-                                       Iterable<String> options)
-    {
-        if (options == null)
-            return;
-
-        final Options optionTable = Options.instance(context);
-        Log log = Log.instance(context);
-
-        Option[] recognizedOptions =
-                Option.getJavacToolOptions().toArray(new Option[0]);
-        OptionHelper optionHelper = new GrumpyHelper(log) {
-            @Override
-            public String get(Option option) {
-                return optionTable.get(option.getText());
-            }
-
-            @Override
-            public void put(String name, String value) {
-                optionTable.put(name, value);
-            }
-
-            @Override
-            public void remove(String name) {
-                optionTable.remove(name);
-            }
-        };
-
-        Iterator<String> flags = options.iterator();
-        while (flags.hasNext()) {
-            String flag = flags.next();
-            int j;
-            for (j=0; j<recognizedOptions.length; j++)
-                if (recognizedOptions[j].matches(flag))
-                    break;
-
-            if (j == recognizedOptions.length) {
-                if (fileManager.handleOption(flag, flags)) {
-                    continue;
-                } else {
-                    String msg = log.localize(PrefixKind.JAVAC, "err.invalid.flag", flag);
-                    throw new IllegalArgumentException(msg);
-                }
-            }
-
-            Option option = recognizedOptions[j];
-            if (option.hasArg()) {
-                if (!flags.hasNext()) {
-                    String msg = log.localize(PrefixKind.JAVAC, "err.req.arg", flag);
-                    throw new IllegalArgumentException(msg);
-                }
-                String operand = flags.next();
-                if (option.process(optionHelper, flag, operand))
-                    // should not happen as the GrumpyHelper will throw exceptions
-                    // in case of errors
-                    throw new IllegalArgumentException(flag + " " + operand);
-            } else {
-                if (option.process(optionHelper, flag))
-                    // should not happen as the GrumpyHelper will throw exceptions
-                    // in case of errors
-                    throw new IllegalArgumentException(flag);
-            }
-        }
-
-        optionTable.notifyListeners();
-    }
-
+    @Override // @DefinedBy(COMPILER_API)
     public int run(InputStream in, OutputStream out, OutputStream err, String... arguments) {
         if (err == null)
             err = System.err;
@@ -237,11 +174,13 @@
         return com.sun.tools.javac.Main.compile(arguments, new PrintWriter(err, true));
     }
 
+    @Override // @DefinedBy(COMPILER_API)
     public Set<SourceVersion> getSourceVersions() {
         return Collections.unmodifiableSet(EnumSet.range(SourceVersion.RELEASE_3,
                                                          SourceVersion.latest()));
     }
 
+    @Override // @DefinedBy(COMPILER_API)
     public int isSupportedOption(String option) {
         Set<Option> recognizedOptions = Option.getJavacToolOptions();
         for (Option o : recognizedOptions) {
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java	Fri Aug 22 12:25:01 2014 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java	Fri Aug 22 16:28:16 2014 -0700
@@ -735,11 +735,7 @@
         // if we're being invoked from JSR 199 or JSR 269, then the classes
         // will already have been entered.
         if (javacTaskImpl != null) {
-            try {
-                javacTaskImpl.enter(null);
-            } catch (IOException e) {
-                throw new Error("unexpected error while entering symbols: " + e);
-            }
+            javacTaskImpl.enter(null);
         }
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Arguments.java	Fri Aug 22 16:28:16 2014 -0700
@@ -0,0 +1,573 @@
+/*
+ * Copyright (c) 1999, 2014, 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.main;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.tools.JavaFileManager;
+import javax.tools.JavaFileObject;
+
+import com.sun.tools.doclint.DocLint;
+import com.sun.tools.javac.code.Lint.LintCategory;
+import com.sun.tools.javac.code.Source;
+import com.sun.tools.javac.file.JavacFileManager;
+import com.sun.tools.javac.jvm.Profile;
+import com.sun.tools.javac.jvm.Target;
+import com.sun.tools.javac.main.OptionHelper.GrumpyHelper;
+import com.sun.tools.javac.util.BaseFileManager;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.ListBuffer;
+import com.sun.tools.javac.util.Log;
+import com.sun.tools.javac.util.Log.PrefixKind;
+import com.sun.tools.javac.util.Options;
+import com.sun.tools.javac.util.PropagatedException;
+
+/**
+ * Shared option and argument handling for command line and API usage of javac.
+ */
+public class Arguments {
+
+    /**
+     * The context key for the arguments.
+     */
+    protected static final Context.Key<Arguments> argsKey = new Context.Key<>();
+
+    private String ownName;
+    private Set<String> classNames;
+    private Set<File> files;
+    private Map<Option, String> deferredFileManagerOptions;
+    private Set<JavaFileObject> fileObjects;
+    private final Options options;
+
+    private JavaFileManager fileManager;
+    private final Log log;
+    private final Context context;
+
+    private enum ErrorMode { ILLEGAL_ARGUMENT, ILLEGAL_STATE, LOG };
+    private ErrorMode errorMode;
+    private boolean errors;
+
+    /**
+     * Gets the Arguments instance for this context.
+     *
+     * @param context the content
+     * @return the Arguments instance for this context.
+     */
+    public static Arguments instance(Context context) {
+        Arguments instance = context.get(argsKey);
+        if (instance == null) {
+            instance = new Arguments(context);
+        }
+        return instance;
+    }
+
+    protected Arguments(Context context) {
+        context.put(argsKey, this);
+        options = Options.instance(context);
+        log = Log.instance(context);
+        this.context = context;
+
+        // Ideally, we could init this here and update/configure it as
+        // needed, but right now, initializing a file manager triggers
+        // initialization of other items in the context, such as Lint
+        // and FSInfo, which should not be initialized until after
+        // processArgs
+        //        fileManager = context.get(JavaFileManager.class);
+    }
+
+    private final OptionHelper cmdLineHelper = new OptionHelper() {
+        @Override
+        public String get(Option option) {
+            return options.get(option);
+        }
+
+        @Override
+        public void put(String name, String value) {
+            options.put(name, value);
+        }
+
+        @Override
+        public void remove(String name) {
+            options.remove(name);
+        }
+
+        @Override
+        public boolean handleFileManagerOption(Option option, String value) {
+            options.put(option.getText(), value);
+            deferredFileManagerOptions.put(option, value);
+            return true;
+        }
+
+        @Override
+        public Log getLog() {
+            return log;
+        }
+
+        @Override
+        public String getOwnName() {
+            return ownName;
+        }
+
+        @Override
+        public void error(String key, Object... args) {
+            Arguments.this.error(key, args);
+        }
+
+        @Override
+        public void addFile(File f) {
+            files.add(f);
+        }
+
+        @Override
+        public void addClassName(String s) {
+            classNames.add(s);
+        }
+
+    };
+
+    /**
+     * Initializes this Args instance with a set of command line args.
+     * The args will be processed in conjunction with the full set of
+     * command line options, including -help, -version etc.
+     * The args may also contain class names and filenames.
+     * Any errors during this call, and later during validate, will be reported
+     * to the log.
+     * @param ownName the name of this tool; used to prefix messages
+     * @param args the args to be processed
+     */
+    public void init(String ownName, String... args) {
+        this.ownName = ownName;
+        errorMode = ErrorMode.LOG;
+        files = new LinkedHashSet<>();
+        deferredFileManagerOptions = new LinkedHashMap<>();
+        fileObjects = null;
+        classNames = new LinkedHashSet<>();
+        processArgs(List.from(args), Option.getJavaCompilerOptions(), cmdLineHelper, true, false);
+    }
+
+    private final OptionHelper apiHelper = new GrumpyHelper(null) {
+        @Override
+        public String get(Option option) {
+            return options.get(option.getText());
+        }
+
+        @Override
+        public void put(String name, String value) {
+            options.put(name, value);
+        }
+
+        @Override
+        public void remove(String name) {
+            options.remove(name);
+        }
+
+        @Override
+        public void error(String key, Object... args) {
+            Arguments.this.error(key, args);
+        }
+
+        @Override
+        public Log getLog() {
+            return Arguments.this.log;
+        }
+    };
+
+    /**
+     * Initializes this Args instance with the parameters for a JavacTask.
+     * The options will be processed in conjunction with the restricted set
+     * of tool options, which does not include -help, -version, etc,
+     * nor does it include classes and filenames, which should be specified
+     * separately.
+     * File manager options are handled directly by the file manager.
+     * Any errors found while processing individual args will be reported
+     * via IllegalArgumentException.
+     * Any subsequent errors during validate will be reported via IllegalStateException.
+     * @param ownName the name of this tool; used to prefix messages
+     * @param options the options to be processed
+     * @param classNames the classes to be subject to annotation processing
+     * @param files the files to be compiled
+     */
+    public void init(String ownName,
+            Iterable<String> options,
+            Iterable<String> classNames,
+            Iterable<? extends JavaFileObject> files) {
+        this.ownName = ownName;
+        this.classNames = toSet(classNames);
+        this.fileObjects = toSet(files);
+        this.files = null;
+        errorMode = ErrorMode.ILLEGAL_ARGUMENT;
+        if (options != null) {
+            processArgs(toList(options), Option.getJavacToolOptions(), apiHelper, false, true);
+        }
+        errorMode = ErrorMode.ILLEGAL_STATE;
+    }
+
+    /**
+     * Gets the files to be compiled.
+     * @return the files to be compiled
+     */
+    public Set<JavaFileObject> getFileObjects() {
+        if (fileObjects == null) {
+            if (files == null) {
+                fileObjects = Collections.emptySet();
+            } else {
+                fileObjects = new LinkedHashSet<>();
+                JavacFileManager jfm = (JavacFileManager) getFileManager();
+                for (JavaFileObject fo: jfm.getJavaFileObjectsFromFiles(files))
+                    fileObjects.add(fo);
+            }
+        }
+        return fileObjects;
+    }
+
+    /**
+     * Gets the classes to be subject to annotation processing.
+     * @return the classes to be subject to annotation processing
+     */
+    public Set<String> getClassNames() {
+        return classNames;
+    }
+
+    /**
+     * Processes strings containing options and operands.
+     * @param args the strings to be processed
+     * @param allowableOpts the set of option declarations that are applicable
+     * @param helper a help for use by Option.process
+     * @param allowOperands whether or not to check for files and classes
+     * @param checkFileManager whether or not to check if the file manager can handle
+     *      options which are not recognized by any of allowableOpts
+     * @return true if all the strings were successfully processed; false otherwise
+     * @throws IllegalArgumentException if a problem occurs and errorMode is set to
+     *      ILLEGAL_ARGUMENT
+     */
+    private boolean processArgs(Iterable<String> args,
+            Set<Option> allowableOpts, OptionHelper helper,
+            boolean allowOperands, boolean checkFileManager) {
+        JavaFileManager fm = checkFileManager ? getFileManager() : null;
+        Iterator<String> argIter = args.iterator();
+        while (argIter.hasNext()) {
+            String arg = argIter.next();
+            if (arg.isEmpty()) {
+                error("err.invalid.flag", arg);
+                return false;
+            }
+
+            Option option = null;
+            if (arg.startsWith("-")) {
+                for (Option o : allowableOpts) {
+                    if (o.matches(arg)) {
+                        option = o;
+                        break;
+                    }
+                }
+            } else if (allowOperands && Option.SOURCEFILE.matches(arg)) {
+                option = Option.SOURCEFILE;
+            }
+
+            if (option == null) {
+                if (fm != null && fm.handleOption(arg, argIter)) {
+                    continue;
+                }
+                error("err.invalid.flag", arg);
+                return false;
+            }
+
+            if (option.hasArg()) {
+                if (!argIter.hasNext()) {
+                    error("err.req.arg", arg);
+                    return false;
+                }
+                String operand = argIter.next();
+                if (option.process(helper, arg, operand)) {
+                    return false;
+                }
+            } else {
+                if (option.process(helper, arg)) {
+                    return false;
+                }
+            }
+
+        }
+
+        options.notifyListeners();
+
+        return true;
+    }
+
+    /**
+     * Validates the overall consistency of the options and operands
+     * processed by processOptions.
+     * @return true if all args are successfully validating; false otherwise.
+     * @throws IllegalStateException if a problem is found and errorMode is set to
+     *      ILLEGAL_STATE
+     */
+    public boolean validate() {
+        if (isEmpty()) {
+            // It is allowed to compile nothing if just asking for help or version info.
+            // But also note that none of these options are supported in API mode.
+            if (options.isSet(Option.HELP)
+                || options.isSet(Option.X)
+                || options.isSet(Option.VERSION)
+                || options.isSet(Option.FULLVERSION))
+                return true;
+
+            if (JavaCompiler.explicitAnnotationProcessingRequested(options)) {
+                error("err.no.source.files.classes");
+            } else {
+                error("err.no.source.files");
+            }
+            return false;
+        }
+
+        if (!checkDirectory(Option.D)) {
+            return false;
+        }
+        if (!checkDirectory(Option.S)) {
+            return false;
+        }
+
+        String sourceString = options.get(Option.SOURCE);
+        Source source = (sourceString != null)
+                ? Source.lookup(sourceString)
+                : Source.DEFAULT;
+        String targetString = options.get(Option.TARGET);
+        Target target = (targetString != null)
+                ? Target.lookup(targetString)
+                : Target.DEFAULT;
+
+        // We don't check source/target consistency for CLDC, as J2ME
+        // profiles are not aligned with J2SE targets; moreover, a
+        // single CLDC target may have many profiles.  In addition,
+        // this is needed for the continued functioning of the JSR14
+        // prototype.
+        if (Character.isDigit(target.name.charAt(0))) {
+            if (target.compareTo(source.requiredTarget()) < 0) {
+                if (targetString != null) {
+                    if (sourceString == null) {
+                        error("warn.target.default.source.conflict",
+                                targetString,
+                                source.requiredTarget().name);
+                    } else {
+                        error("warn.source.target.conflict",
+                                sourceString,
+                                source.requiredTarget().name);
+                    }
+                    return false;
+                } else {
+                    target = source.requiredTarget();
+                    options.put("-target", target.name);
+                }
+            }
+        }
+
+        String profileString = options.get(Option.PROFILE);
+        if (profileString != null) {
+            Profile profile = Profile.lookup(profileString);
+            if (!profile.isValid(target)) {
+                error("warn.profile.target.conflict", profileString, target.name);
+            }
+
+            // This check is only effective in command line mode,
+            // where the file manager options are added to options
+            if (options.get(Option.BOOTCLASSPATH) != null) {
+                error("err.profile.bootclasspath.conflict");
+            }
+        }
+
+        boolean lintOptions = options.isUnset(Option.XLINT_CUSTOM, "-" + LintCategory.OPTIONS.option);
+
+        if (lintOptions && source.compareTo(Source.DEFAULT) < 0) {
+            JavaFileManager fm = getFileManager();
+            if (fm instanceof BaseFileManager) {
+                if (((BaseFileManager) fm).isDefaultBootClassPath())
+                    log.warning(LintCategory.OPTIONS, "source.no.bootclasspath", source.name);
+            }
+        }
+
+        boolean obsoleteOptionFound = false;
+
+        if (source.compareTo(Source.MIN) < 0) {
+            log.error("option.removed.source", source.name, Source.MIN.name);
+        } else if (source == Source.MIN && lintOptions) {
+            log.warning(LintCategory.OPTIONS, "option.obsolete.source", source.name);
+            obsoleteOptionFound = true;
+        }
+
+        if (target.compareTo(Target.MIN) < 0) {
+            log.error("option.removed.target", target.name, Target.MIN.name);
+        } else if (target == Target.MIN && lintOptions) {
+            log.warning(LintCategory.OPTIONS, "option.obsolete.target", target.name);
+            obsoleteOptionFound = true;
+        }
+
+        if (obsoleteOptionFound)
+            log.warning(LintCategory.OPTIONS, "option.obsolete.suppression");
+
+        return !errors;
+    }
+
+    /**
+     * Returns true if there are no files or classes specified for use.
+     * @return true if there are no files or classes specified for use
+     */
+    public boolean isEmpty() {
+        return ((files == null) || files.isEmpty())
+                && ((fileObjects == null) || fileObjects.isEmpty())
+                && classNames.isEmpty();
+    }
+
+    /**
+     * Gets the file manager options which may have been deferred
+     * during processArgs.
+     * @return the deferred file manager options
+     */
+    public Map<Option, String> getDeferredFileManagerOptions() {
+        return deferredFileManagerOptions;
+    }
+
+    /**
+     * Gets any options specifying plugins to be run.
+     * @return options for plugins
+     */
+    public Set<List<String>> getPluginOpts() {
+        String plugins = options.get(Option.PLUGIN);
+        if (plugins == null)
+            return Collections.emptySet();
+
+        Set<List<String>> pluginOpts = new LinkedHashSet<>();
+        for (String plugin: plugins.split("\\x00")) {
+            pluginOpts.add(List.from(plugin.split("\\s+")));
+        }
+        return Collections.unmodifiableSet(pluginOpts);
+    }
+
+    /**
+     * Gets any options specifying how doclint should be run.
+     * An empty list is returned if no doclint options are specified
+     * or if the only doclint option is -Xdoclint:none.
+     * @return options for doclint
+     */
+    public List<String> getDocLintOpts() {
+        String xdoclint = options.get(Option.XDOCLINT);
+        String xdoclintCustom = options.get(Option.XDOCLINT_CUSTOM);
+        if (xdoclint == null && xdoclintCustom == null)
+            return List.nil();
+
+        Set<String> doclintOpts = new LinkedHashSet<>();
+        if (xdoclint != null)
+            doclintOpts.add(DocLint.XMSGS_OPTION);
+        if (xdoclintCustom != null) {
+            for (String s: xdoclintCustom.split("\\s+")) {
+                if (s.isEmpty())
+                    continue;
+                doclintOpts.add(s.replace(Option.XDOCLINT_CUSTOM.text, DocLint.XMSGS_CUSTOM_PREFIX));
+            }
+        }
+
+        if (doclintOpts.equals(Collections.singleton(DocLint.XMSGS_CUSTOM_PREFIX + "none")))
+            return List.nil();
+
+        // standard doclet normally generates H1, H2,
+        // so for now, allow user comments to assume that
+        doclintOpts.add(DocLint.XIMPLICIT_HEADERS + "2");
+
+        return List.from(doclintOpts.toArray(new String[doclintOpts.size()]));
+    }
+
+    private boolean checkDirectory(Option option) {
+        String value = options.get(option);
+        if (value == null) {
+            return true;
+        }
+        File file = new File(value);
+        if (!file.exists()) {
+            error("err.dir.not.found", value);
+            return false;
+        }
+        if (!file.isDirectory()) {
+            error("err.file.not.directory", value);
+            return false;
+        }
+        return true;
+    }
+
+    void error(String key, Object... args) {
+        errors = true;
+        switch (errorMode) {
+            case ILLEGAL_ARGUMENT: {
+                String msg = log.localize(PrefixKind.JAVAC, key, args);
+                throw new PropagatedException(new IllegalArgumentException(msg));
+            }
+            case ILLEGAL_STATE: {
+                String msg = log.localize(PrefixKind.JAVAC, key, args);
+                throw new PropagatedException(new IllegalStateException(msg));
+            }
+            case LOG:
+                report(key, args);
+                log.printLines(PrefixKind.JAVAC, "msg.usage", ownName);
+        }
+    }
+
+    void warning(String key, Object... args) {
+        report(key, args);
+    }
+
+    private void report(String key, Object... args) {
+        log.printRawLines(ownName + ": " + log.localize(PrefixKind.JAVAC, key, args));
+    }
+
+    private JavaFileManager getFileManager() {
+        if (fileManager == null)
+            fileManager = context.get(JavaFileManager.class);
+        return fileManager;
+    }
+
+    <T> ListBuffer<T> toList(Iterable<? extends T> items) {
+        ListBuffer<T> list = new ListBuffer<>();
+        if (items != null) {
+            for (T item : items) {
+                list.add(item);
+            }
+        }
+        return list;
+    }
+
+    <T> Set<T> toSet(Iterable<? extends T> items) {
+        Set<T> set = new LinkedHashSet<>();
+        if (items != null) {
+            for (T item : items) {
+                set.add(item);
+            }
+        }
+        return set;
+    }
+}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Fri Aug 22 12:25:01 2014 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Fri Aug 22 16:28:16 2014 -0700
@@ -26,6 +26,7 @@
 package com.sun.tools.javac.main;
 
 import java.io.*;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
@@ -43,13 +44,13 @@
 import javax.tools.JavaFileObject;
 import javax.tools.StandardLocation;
 
-import static javax.tools.StandardLocation.CLASS_OUTPUT;
-
 import com.sun.source.util.TaskEvent;
 import com.sun.tools.javac.api.MultiTaskListener;
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.code.Lint.LintCategory;
-import com.sun.tools.javac.code.Symbol.*;
+import com.sun.tools.javac.code.Symbol.ClassSymbol;
+import com.sun.tools.javac.code.Symbol.CompletionFailure;
+import com.sun.tools.javac.code.Symbol.PackageSymbol;
 import com.sun.tools.javac.comp.*;
 import com.sun.tools.javac.comp.CompileStates.CompileState;
 import com.sun.tools.javac.file.JavacFileManager;
@@ -57,10 +58,18 @@
 import com.sun.tools.javac.parser.*;
 import com.sun.tools.javac.processing.*;
 import com.sun.tools.javac.tree.*;
-import com.sun.tools.javac.tree.JCTree.*;
+import com.sun.tools.javac.tree.JCTree.JCClassDecl;
+import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
+import com.sun.tools.javac.tree.JCTree.JCExpression;
+import com.sun.tools.javac.tree.JCTree.JCLambda;
+import com.sun.tools.javac.tree.JCTree.JCMemberReference;
+import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
+import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.Log.WriterKind;
 
+import static javax.tools.StandardLocation.CLASS_OUTPUT;
+
 import static com.sun.tools.javac.code.TypeTag.CLASS;
 import static com.sun.tools.javac.main.Option.*;
 import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag.*;
@@ -394,19 +403,6 @@
         processPcks   = options.isSet("process.packages");
         werror        = options.isSet(WERROR);
 
-        // Should this be with other option checking, in Main
-        if (source.compareTo(Source.DEFAULT) < 0) {
-            if (options.isUnset(XLINT_CUSTOM, "-" + LintCategory.OPTIONS.option)) {
-                if (fileManager instanceof BaseFileManager) {
-                    if (((BaseFileManager) fileManager).isDefaultBootClassPath())
-                        log.warning(LintCategory.OPTIONS, "source.no.bootclasspath", source.name);
-                }
-            }
-        }
-
-        // Should this be with other option checking, in Main
-        checkForObsoleteOptions(target);
-
         verboseCompilePolicy = options.isSet("verboseCompilePolicy");
 
         if (attrParseOnly)
@@ -436,33 +432,6 @@
             log.setDiagnosticFormatter(RichDiagnosticFormatter.instance(context));
     }
 
-    // Should this be with other option checking, in Main
-    private void checkForObsoleteOptions(Target target) {
-        // Unless lint checking on options is disabled, check for
-        // obsolete source and target options.
-        boolean obsoleteOptionFound = false;
-
-        boolean lintOptions =
-            options.isUnset(XLINT_CUSTOM, "-"+LintCategory.OPTIONS.option);
-
-        if (source.compareTo(Source.MIN) < 0) {
-            log.error("option.removed.source", source.name, Source.MIN.name);
-        } else if (source == Source.MIN && lintOptions) {
-            log.warning(LintCategory.OPTIONS, "option.obsolete.source", source.name);
-            obsoleteOptionFound = true;
-        }
-
-        if (target.compareTo(Target.MIN) < 0) {
-            log.error("option.removed.target", target.name, Target.MIN.name);
-        } else if (target == Target.MIN && lintOptions) {
-            log.warning(LintCategory.OPTIONS, "option.obsolete.target", target.name);
-            obsoleteOptionFound = true;
-        }
-
-        if (obsoleteOptionFound)
-            log.warning(LintCategory.OPTIONS, "option.obsolete.suppression");
-    }
-
     /* Switches:
      */
 
@@ -834,8 +803,8 @@
      * @param processors user provided annotation processors to bypass
      * discovery, {@code null} means that no processors were provided
      */
-    public void compile(List<JavaFileObject> sourceFileObjects,
-                        List<String> classnames,
+    public void compile(Collection<JavaFileObject> sourceFileObjects,
+                        Collection<String> classnames,
                         Iterable<? extends Processor> processors)
     {
         if (!taskListener.isEmpty()) {
@@ -1082,7 +1051,7 @@
     // and all deferredDiagnostics must have been handled: i.e. either reported
     // or determined to be transient, and therefore suppressed.
     public void processAnnotations(List<JCCompilationUnit> roots,
-                                   List<String> classnames) {
+                                   Collection<String> classnames) {
         if (shouldStop(CompileState.PROCESS)) {
             // Errors were encountered.
             // Unless all the errors are resolve errors, the errors were parse errors
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Main.java	Fri Aug 22 12:25:01 2014 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Main.java	Fri Aug 22 16:28:16 2014 -0700
@@ -25,40 +25,25 @@
 
 package com.sun.tools.javac.main;
 
-import java.io.File;
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.net.URL;
 import java.security.DigestInputStream;
 import java.security.MessageDigest;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.Map;
+import java.security.NoSuchAlgorithmException;
+
 import java.util.Set;
 
-import javax.annotation.processing.Processor;
 import javax.tools.JavaFileManager;
-import javax.tools.JavaFileObject;
 
-import com.sun.source.util.JavacTask;
-import com.sun.source.util.Plugin;
-import com.sun.tools.doclint.DocLint;
 import com.sun.tools.javac.api.BasicJavacTask;
-import com.sun.tools.javac.code.Source;
 import com.sun.tools.javac.file.CacheFSInfo;
 import com.sun.tools.javac.file.JavacFileManager;
-import com.sun.tools.javac.jvm.Profile;
-import com.sun.tools.javac.jvm.Target;
 import com.sun.tools.javac.processing.AnnotationProcessingError;
-import com.sun.tools.javac.processing.JavacProcessingEnvironment;
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.Log.PrefixKind;
 import com.sun.tools.javac.util.Log.WriterKind;
-import com.sun.tools.javac.util.ServiceLoader;
-
-import static com.sun.tools.javac.main.Option.*;
 
 /** This class provides a command line interface to the javac compiler.
  *
@@ -108,61 +93,9 @@
         public final int exitCode;
     }
 
-    private Option[] recognizedOptions =
-            Option.getJavaCompilerOptions().toArray(new Option[0]);
-
-    private OptionHelper optionHelper = new OptionHelper() {
-        @Override
-        public String get(Option option) {
-            return options.get(option);
-        }
-
-        @Override
-        public void put(String name, String value) {
-            options.put(name, value);
-        }
-
-        @Override
-        public boolean handleFileManagerOption(Option option, String value) {
-            options.put(option.getText(), value);
-            deferredFileManagerOptions.put(option, value);
-            return true;
-        }
-
-        @Override
-        public void remove(String name) {
-            options.remove(name);
-        }
-
-        @Override
-        public Log getLog() {
-            return log;
-        }
-
-        @Override
-        public String getOwnName() {
-            return ownName;
-        }
-
-        @Override
-        public void error(String key, Object... args) {
-            Main.this.error(key, args);
-        }
-
-        @Override
-        public void addFile(File f) {
-            filenames.add(f);
-        }
-
-        @Override
-        public void addClassName(String s) {
-            classnames.append(s);
-        }
-
-    };
-
     /**
      * Construct a compiler instance.
+     * @param name the name of this tool
      */
     public Main(String name) {
         this(name, new PrintWriter(System.err, true));
@@ -170,25 +103,14 @@
 
     /**
      * Construct a compiler instance.
+     * @param name the name of this tool
+     * @param out a stream to which to write messages
      */
     public Main(String name, PrintWriter out) {
         this.ownName = name;
         this.out = out;
     }
 
-    /** A table of all options that's passed to the JavaCompiler constructor.  */
-    private Options options = null;
-
-    /** The list of source files to process
-     */
-    public Set<File> filenames = null; // XXX should be protected or private
-
-    /** List of class files names passed on the command line
-     */
-    protected ListBuffer<String> classnames = null;
-
-    public Map<Option, String> deferredFileManagerOptions; // XXX should be protected or private
-
     /** Report a usage error.
      */
     void error(String key, Object... args) {
@@ -206,156 +128,11 @@
         log.printRawLines(ownName + ": " + log.localize(PrefixKind.JAVAC, key, args));
     }
 
-    public Option getOption(String flag) {
-        for (Option option : recognizedOptions) {
-            if (option.matches(flag))
-                return option;
-        }
-        return null;
-    }
 
-    public void setOptions(Options options) {
-        if (options == null)
-            throw new NullPointerException();
-        this.options = options;
-    }
-
-    public void setAPIMode(boolean apiMode) {
-        this.apiMode = apiMode;
-    }
-
-    /** Process command line arguments: store all command line options
-     *  in `options' table and return all source filenames.
-     *  @param flags    The array of command line arguments.
-     */
-    public Collection<File> processArgs(String[] flags) { // XXX sb protected
-        return processArgs(flags, null);
-    }
-
-    public Collection<File> processArgs(String[] flags, String[] classNames) { // XXX sb protected
-        int ac = 0;
-        while (ac < flags.length) {
-            String flag = flags[ac];
-            ac++;
-
-            Option option = null;
-
-            if (flag.length() > 0) {
-                // quick hack to speed up file processing:
-                // if the option does not begin with '-', there is no need to check
-                // most of the compiler options.
-                int firstOptionToCheck = flag.charAt(0) == '-' ? 0 : recognizedOptions.length-1;
-                for (int j=firstOptionToCheck; j<recognizedOptions.length; j++) {
-                    if (recognizedOptions[j].matches(flag)) {
-                        option = recognizedOptions[j];
-                        break;
-                    }
-                }
-            }
-
-            if (option == null) {
-                error("err.invalid.flag", flag);
-                return null;
-            }
-
-            if (option.hasArg()) {
-                if (ac == flags.length) {
-                    error("err.req.arg", flag);
-                    return null;
-                }
-                String operand = flags[ac];
-                ac++;
-                if (option.process(optionHelper, flag, operand))
-                    return null;
-            } else {
-                if (option.process(optionHelper, flag))
-                    return null;
-            }
-        }
-
-        if (options.get(PROFILE) != null && options.get(BOOTCLASSPATH) != null) {
-            error("err.profile.bootclasspath.conflict");
-            return null;
-        }
-
-        if (this.classnames != null && classNames != null) {
-            this.classnames.addAll(Arrays.asList(classNames));
-        }
-
-        if (!checkDirectory(D))
-            return null;
-        if (!checkDirectory(S))
-            return null;
-
-        String sourceString = options.get(SOURCE);
-        Source source = (sourceString != null)
-            ? Source.lookup(sourceString)
-            : Source.DEFAULT;
-        String targetString = options.get(TARGET);
-        Target target = (targetString != null)
-            ? Target.lookup(targetString)
-            : Target.DEFAULT;
-
-        if (Character.isDigit(target.name.charAt(0))) {
-            if (target.compareTo(source.requiredTarget()) < 0) {
-                if (targetString != null) {
-                    if (sourceString == null) {
-                        warning("warn.target.default.source.conflict",
-                                targetString,
-                                source.requiredTarget().name);
-                    } else {
-                        warning("warn.source.target.conflict",
-                                sourceString,
-                                source.requiredTarget().name);
-                    }
-                    return null;
-                } else {
-                    target = source.requiredTarget();
-                    options.put("-target", target.name);
-                }
-            }
-        }
-
-        String profileString = options.get(PROFILE);
-        if (profileString != null) {
-            Profile profile = Profile.lookup(profileString);
-            if (!profile.isValid(target)) {
-                warning("warn.profile.target.conflict", profileString, target.name);
-                return null;
-            }
-        }
-
-        // handle this here so it works even if no other options given
-        String showClass = options.get("showClass");
-        if (showClass != null) {
-            if (showClass.equals("showClass")) // no value given for option
-                showClass = "com.sun.tools.javac.Main";
-            showClass(showClass);
-        }
-
-        options.notifyListeners();
-
-        return filenames;
-    }
-    // where
-        private boolean checkDirectory(Option option) {
-            String value = options.get(option);
-            if (value == null)
-                return true;
-            File file = new File(value);
-            if (!file.exists()) {
-                error("err.dir.not.found", value);
-                return false;
-            }
-            if (!file.isDirectory()) {
-                error("err.file.not.directory", value);
-                return false;
-            }
-            return true;
-        }
-
-    /** Programmatic interface for main function.
-     * @param args    The command line parameters.
+    /**
+     * Programmatic interface for main function.
+     * @param args  the command line parameters
+     * @return the result of the compilation
      */
     public Result compile(String[] args) {
         Context context = new Context();
@@ -368,174 +145,108 @@
         return result;
     }
 
-    public Result compile(String[] args, Context context) {
-        return compile(args, context, List.<JavaFileObject>nil(), null);
-    }
-
-    /** Programmatic interface for main function.
-     * @param args    The command line parameters.
+    /**
+     * Internal version of compile, allowing context to be provided.
+     * Note that the context needs to have a file manager set up.
+     * @param argv  the command line parameters
+     * @param context the context
+     * @return the result of the compilation
      */
-    protected Result compile(String[] args,
-                       Context context,
-                       List<JavaFileObject> fileObjects,
-                       Iterable<? extends Processor> processors)
-    {
-        return compile(args,  null, context, fileObjects, processors);
-    }
-
-    public Result compile(String[] args,
-                          String[] classNames,
-                          Context context,
-                          List<JavaFileObject> fileObjects,
-                          Iterable<? extends Processor> processors)
-    {
+    public Result compile(String[] argv, Context context) {
         context.put(Log.outKey, out);
         log = Log.instance(context);
 
-        if (options == null)
-            options = Options.instance(context); // creates a new one
+        if (argv.length == 0) {
+            Option.HELP.process(new OptionHelper.GrumpyHelper(log) {
+                @Override
+                public String getOwnName() { return ownName; }
+            }, "-help");
+            return Result.CMDERR;
+        }
 
-        filenames = new LinkedHashSet<>();
-        classnames = new ListBuffer<>();
-        deferredFileManagerOptions = new LinkedHashMap<>();
-        JavaCompiler comp = null;
-        /*
-         * TODO: Logic below about what is an acceptable command line
-         * should be updated to take annotation processing semantics
-         * into account.
-         */
         try {
-            if (args.length == 0
-                    && (classNames == null || classNames.length == 0)
-                    && fileObjects.isEmpty()) {
-                Option.HELP.process(optionHelper, "-help");
-                return Result.CMDERR;
-            }
+            argv = CommandLine.parse(argv);
+        } catch (FileNotFoundException e) {
+            warning("err.file.not.found", e.getMessage());
+            return Result.SYSERR;
+        } catch (IOException ex) {
+            log.printLines(PrefixKind.JAVAC, "msg.io");
+            ex.printStackTrace(log.getWriter(WriterKind.NOTICE));
+            return Result.SYSERR;
+        }
 
-            Collection<File> files;
-            try {
-                files = processArgs(CommandLine.parse(args), classNames);
-                if (files == null) {
-                    // null signals an error in options, abort
-                    return Result.CMDERR;
-                } else if (files.isEmpty() && fileObjects.isEmpty() && classnames.isEmpty()) {
-                    // it is allowed to compile nothing if just asking for help or version info
-                    if (options.isSet(HELP)
-                        || options.isSet(X)
-                        || options.isSet(VERSION)
-                        || options.isSet(FULLVERSION))
-                        return Result.OK;
-                    if (JavaCompiler.explicitAnnotationProcessingRequested(options)) {
-                        error("err.no.source.files.classes");
-                    } else {
-                        error("err.no.source.files");
-                    }
-                    return Result.CMDERR;
-                }
-            } catch (java.io.FileNotFoundException e) {
-                warning("err.file.not.found", e.getMessage());
-                return Result.SYSERR;
-            }
+        Arguments args = Arguments.instance(context);
+        args.init(ownName, argv);
 
-            boolean forceStdOut = options.isSet("stdout");
-            if (forceStdOut) {
-                log.flush();
-                log.setWriters(new PrintWriter(System.out, true));
-            }
+        if (log.nerrors > 0)
+            return Result.CMDERR;
 
-            // allow System property in following line as a Mustang legacy
-            boolean batchMode = (options.isUnset("nonBatchMode")
-                        && System.getProperty("nonBatchMode") == null);
-            if (batchMode)
-                CacheFSInfo.preRegister(context);
+        Options options = Options.instance(context);
 
-            fileManager = context.get(JavaFileManager.class);
-            if (fileManager instanceof BaseFileManager) {
-                ((BaseFileManager) fileManager).handleOptions(deferredFileManagerOptions);
-            }
+        // init Log
+        boolean forceStdOut = options.isSet("stdout");
+        if (forceStdOut) {
+            log.flush();
+            log.setWriters(new PrintWriter(System.out, true));
+        }
 
-            // FIXME: this code will not be invoked if using JavacTask.parse/analyze/generate
-            // invoke any available plugins
-            String plugins = options.get(PLUGIN);
-            if (plugins != null) {
-                JavacProcessingEnvironment pEnv = JavacProcessingEnvironment.instance(context);
-                ClassLoader cl = pEnv.getProcessorClassLoader();
-                ServiceLoader<Plugin> sl = ServiceLoader.load(Plugin.class, cl);
-                Set<List<String>> pluginsToCall = new LinkedHashSet<>();
-                for (String plugin: plugins.split("\\x00")) {
-                    pluginsToCall.add(List.from(plugin.split("\\s+")));
-                }
-                JavacTask task = null;
-                for (Plugin plugin : sl) {
-                    for (List<String> p : pluginsToCall) {
-                        if (plugin.getName().equals(p.head)) {
-                            pluginsToCall.remove(p);
-                            try {
-                                if (task == null)
-                                    task = JavacTask.instance(pEnv);
-                                plugin.init(task, p.tail.toArray(new String[p.tail.size()]));
-                            } catch (Throwable ex) {
-                                if (apiMode)
-                                    throw new RuntimeException(ex);
-                                pluginMessage(ex);
-                                return Result.SYSERR;
-                            }
-                        }
-                    }
-                }
-                for (List<String> p: pluginsToCall) {
-                    log.printLines(PrefixKind.JAVAC, "msg.plugin.not.found", p.head);
-                }
-            }
+        // init CacheFSInfo
+        // allow System property in following line as a Mustang legacy
+        boolean batchMode = (options.isUnset("nonBatchMode")
+                    && System.getProperty("nonBatchMode") == null);
+        if (batchMode)
+            CacheFSInfo.preRegister(context);
 
-            if (options.isSet("completionDeps")) {
-                Dependencies.GraphDependencies.preRegister(context);
-            }
+        // init file manager
+        fileManager = context.get(JavaFileManager.class);
+        if (fileManager instanceof BaseFileManager) {
+            ((BaseFileManager) fileManager).setContext(context); // reinit with options
+            ((BaseFileManager) fileManager).handleOptions(args.getDeferredFileManagerOptions());
+        }
 
-            comp = JavaCompiler.instance(context);
+        // handle this here so it works even if no other options given
+        String showClass = options.get("showClass");
+        if (showClass != null) {
+            if (showClass.equals("showClass")) // no value given for option
+                showClass = "com.sun.tools.javac.Main";
+            showClass(showClass);
+        }
 
-            // FIXME: this code will not be invoked if using JavacTask.parse/analyze/generate
-            String xdoclint = options.get(XDOCLINT);
-            String xdoclintCustom = options.get(XDOCLINT_CUSTOM);
-            if (xdoclint != null || xdoclintCustom != null) {
-                Set<String> doclintOpts = new LinkedHashSet<>();
-                if (xdoclint != null)
-                    doclintOpts.add(DocLint.XMSGS_OPTION);
-                if (xdoclintCustom != null) {
-                    for (String s: xdoclintCustom.split("\\s+")) {
-                        if (s.isEmpty())
-                            continue;
-                        doclintOpts.add(s.replace(XDOCLINT_CUSTOM.text, DocLint.XMSGS_CUSTOM_PREFIX));
-                    }
-                }
-                if (!(doclintOpts.size() == 1
-                        && doclintOpts.iterator().next().equals(DocLint.XMSGS_CUSTOM_PREFIX + "none"))) {
-                    JavacTask t = BasicJavacTask.instance(context);
-                    // standard doclet normally generates H1, H2
-                    doclintOpts.add(DocLint.XIMPLICIT_HEADERS + "2");
-                    new DocLint().init(t, doclintOpts.toArray(new String[doclintOpts.size()]));
-                    comp.keepComments = true;
-                }
-            }
+        boolean ok = args.validate();
+        if (!ok || log.nerrors > 0)
+            return Result.CMDERR;
 
-            if (options.get(XSTDOUT) != null) {
-                // Stdout reassigned - ask compiler to close it when it is done
-                comp.closeables = comp.closeables.prepend(log.getWriter(WriterKind.NOTICE));
-            }
+        if (args.isEmpty())
+            return Result.OK;
 
-            if (!files.isEmpty()) {
-                // add filenames to fileObjects
-                comp = JavaCompiler.instance(context);
-                List<JavaFileObject> otherFiles = List.nil();
-                JavacFileManager dfm = (JavacFileManager)fileManager;
-                for (JavaFileObject fo : dfm.getJavaFileObjectsFromFiles(files))
-                    otherFiles = otherFiles.prepend(fo);
-                for (JavaFileObject fo : otherFiles)
-                    fileObjects = fileObjects.prepend(fo);
-            }
-            comp.compile(fileObjects,
-                         classnames.toList(),
-                         processors);
+        // init plugins
+        Set<List<String>> pluginOpts = args.getPluginOpts();
+        if (!pluginOpts.isEmpty()) {
+            BasicJavacTask t = (BasicJavacTask) BasicJavacTask.instance(context);
+            t.initPlugins(pluginOpts);
+        }
+
+        // init doclint
+        List<String> docLintOpts = args.getDocLintOpts();
+        if (!docLintOpts.isEmpty()) {
+            BasicJavacTask t = (BasicJavacTask) BasicJavacTask.instance(context);
+            t.initDocLint(docLintOpts);
+        }
+
+        // init Depeendencies
+        if (options.isSet("completionDeps")) {
+            Dependencies.GraphDependencies.preRegister(context);
+        }
+
+        // init JavaCompiler
+        JavaCompiler comp = JavaCompiler.instance(context);
+        if (options.get(Option.XSTDOUT) != null) {
+            // Stdout reassigned - ask compiler to close it when it is done
+            comp.closeables = comp.closeables.prepend(log.getWriter(WriterKind.NOTICE));
+        }
+
+        try {
+            comp.compile(args.getFileObjects(), args.getClassNames(), null);
 
             if (log.expectDiagKeys != null) {
                 if (log.expectDiagKeys.isEmpty()) {
@@ -547,37 +258,25 @@
                 }
             }
 
-            if (comp.errorCount() != 0)
-                return Result.ERROR;
-        } catch (IOException ex) {
-            ioMessage(ex);
-            return Result.SYSERR;
-        } catch (OutOfMemoryError ex) {
-            resourceMessage(ex);
-            return Result.SYSERR;
-        } catch (StackOverflowError ex) {
+            return (comp.errorCount() == 0) ? Result.OK : Result.ERROR;
+
+        } catch (OutOfMemoryError | StackOverflowError ex) {
             resourceMessage(ex);
             return Result.SYSERR;
         } catch (FatalError ex) {
-            feMessage(ex);
+            feMessage(ex, options);
             return Result.SYSERR;
         } catch (AnnotationProcessingError ex) {
-            if (apiMode)
-                throw new RuntimeException(ex.getCause());
             apMessage(ex);
             return Result.SYSERR;
-        } catch (ClientCodeException ex) {
-            // as specified by javax.tools.JavaCompiler#getTask
-            // and javax.tools.JavaCompiler.CompilationTask#call
-            throw new RuntimeException(ex.getCause());
         } catch (PropagatedException ex) {
+            // TODO: what about errors from plugins?   should not simply rethrow the error here
             throw ex.getCause();
         } catch (Throwable ex) {
             // Nasty.  If we've already reported an error, compensate
             // for buggy compiler error recovery by swallowing thrown
             // exceptions.
-            if (comp == null || comp.errorCount() == 0 ||
-                options == null || options.isSet("dev"))
+            if (comp == null || comp.errorCount() == 0 || options.isSet("dev"))
                 bugMessage(ex);
             return Result.ABNORMAL;
         } finally {
@@ -588,10 +287,7 @@
                     throw new RuntimeException(ex.getCause());
                 }
             }
-            filenames = null;
-            options = null;
         }
-        return Result.OK;
     }
 
     /** Print a message reporting an internal error.
@@ -603,7 +299,7 @@
 
     /** Print a message reporting a fatal error.
      */
-    void feMessage(Throwable ex) {
+    void feMessage(Throwable ex, Options options) {
         log.printRawLines(ex.getMessage());
         if (ex.getCause() != null && options.isSet("dev")) {
             ex.getCause().printStackTrace(log.getWriter(WriterKind.NOTICE));
@@ -663,47 +359,19 @@
                 for (byte b: digest)
                     sb.append(String.format("%02x", b));
                 pw.println("  " + algorithm + " checksum: " + sb);
-            } catch (Exception e) {
+            } catch (NoSuchAlgorithmException | IOException e) {
                 pw.println("  cannot compute digest: " + e);
             }
         }
     }
 
+    // TODO: update this to JavacFileManager
     private JavaFileManager fileManager;
 
     /* ************************************************************************
      * Internationalization
      *************************************************************************/
 
-//    /** Find a localized string in the resource bundle.
-//     *  @param key     The key for the localized string.
-//     */
-//    public static String getLocalizedString(String key, Object... args) { // FIXME sb private
-//        try {
-//            if (messages == null)
-//                messages = new JavacMessages(javacBundleName);
-//            return messages.getLocalizedString("javac." + key, args);
-//        }
-//        catch (MissingResourceException e) {
-//            throw new Error("Fatal Error: Resource for javac is missing", e);
-//        }
-//    }
-//
-//    public static void useRawMessages(boolean enable) {
-//        if (enable) {
-//            messages = new JavacMessages(javacBundleName) {
-//                    @Override
-//                    public String getLocalizedString(String key, Object... args) {
-//                        return key;
-//                    }
-//                };
-//        } else {
-//            messages = new JavacMessages(javacBundleName);
-//        }
-//    }
-
     public static final String javacBundleName =
         "com.sun.tools.javac.resources.javac";
-//
-//    private static JavacMessages messages;
 }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java	Fri Aug 22 12:25:01 2014 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java	Fri Aug 22 16:28:16 2014 -0700
@@ -55,7 +55,7 @@
 
 /**
  * Options for javac. The specific Option to handle a command-line option
- * is identified by searching the members of this enum in order, looking
+ * is identified by searching the members of this enum in order, looking for
  * the first {@link #matches match}. The action for an Option is performed
  * by calling {@link #process process}, and by providing a suitable
  * {@link OptionHelper} to provide access the compiler state.
--- a/langtools/test/tools/javac/6410653/T6410653.java	Fri Aug 22 12:25:01 2014 +0200
+++ b/langtools/test/tools/javac/6410653/T6410653.java	Fri Aug 22 16:28:16 2014 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2014, 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
@@ -45,6 +45,7 @@
         useRawMessages.setBoolean(null, true);
         ByteArrayOutputStream out = new ByteArrayOutputStream();
         compiler.run(null, null, out, "-d", source, source);
+        System.err.println(">>>" + out + "<<<");
         useRawMessages.setBoolean(null, false);
         if (!out.toString().equals(String.format("%s%n%s%n",
                                                  "javac: javac.err.file.not.directory",
--- a/langtools/test/tools/javac/6457284/T6457284.java	Fri Aug 22 12:25:01 2014 +0200
+++ b/langtools/test/tools/javac/6457284/T6457284.java	Fri Aug 22 16:28:16 2014 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2014, 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
@@ -32,7 +32,8 @@
 import java.net.URI;
 import javax.lang.model.element.Element;
 
-import com.sun.tools.javac.api.JavacTaskImpl;
+import com.sun.source.util.JavacTask;
+import com.sun.tools.javac.api.JavacTool;
 import com.sun.tools.javac.util.Context;
 import com.sun.tools.javac.util.List;
 import com.sun.tools.javac.util.JavacMessages;
@@ -49,10 +50,12 @@
         }
     }
     public static void main(String[] args) throws IOException {
-        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
-        JavacTaskImpl task = (JavacTaskImpl)compiler.getTask(null, null, null, null, null,
-                                                             List.of(new MyFileObject()));
-        MyMessages.preRegister(task.getContext());
+        Context context = new Context();
+        MyMessages.preRegister(context);
+        JavacTool tool = JavacTool.create();
+        JavacTask task = tool.getTask(null, null, null, null, null,
+                                      List.of(new MyFileObject()),
+                                      context);
         task.parse();
         for (Element e : task.analyze()) {
             if (!e.getEnclosingElement().toString().equals("compiler.misc.unnamed.package"))
--- a/langtools/test/tools/javac/T6358166.java	Fri Aug 22 12:25:01 2014 +0200
+++ b/langtools/test/tools/javac/T6358166.java	Fri Aug 22 16:28:16 2014 -0700
@@ -29,13 +29,15 @@
 
 import java.io.*;
 import java.util.*;
+
 import javax.annotation.processing.*;
 import javax.lang.model.element.*;
 import javax.tools.*;
-import com.sun.tools.javac.file.*;
-import com.sun.tools.javac.file.JavacFileManager; // disambiguate
+
+import com.sun.tools.javac.api.JavacTaskImpl;
+import com.sun.tools.javac.api.JavacTool;
+import com.sun.tools.javac.file.JavacFileManager;
 import com.sun.tools.javac.main.JavaCompiler;
-import com.sun.tools.javac.main.*;
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.List; // disambiguate
 
@@ -58,12 +60,11 @@
     static void test(JavacFileManager fm, JavaFileObject f, String... args) throws Throwable {
         Context context = new Context();
 
-        Main compilerMain = initCompilerMain(context, fm, args);
+        JavacTool tool = JavacTool.create();
+        JavacTaskImpl task = (JavacTaskImpl) tool.getTask(null, fm, null, Arrays.asList(args), null, List.of(f), context);
+        task.call();
 
         JavaCompiler c = JavaCompiler.instance(context);
-
-        c.compile(List.of(f));
-
         if (c.errorCount() != 0)
             throw new AssertionError("compilation failed");
 
@@ -72,19 +73,6 @@
             throw new AssertionError("elapsed time is suspect: " + msec);
     }
 
-    static Main initCompilerMain(Context context, JavacFileManager fm, String... args) {
-        fm.setContext(context);
-        context.put(JavaFileManager.class, fm);
-
-        Main compilerMain = new Main("javac", new PrintWriter(System.err, true));
-        compilerMain.setOptions(Options.instance(context));
-        compilerMain.filenames = new LinkedHashSet<File>();
-        compilerMain.deferredFileManagerOptions = new LinkedHashMap<>();
-        compilerMain.processArgs(args);
-        fm.handleOptions(compilerMain.deferredFileManagerOptions);
-        return compilerMain;
-    }
-
     public boolean process(Set<? extends TypeElement> tes, RoundEnvironment renv) {
         return true;
     }
--- a/langtools/test/tools/javac/T6358168.java	Fri Aug 22 12:25:01 2014 +0200
+++ b/langtools/test/tools/javac/T6358168.java	Fri Aug 22 16:28:16 2014 -0700
@@ -28,61 +28,63 @@
  */
 
 import java.io.*;
-import java.net.*;
 import java.util.*;
+
 import javax.annotation.processing.*;
 import javax.lang.model.element.*;
 import javax.tools.*;
-import com.sun.tools.javac.file.*;
+
+import com.sun.source.util.JavacTask;
+import com.sun.tools.javac.api.JavacTool;
 import com.sun.tools.javac.file.JavacFileManager;
 import com.sun.tools.javac.main.JavaCompiler;
-import com.sun.tools.javac.main.*;
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.List; // disambiguate
 
 
 @SupportedAnnotationTypes("*")
 public class T6358168 extends AbstractProcessor {
-    private static String testClasses = System.getProperty("test.classes");
-    private static String testSrc = System.getProperty("test.src");
-    private static String self = T6358168.class.getName();
+    private static final String testClasses = System.getProperty("test.classes");
+    private static final String testSrc = System.getProperty("test.src");
+    private static final String self = T6358168.class.getName();
 
     public static void main(String... args) throws Throwable {
 
         JavacFileManager fm = new JavacFileManager(new Context(), false, null);
-        JavaFileObject f = fm.getFileForInput(testSrc + File.separatorChar + T6358168.class.getName() + ".java");
+        List<JavaFileObject> files = toList(fm.getJavaFileObjects(new File(testSrc, self + ".java")));
 
         try {
             // first, test case with no annotation processing
-            testNoAnnotationProcessing(fm, f);
+            testNoAnnotationProcessing(fm, files);
 
             // now, test case with annotation processing
-            testAnnotationProcessing(fm, f);
+            testAnnotationProcessing(fm, files);
         }
         catch (Throwable t) {
-            AssertionError e = new AssertionError();
-            e.initCause(t);
-            throw e;
+            throw new AssertionError(t);
         }
     }
 
-    static void testNoAnnotationProcessing(JavacFileManager fm, JavaFileObject f) throws Throwable {
+    static void testNoAnnotationProcessing(JavacFileManager fm, List<JavaFileObject> files) throws Throwable {
         Context context = new Context();
 
         String[] args = { "-d", "." };
-        Main compilerMain = initCompilerMain(context, fm, args);
+
+        JavacTool tool = JavacTool.create();
+        JavacTask task = tool.getTask(null, fm, null, List.from(args), null, files, context);
+        // no need in this simple case to call task.prepareCompiler(false)
 
         JavaCompiler compiler = JavaCompiler.instance(context);
-        compiler.compile(List.of(f));
+        compiler.compile(files);
         try {
-            compiler.compile(List.of(f));
+            compiler.compile(files);
             throw new Error("Error: AssertionError not thrown after second call of compile");
         } catch (AssertionError e) {
             System.err.println("Exception from compiler (expected): " + e);
         }
     }
 
-    static void testAnnotationProcessing(JavacFileManager fm, JavaFileObject f) throws Throwable {
+    static void testAnnotationProcessing(JavacFileManager fm, List<JavaFileObject> files) throws Throwable {
         Context context = new Context();
 
         String[] args = {
@@ -91,31 +93,29 @@
                 "-processor", self,
                 "-d", "."
         };
-        Main compilerMain = initCompilerMain(context, fm, args);
+
+        JavacTool tool = JavacTool.create();
+        JavacTask task = tool.getTask(null, fm, null, List.from(args), null, files, context);
+        // no need in this simple case to call task.prepareCompiler(false)
 
         JavaCompiler compiler = JavaCompiler.instance(context);
-        compiler.compile(List.of(f));
+        compiler.compile(files);
         try {
-            compiler.compile(List.of(f));
+            compiler.compile(files);
             throw new Error("Error: AssertionError not thrown after second call of compile");
         } catch (AssertionError e) {
             System.err.println("Exception from compiler (expected): " + e);
         }
     }
 
-    static Main initCompilerMain(Context context, JavacFileManager fm, String... args) {
-        fm.setContext(context);
-        context.put(JavaFileManager.class, fm);
-
-        Main compilerMain = new Main("javac", new PrintWriter(System.err, true));
-        compilerMain.setOptions(Options.instance(context));
-        compilerMain.filenames = new LinkedHashSet<File>();
-        compilerMain.deferredFileManagerOptions = new LinkedHashMap<>();
-        compilerMain.processArgs(args);
-        fm.handleOptions(compilerMain.deferredFileManagerOptions);
-        return compilerMain;
+    private static List<JavaFileObject> toList(Iterable<? extends JavaFileObject> iter) {
+        ListBuffer<JavaFileObject> files = new ListBuffer<>();
+        for (JavaFileObject file: iter)
+            files.add(file);
+        return files.toList();
     }
 
+    @Override
     public boolean process(Set<? extends TypeElement> tes, RoundEnvironment renv) {
         return true;
     }
--- a/langtools/test/tools/javac/T8009640/CheckRejectProfileBCPOptionsIfUsedTogetherTest.java	Fri Aug 22 12:25:01 2014 +0200
+++ b/langtools/test/tools/javac/T8009640/CheckRejectProfileBCPOptionsIfUsedTogetherTest.java	Fri Aug 22 16:28:16 2014 -0700
@@ -44,12 +44,14 @@
 
     public static void main(String args[]) throws Exception {
         ToolBox tb = new ToolBox();
+        tb.writeFile("Test.java", TestSrc);
 
         ToolBox.Result result = tb.new JavacTask(ToolBox.Mode.CMDLINE)
                 .options("-profile", "compact1",
                         "-bootclasspath", Paths.get(ToolBox.testJDK, "jre/lib/rt.jar").toString())
-                .sources(TestSrc)
-                .run(ToolBox.Expect.FAIL);
+                .files("Test.java")
+                .run(ToolBox.Expect.FAIL)
+                .writeAll();
 
         String out = result.getOutput(ToolBox.OutputKind.DIRECT);
         Assert.check(out.startsWith(
--- a/langtools/test/tools/javac/api/6410643/T6410643.java	Fri Aug 22 12:25:01 2014 +0200
+++ b/langtools/test/tools/javac/api/6410643/T6410643.java	Fri Aug 22 16:28:16 2014 -0700
@@ -49,9 +49,13 @@
 
     void test(String... args) {
         task = tool.getTask(null, null, null, null, null, null);
-        if (task.call())
+        try {
+            task.call();
             throw new AssertionError("Error expected");
-        System.err.println("Compilation failed as expected!");
+        } catch (IllegalStateException e) {
+            System.err.println("Expected error occurred: " + e);
+        }
+
         Iterable<String>         s = singleton(null);
         Iterable<JavaFileObject> f = singleton(null);
         //    case (null, null, null) is tested above
--- a/langtools/test/tools/javac/api/T6357331.java	Fri Aug 22 12:25:01 2014 +0200
+++ b/langtools/test/tools/javac/api/T6357331.java	Fri Aug 22 16:28:16 2014 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2014, 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
@@ -27,7 +27,7 @@
  * @summary NPE from JavacTask.getElements() after calling CompilationTask.run
  */
 import java.io.*;
-import java.util.Arrays;
+import java.util.*;
 import javax.tools.*;
 import com.sun.source.util.*;
 
@@ -36,7 +36,11 @@
     public static void main(String... args) {
         JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
         PrintWriter out = new PrintWriter(new StringWriter());
-        final JavacTask task = (JavacTask) (tool.getTask(out, null, null, null, null, null));
+        List<String> opts = Arrays.asList("-d", ".");
+        StandardJavaFileManager fm = tool.getStandardFileManager(null, null, null);
+        File thisFile = new File(System.getProperty("test.src"), "T6357331.java");
+        Iterable<? extends JavaFileObject> files = fm.getJavaFileObjects(thisFile);
+        final JavacTask task = (JavacTask) (tool.getTask(out, fm, null, opts, null, files));
 
         // set a listener to verify that IllegalStateException is not thrown
         // during the compilation
--- a/langtools/test/tools/javac/api/TestJavacTaskScanner.java	Fri Aug 22 12:25:01 2014 +0200
+++ b/langtools/test/tools/javac/api/TestJavacTaskScanner.java	Fri Aug 22 16:28:16 2014 -0700
@@ -75,11 +75,7 @@
 
     public void run() {
         Iterable<? extends TypeElement> toplevels;
-        try {
-            toplevels = task.enter(task.parse());
-        } catch (IOException ex) {
-            throw new AssertionError(ex);
-        }
+        toplevels = task.enter(task.parse());
         for (TypeElement clazz : toplevels) {
             System.out.format("Testing %s:%n%n", clazz.getSimpleName());
             testParseType(clazz);
--- a/langtools/test/tools/javac/api/TestJavacTask_Lock.java	Fri Aug 22 12:25:01 2014 +0200
+++ b/langtools/test/tools/javac/api/TestJavacTask_Lock.java	Fri Aug 22 16:28:16 2014 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2014, 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
@@ -51,7 +51,7 @@
             int test(CompilationTask t) {
                 try {
                     ((JavacTask) t).parse();
-                return 1;
+                    return 1;
                 } catch (IOException ex) {
                     throw new Error(ex);
                 }
@@ -94,6 +94,7 @@
             second.test(t);
             error("No exception thrown");
         } catch (IllegalStateException e) {
+            e.printStackTrace();
             System.err.println("Expected exception caught: " + e);
         } catch (Exception e) {
             error("Unexpected exception caught: " + e);
--- a/langtools/test/tools/javac/api/TestResolveError.java	Fri Aug 22 12:25:01 2014 +0200
+++ b/langtools/test/tools/javac/api/TestResolveError.java	Fri Aug 22 16:28:16 2014 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2014, 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
@@ -65,11 +65,7 @@
         types = task.getTypes();
 
         Iterable<? extends TypeElement> toplevels;
-        try {
-            toplevels = task.enter(task.parse());
-        } catch (IOException ex) {
-            throw new AssertionError(ex);
-        }
+        toplevels = task.enter(task.parse());
 
         for (TypeElement clazz : toplevels) {
             System.out.format("Testing %s:%n%n", clazz.getSimpleName());
--- a/langtools/test/tools/javac/api/taskListeners/CompileEvent.java	Fri Aug 22 12:25:01 2014 +0200
+++ b/langtools/test/tools/javac/api/taskListeners/CompileEvent.java	Fri Aug 22 16:28:16 2014 -0700
@@ -70,27 +70,29 @@
         }, new PrintWriter(out, true));
         if (mainResult != 0)
             throw new AssertionError("Compilation failed unexpectedly, exit code: " + mainResult);
-        assertOutput(out);
+        assertOutput(out.toString());
 
         JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
         StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null);
         Iterable<? extends JavaFileObject> testFileObjects = fm.getJavaFileObjects(test);
 
         //test events fired to listeners registered from plugins
-        //when starting compiler using JavaCompiler.getTak(...).call
+        //when starting compiler using JavaCompiler.getTask(...).call
         List<String> options =
                 Arrays.asList("-Xplugin:compile-event", "-processorpath", testClasses);
         out = new StringWriter();
         boolean compResult = comp.getTask(out, null, null, options, null, testFileObjects).call();
         if (!compResult)
             throw new AssertionError("Compilation failed unexpectedly.");
-        assertOutput(out);
+        assertOutput(out.toString());
     }
 
-    void assertOutput(StringWriter out) {
+    void assertOutput(String found) {
         String lineSeparator = System.getProperty("line.separator");
-        if (!out.toString().trim().replace(lineSeparator, "\n").equals(EXPECTED)) {
-            throw new AssertionError("Unexpected events: " + out.toString());
+        if (!found.trim().replace(lineSeparator, "\n").equals(EXPECTED)) {
+            System.err.println("Expected: " + EXPECTED);
+            System.err.println("Found:    " + found);
+            throw new AssertionError("Unexpected events: " + found);
         }
     }
 
--- a/langtools/test/tools/javac/api/taskListeners/EventsBalancedTest.java	Fri Aug 22 12:25:01 2014 +0200
+++ b/langtools/test/tools/javac/api/taskListeners/EventsBalancedTest.java	Fri Aug 22 16:28:16 2014 -0700
@@ -66,11 +66,10 @@
         }
     }
 
-    void test(Iterable<String> options, Iterable<JavaFileObject> files) throws IOException {
-        StringWriter sw = new StringWriter();
-        PrintWriter pw = new PrintWriter(sw);
+    void test(List<String> options, List<JavaFileObject> files) throws IOException {
+        System.err.println("testing: " + options + ", " + files);
         TestListener listener = new TestListener();
-        JavacTask task = tool.getTask(pw, fm, null, options, null, files);
+        JavacTask task = tool.getTask(null, fm, null, options, null, files);
 
         task.setTaskListener(listener);
 
--- a/langtools/test/tools/javac/failover/CheckAttributedTree.java	Fri Aug 22 12:25:01 2014 +0200
+++ b/langtools/test/tools/javac/failover/CheckAttributedTree.java	Fri Aug 22 16:28:16 2014 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2014, 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
@@ -54,10 +54,10 @@
 import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.concurrent.atomic.AtomicInteger;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
 
 import javax.lang.model.element.Element;
 import javax.swing.DefaultComboBoxModel;
@@ -80,11 +80,13 @@
 import javax.tools.JavaFileObject;
 
 import com.sun.source.tree.CompilationUnitTree;
+import com.sun.source.util.JavacTask;
 import com.sun.source.util.TaskEvent;
-import com.sun.source.util.JavacTask;
 import com.sun.source.util.TaskListener;
+import com.sun.tools.javac.api.JavacTaskImpl;
 import com.sun.tools.javac.code.Symbol;
 import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.main.JavaCompiler;
 import com.sun.tools.javac.tree.EndPosTable;
 import com.sun.tools.javac.tree.JCTree;
 import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
@@ -256,6 +258,7 @@
                     }
                 }
             });
+            return;
         }
 
         if (!quiet)
@@ -272,7 +275,7 @@
      * @param file the file to be read
      * @return the tree for the content of the file
      * @throws IOException if any IO errors occur
-     * @throws TreePosTest.ParseException if any errors occur while parsing the file
+     * @throws AttributionException if any errors occur while analyzing the file
      */
     List<Pair<JCCompilationUnit, JCTree>> read(File file) throws IOException, AttributionException {
         r.errors = 0;
@@ -283,22 +286,28 @@
         task.setTaskListener(new TaskListener() {
             public void started(TaskEvent e) {
                 if (e.getKind() == TaskEvent.Kind.ANALYZE)
-                        analyzedElems.add(e.getTypeElement());
+                    analyzedElems.add(e.getTypeElement());
             }
             public void finished(TaskEvent e) { }
         });
 
         try {
             Iterable<? extends CompilationUnitTree> trees = task.parse();
-            task.analyze();
+//            JavaCompiler c = JavaCompiler.instance(((JavacTaskImpl) task).getContext());
+//            System.err.println("verboseCompilePolicy: " + c.verboseCompilePolicy);
+//            System.err.println("shouldStopIfError: " + c.shouldStopPolicyIfError);
+//            System.err.println("shouldStopIfNoError: " + c.shouldStopPolicyIfNoError);
+            Iterable<? extends Element> elems = task.analyze();
+            if (!elems.iterator().hasNext())
+                throw new AttributionException("No results from analyze");
             List<Pair<JCCompilationUnit, JCTree>> res = new ArrayList<>();
-            //System.out.println("Try to add pairs. Elems are " + analyzedElems);
+            //System.err.println("Try to add pairs. Elems are " + analyzedElems);
             for (CompilationUnitTree t : trees) {
                JCCompilationUnit cu = (JCCompilationUnit)t;
                for (JCTree def : cu.defs) {
                    if (def.hasTag(CLASSDEF) &&
                            analyzedElems.contains(((JCTree.JCClassDecl)def).sym)) {
-                       //System.out.println("Adding pair...");
+                       //System.err.println("Adding pair..." + cu.sourcefile + " " + ((JCTree.JCClassDecl) def).name);
                        res.add(new Pair<>(cu, def));
                    }
                }
@@ -316,7 +325,9 @@
      * @param msg the error message
      */
     void error(String msg) {
+        System.err.println();
         System.err.println(msg);
+        System.err.println();
         errCount.incrementAndGet();
     }
 
@@ -347,6 +358,7 @@
     private class NPETester extends TreeScanner {
         void test(List<Pair<JCCompilationUnit, JCTree>> trees) {
             for (Pair<JCCompilationUnit, JCTree> p : trees) {
+//              System.err.println("checking " + p.fst.sourcefile);
                 sourcefile = p.fst.sourcefile;
                 endPosTable = p.fst.endPositions;
                 encl = new Info(p.snd, endPosTable);
@@ -366,7 +378,7 @@
                 check(tree.type != null,
                         "'null' field 'type' found in tree ", self);
                 if (tree.type==null)
-                    new Throwable().printStackTrace();
+                    Thread.dumpStack();
             }
 
             Field errField = checkFields(tree);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/options/modes/AtFilesTest.java	Fri Aug 22 16:28:16 2014 -0700
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2014, 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 8044859
+ * @summary test support for at-files
+ * @build Tester
+ * @run main AtFilesTest
+ */
+
+import java.io.IOException;
+
+public class AtFilesTest extends Tester {
+    public static void main(String... args) throws Exception {
+        AtFilesTest t = new AtFilesTest();
+        t.runTests();
+    }
+
+    @Test
+    void testAtFiles() throws IOException {
+        writeFile("src/A.java", "class A { }");
+        writeFile("files.txt", "src/A.java");
+        mkdirs("classes");
+
+        String[] opts = { "-d", "classes", "@files.txt" };
+        String[] files = { };
+
+        runMain(opts, files)
+                .checkOK()
+                .checkClass("A");
+
+        runCall(opts, files)
+                .checkIllegalArgumentException();
+
+        runParse(opts, files)
+                .checkIllegalArgumentException();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/options/modes/DocLintTest.java	Fri Aug 22 16:28:16 2014 -0700
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2014, 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 8044859
+ * @summary test support for -Xdoclint
+ * @build Tester
+ * @run main DocLintTest
+ */
+
+import com.sun.tools.javac.main.Main;
+import java.io.IOException;
+
+public class DocLintTest extends Tester {
+    public static void main(String... args) throws Exception {
+        DocLintTest t = new DocLintTest();
+        t.runTests();
+    }
+
+    @Test
+    void testDocLint() throws IOException {
+        writeFile("src/C.java", "/** & */ class C { }");
+        mkdirs("classes");
+
+        String[] opts = { "-d", "classes", "-Xdoclint" };
+        String[] files = { "src/C.java" };
+
+        runMain(opts, files)
+                .checkResult(Main.Result.ERROR.exitCode);
+
+        runCall(opts, files)
+                .checkResult(false);
+
+        // 1. doclint runs at the beginning of analyze
+        // 2. the analyze call itself succeeds, so we check for errors being reported
+        runAnalyze(opts, files)
+                .checkResult(true)
+                .checkLog(Log.DIRECT, "^");
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/options/modes/FSInfoTest.java	Fri Aug 22 16:28:16 2014 -0700
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2014, 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 8044859
+ * @summary test support for the internal file system cache
+ * @build Tester
+ * @run main FSInfoTest
+ */
+
+import com.sun.tools.javac.file.CacheFSInfo;
+import com.sun.tools.javac.file.FSInfo;
+import java.io.IOException;
+
+public class FSInfoTest extends Tester {
+    public static void main(String... args) throws Exception {
+        FSInfoTest t = new FSInfoTest();
+        t.writeFile("C.java", "class C { }");
+        t.runTests();
+    }
+
+    @Test
+    void testCacheEnabled() throws IOException {
+
+        String[] args = { };
+        String[] files = { "C.java"};
+
+        TestResult tr = runMain(args, files);
+        FSInfo info = tr.context.get(FSInfo.class);
+        if (!(info instanceof CacheFSInfo))
+            error("unexpected FSInfo; found " + info.getClass() + ", expected CacheFSInfo");
+    }
+
+    @Test
+    void testCacheDisabled() throws IOException {
+        writeFile("C.java", "class C { }");
+
+        String[] args = { "-XDnonBatchMode" };
+        String[] files = { "C.java"};
+
+        TestResult tr = runMain(args, files);
+        FSInfo info = tr.context.get(FSInfo.class);
+        if (info instanceof CacheFSInfo)
+            error("unexpected CacheFSInfo found");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/options/modes/InfoOptsTest.java	Fri Aug 22 16:28:16 2014 -0700
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2014, 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 8044859
+ * @summary test support for info options -help -X -version -fullversion
+ * @build Tester
+ * @run main InfoOptsTest
+ */
+
+import java.io.IOException;
+
+public class InfoOptsTest extends Tester {
+    public static void main(String... args) throws Exception {
+        InfoOptsTest t = new InfoOptsTest();
+        t.runTests();
+    }
+
+    @Test
+    void testInfoOpts() throws IOException {
+        testInfoOpt("-help", "-deprecation");
+        testInfoOpt("-X", "-Xlint");
+
+        String specVersion = System.getProperty("java.specification.version");
+        testInfoOpt("-version", "javac", specVersion);
+        testInfoOpt("-fullversion", "javac", specVersion, "-b");
+    }
+
+    void testInfoOpt(String opt, String... expect) {
+        String[] opts = { opt };
+        String[] files = { };
+
+        runMain(opts, files)
+                .checkOK()
+                .checkLog(expect);
+
+        runCall(opts, files)
+                .checkIllegalArgumentException();
+
+        runParse(opts, files)
+                .checkIllegalArgumentException();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/options/modes/NoOperandsTest.java	Fri Aug 22 16:28:16 2014 -0700
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2014, 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 8044859
+ * @summary test support no operands being specified
+ * @build Tester
+ * @run main NoOperandsTest
+ */
+
+import com.sun.tools.javac.main.Main;
+import java.io.IOException;
+
+public class NoOperandsTest extends Tester {
+    public static void main(String... args) throws Exception {
+        NoOperandsTest t = new NoOperandsTest();
+        t.runTests();
+    }
+
+    @Test
+    void testNoOperands() throws IOException {
+        String[] opts = { "-d", "." };
+        String[] files = { };
+
+        runMain(opts, files)
+                .checkResult(Main.Result.CMDERR.exitCode);
+
+        runCall(opts, files)
+                .checkIllegalStateException();
+
+        runParse(opts, files)
+                .checkIllegalStateException();
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/options/modes/OutputDirTest.java	Fri Aug 22 16:28:16 2014 -0700
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2014, 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 8044859
+ * @summary test support for output directory options  -d  and -s
+ * @build Tester
+ * @run main OutputDirTest
+ */
+
+import com.sun.tools.javac.main.Main;
+import java.io.IOException;
+
+public class OutputDirTest extends Tester {
+    public static void main(String... args) throws Exception {
+        OutputDirTest t = new OutputDirTest();
+        t.writeFile("src/C.java", "class C { }");
+        t.runTests();
+    }
+
+    @Test
+    void testClassOutputDir() throws IOException {
+        testOutputDir("-d");
+    }
+
+    @Test
+    void testSourceOutputDir() throws IOException {
+        testOutputDir("-s");
+    }
+
+    void testOutputDir(String opt) {
+        String[] opts = { opt, "does-not-exist"};
+        String[] files = { "src/C.java" };
+
+        runMain(opts, files)
+                .checkResult(Main.Result.CMDERR.exitCode);
+
+// The API tests are disabled (for now) because Args.validate does
+// not have an easy way to access/validate file manager options,
+// which are handled directly by the file manager
+
+//        runCall(opts, files)
+//                .checkIllegalStateException();
+
+//        runParse(opts, files)
+//                .checkIllegalStateException();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/options/modes/ProfileBootClassPathTest.java	Fri Aug 22 16:28:16 2014 -0700
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2014, 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 8044859
+ * @summary test support for checking -profile and -bootclasspath
+ * @build Tester
+ * @run main ProfileBootClassPathTest
+ */
+
+import com.sun.tools.javac.main.Main;
+import java.io.File;
+import java.io.IOException;
+
+public class ProfileBootClassPathTest extends Tester {
+    public static void main(String... args) throws Exception {
+        ProfileBootClassPathTest t = new ProfileBootClassPathTest();
+        t.runTests();
+    }
+
+    @Tester.Test
+    void testProfileBootClassPath() throws IOException {
+        writeFile("C.java", "class C { }");
+
+        String javaHome = System.getProperty("java.home");
+        String rt_jar = new File(javaHome, "jre/lib/rt.jar").getPath();
+        String[] opts = { "-profile", "compact1", "-bootclasspath", rt_jar };
+        String[] files = { "C.java" };
+
+        runMain(opts, files)
+                .checkResult(Main.Result.CMDERR.exitCode);
+
+// The API tests are disabled (for now) because Args.validate does
+// not have an easy way to access/validate file manager options,
+// which are handled directly by the file manager
+
+//        runCall(opts, files)
+//                .checkIllegalStateException();
+
+//        runParse(opts, files)
+//                .checkIllegalStateException();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/options/modes/ProfileTargetTest.java	Fri Aug 22 16:28:16 2014 -0700
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2014, 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 8044859
+ * @summary test support for checking -profile and -target
+ * @build Tester
+ * @run main ProfileTargetTest
+ */
+
+import com.sun.tools.javac.main.Main;
+import java.io.IOException;
+
+public class ProfileTargetTest extends Tester {
+    public static void main(String... args) throws Exception {
+        ProfileTargetTest t = new ProfileTargetTest();
+        t.runTests();
+    }
+
+    @Test
+    void testProfileTarget() throws IOException {
+        writeFile("C.java", "class C { }");
+
+        String[] opts = { "-profile", "compact1", "-source", "7", "-target", "7" };
+        String[] files = { "C.java" };
+
+        runMain(opts, files)
+                .checkResult(Main.Result.CMDERR.exitCode);
+
+        runCall(opts, files)
+                .checkIllegalStateException();
+
+        runParse(opts, files)
+                .checkIllegalStateException();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/options/modes/SourceTargetTest.java	Fri Aug 22 16:28:16 2014 -0700
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2014, 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 8044859
+ * @summary test support for -source and -target checks
+ * @build Tester
+ * @run main SourceTargetTest
+ */
+
+import com.sun.tools.javac.main.Main;
+import java.io.IOException;
+
+public class SourceTargetTest extends Tester {
+    public static void main(String... args) throws Exception {
+        SourceTargetTest t = new SourceTargetTest();
+        t.runTests();
+    }
+
+    @Test
+    void testSourceTarget() throws IOException {
+        String v = System.getProperty("java.specification.version");
+        String latest = v.substring(v.lastIndexOf(".") + 1);
+        String prev = String.valueOf(Integer.valueOf(latest) - 1);
+
+        writeFile("C.java", "class C { }");
+
+        String[] opts = { "-source", latest, "-target", prev };
+        String[] files = { "C.java" };
+
+        runMain(opts, files)
+                .checkResult(Main.Result.CMDERR.exitCode);
+
+        runCall(opts, files)
+                .checkIllegalStateException();
+
+        runParse(opts, files)
+                .checkIllegalStateException();
+    }
+
+    @Test
+    void testObsoleteSourceTarget() throws IOException {
+
+        writeFile("C.java", "class C { }");
+
+        String[] opts = { "-source", "1.6", "-target", "1.6" };
+        String[] files = { "C.java" };
+
+        runMain(opts, files)
+                .checkOK()
+                .checkLog("obsolete");
+
+        runCall(opts, files)
+                .checkOK()
+                .checkLog("obsolete");
+
+        runParse(opts, files)
+                .checkOK()
+                .checkLog("obsolete");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/options/modes/StdOutTest.java	Fri Aug 22 16:28:16 2014 -0700
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2014, 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 8044859
+ * @summary test support for  -Xstdout file  and  -XDstdout
+ * @build Tester
+ * @run main StdOutTest
+ */
+
+import com.sun.tools.javac.main.Main;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+public class StdOutTest extends Tester {
+    public static void main(String... args) throws Exception {
+        StdOutTest t = new StdOutTest();
+        t.writeFile("src/Bad.java", "class Bad");
+        t.runTests();
+    }
+
+    @Test
+    void testXstdout() throws IOException {
+        String[] args = { "-Xstdout", "out.txt" };
+        String[] files = { "src/Bad.java" };
+
+        // verify messages get written to the specified file
+        runMain(args, files)
+                .checkResult(Main.Result.ERROR.exitCode);
+        if (!Files.exists(Paths.get("out.txt"))) {
+            error("expected file not found");
+        }
+
+        runCall(args, files)
+                .checkIllegalArgumentException();
+
+        runParse(args, files)
+                .checkIllegalArgumentException();
+    }
+
+    @Test
+    void testXDstdout() throws IOException {
+        String[] args = { "-XDstdout" };
+        String[] files = { "src/Bad.java" };
+
+        runMain(args, files)
+                .checkLog(Log.STDOUT, "Bad");
+
+        runCall(args, files)
+                .checkLog(Log.DIRECT, "Bad");
+
+        runParse(args, files)
+                .checkLog(Log.DIRECT, "Bad");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/options/modes/Tester.java	Fri Aug 22 16:28:16 2014 -0700
@@ -0,0 +1,361 @@
+/*
+ * Copyright (c) 2014, 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.
+ */
+
+import com.sun.tools.javac.api.JavacTool;
+import com.sun.tools.javac.file.JavacFileManager;
+import com.sun.tools.javac.util.Context;
+import java.io.ByteArrayOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.annotation.Annotation;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.EnumMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import javax.tools.JavaFileManager;
+import javax.tools.JavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.ToolProvider;
+
+public class Tester {
+
+    /** Marker annotation for test methods to be invoked by runTests. */
+    @Retention(RetentionPolicy.RUNTIME)
+    @interface Test { }
+
+    /**
+     * Run all methods annotated with @Test, and throw an exception if any
+     * errors are reported..
+     * Typically called on a tester object in main()
+     * @throws Exception if any errors occurred
+     */
+    void runTests() throws Exception {
+        for (Method m: getClass().getDeclaredMethods()) {
+            Annotation a = m.getAnnotation(Test.class);
+            if (a != null) {
+                try {
+                    out.println("Running test " + m.getName());
+                    m.invoke(this);
+                } catch (InvocationTargetException e) {
+                    Throwable cause = e.getCause();
+                    throw (cause instanceof Exception) ? ((Exception) cause) : e;
+                }
+                out.println();
+            }
+        }
+        if (errors > 0)
+            throw new Exception(errors + " errors occurred");
+    }
+
+    TestResult runMain(String[] opts, String[] files) {
+        out.println("Main " + Arrays.toString(opts) + " " + Arrays.toString(files));
+        return run(new TestResult(opts), (tr, c, pw) -> {
+            com.sun.tools.javac.main.Main compiler =
+                new com.sun.tools.javac.main.Main("javac", pw);
+            int rc = compiler.compile(join(opts, files), c).exitCode;
+            tr.setResult(rc);
+        });
+    }
+
+    TestResult runCall(String[] opts, String[] files) {
+        out.println("Call " + Arrays.toString(opts) + " " + Arrays.toString(files));
+        return run(new TestResult(opts), (tr, c, pw) -> {
+            boolean ok = JavacTool.create()
+                    .getTask(pw, null, null, Arrays.asList(opts), null, getFiles(files), c)
+                    .call();
+            tr.setResult(ok);
+        });
+    }
+
+    TestResult runParse(String[] opts, String[] files) {
+        out.println("Parse " + Arrays.toString(opts) + " " + Arrays.toString(files));
+        return run(new TestResult(opts), (tr, c, pw) -> {
+            JavacTool.create()
+                    .getTask(pw, null, null, Arrays.asList(opts), null, getFiles(files), c)
+                    .parse();
+            tr.setResult(true);
+        });
+    }
+
+    TestResult runAnalyze(String[] opts, String[] files) {
+        out.println("Analyze " + Arrays.toString(opts) + " " + Arrays.toString(files));
+        return run(new TestResult(opts), (tr, c, pw) -> {
+            JavacTool.create()
+                    .getTask(pw, null, null, Arrays.asList(opts), null, getFiles(files), c)
+                    .analyze();
+            tr.setResult(true);
+        });
+    }
+
+    interface Runnable {
+        void run(TestResult tr, Context c, PrintWriter pw) throws IOException;
+    }
+
+    TestResult run(TestResult tr, Runnable r) {
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        StreamOutput sysOut = new StreamOutput(System.out, System::setOut);
+        StreamOutput sysErr = new StreamOutput(System.err, System::setErr);
+        Context context = new Context();
+        JavacFileManager.preRegister(context);
+        try {
+            r.run(tr, context, pw);
+        } catch (IllegalArgumentException | IllegalStateException | IOException e) {
+            tr.setThrown(e);
+        } finally {
+            ((JavacFileManager) context.get(JavaFileManager.class)).close();
+            tr.setLogs(sw.toString(), sysOut.close(), sysErr.close());
+        }
+        tr.setContext(context);
+        tr.show();
+        return tr;
+    }
+
+    enum Log { DIRECT, STDOUT, STDERR };
+
+    class TestResult {
+        final List<String> args;
+        Throwable thrown;
+        Object rc; // Number or Boolean
+        Map<Log, String> logs;
+        Context context;
+
+        TestResult(String... args) {
+            this.args = Arrays.asList(args);
+        }
+
+        TestResult(List<String> args, Iterable<? extends JavaFileObject> files) {
+            this.args = new ArrayList<>();
+            this.args.addAll(args);
+            for (JavaFileObject f: files)
+                this.args.add(f.getName());
+        }
+
+        void setResult(int rc) {
+            this.rc = rc;
+        }
+
+        void setResult(boolean ok) {
+            this.rc = ok ? 0 : 1;
+        }
+
+        void setThrown(Throwable thrown) {
+            this.thrown = thrown;
+        }
+
+        void setLogs(String direct, String stdOut, String stdErr) {
+            logs = new EnumMap<>(Log.class);
+            logs.put(Log.DIRECT, direct);
+            logs.put(Log.STDOUT, stdOut);
+            logs.put(Log.STDERR, stdErr);
+        }
+
+        void setContext(Context context) {
+            this.context = context;
+        }
+
+        final void show() {
+            String NL = System.getProperty("line.separator");
+            boolean needSep = false;
+            if (rc != null) {
+                out.print("rc:" + rc);
+                needSep = true;
+            }
+            if (thrown != null) {
+                if (needSep) out.print("; ");
+                out.print("thrown:" + thrown);
+                needSep = true;
+            }
+            if (needSep)
+                out.println();
+            logs.forEach((k, v) -> {
+                if (!v.isEmpty()) {
+                    out.println("javac/" + k + ":");
+                    if (v.endsWith(NL))
+                        out.print(v);
+                    else
+                        out.println(v);
+                }
+
+            });
+        }
+
+        TestResult checkOK() {
+            if (thrown != null) {
+                error("unexpected exception thrown: " + thrown);
+            } else if (rc == null) {
+                error("no result set");
+            } else if (rc != (Integer) 0 && rc != (Boolean) true) {
+                error("compilation failed unexpectedly; rc=" + rc);
+            }
+            return this;
+        }
+
+        TestResult checkResult(int expect) {
+            if (thrown != null) {
+                error("unexpected exception thrown: " + thrown);
+            } else if (rc != (Integer) expect) {
+                error("unexpected result: " + rc +", expected:" + expect);
+            }
+            return this;
+        }
+
+        TestResult checkResult(boolean expect) {
+            if (thrown != null) {
+                error("unexpected exception thrown: " + thrown);
+            } else if (rc != (Integer) (expect ? 0 : 1)) {
+                error("unexpected result: " + rc +", expected:" + expect);
+            }
+            return this;
+        }
+
+        TestResult checkLog(String... expects) {
+            return checkLog(Log.DIRECT, expects);
+        }
+
+        TestResult checkLog(Log l, String... expects) {
+            for (String e: expects) {
+                if (!logs.get(l).contains(e))
+                    error("expected string not found: " + e);
+            }
+            return this;
+        }
+
+        TestResult checkIllegalArgumentException() {
+            return checkThrown(IllegalArgumentException.class);
+        }
+
+        TestResult checkIllegalStateException() {
+            return checkThrown(IllegalStateException.class);
+        }
+
+        TestResult checkThrown(Class<? extends Throwable> t) {
+            if (thrown == null)
+                error("expected exception not thrown: " + t);
+            else if (!t.isAssignableFrom(thrown.getClass()))
+                error("unexpected exception thrown: " + thrown + ";  expected: " + t);
+            return this;
+        }
+
+        TestResult checkClass(String name) {
+            Path p = getOutDir().resolve(name.replace(".", "/") + ".class");
+            if (!Files.exists(p))
+                error("expected class not found: " + name + " (" + p + ")");
+            return this;
+        }
+
+        Path getOutDir() {
+            Iterator<String> iter = args.iterator();
+            while (iter.hasNext()) {
+                if (iter.next().equals("-d")) {
+                    return Paths.get(iter.next());
+                }
+            }
+            return null;
+        }
+    }
+
+    /**
+     * Utility class to simplify the handling of temporarily setting a
+     * new stream for System.out or System.err.
+     */
+    private static class StreamOutput {
+        // functional interface to set a stream.
+        private interface Initializer {
+            void set(PrintStream s);
+        }
+
+        private final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        private final PrintStream ps = new PrintStream(baos);
+        private final PrintStream prev;
+        private final Initializer init;
+
+        StreamOutput(PrintStream s, Initializer init) {
+            prev = s;
+            init.set(ps);
+            this.init = init;
+        }
+
+        String close() {
+            init.set(prev);
+            ps.close();
+            return baos.toString();
+        }
+    }
+
+    List<JavaFileObject> getFiles(String... paths) {
+        List<JavaFileObject> files = new ArrayList<>();
+        for (JavaFileObject f : fm.getJavaFileObjects(paths))
+            files.add(f);
+        return files;
+    }
+
+    String toString(List<JavaFileObject> files) {
+        return files.stream().map(f -> f.getName()).collect(Collectors.toList()).toString();
+    }
+
+    void mkdirs(String path) throws IOException {
+        Files.createDirectories(Paths.get(path));
+    }
+
+    void writeFile(String path, String body) throws IOException {
+        Path p = Paths.get(path);
+        if (p.getParent() != null)
+            Files.createDirectories(p.getParent());
+        try (FileWriter w = new FileWriter(path)) {
+            w.write(body);
+        }
+    }
+
+    String[] join(String[] a, String[] b) {
+        String[] result = new String[a.length + b.length];
+        System.arraycopy(a, 0, result, 0, a.length);
+        System.arraycopy(b, 0, result, a.length, b.length);
+        return result;
+    }
+
+    void error(String message) {
+        out.print(">>>>> ");
+        out.println(message);
+        errors++;
+    }
+
+    StandardJavaFileManager fm =
+            ToolProvider.getSystemJavaCompiler().getStandardFileManager(null, null, null);
+    PrintStream out = System.err;
+    int errors;
+
+}
--- a/langtools/test/tools/javac/profiles/ProfileOptionTest.java	Fri Aug 22 12:25:01 2014 +0200
+++ b/langtools/test/tools/javac/profiles/ProfileOptionTest.java	Fri Aug 22 16:28:16 2014 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2014, 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
@@ -67,7 +67,7 @@
     // ---------- Test cases, invoked reflectively via run. ----------
 
     @Test
-    void testInvalidProfile_CommandLine() throws Exception {
+    void testInvalidProfile_API() throws Exception {
         JavaFileObject fo = new StringJavaFileObject("Test.java", "class Test { }");
         String badName = "foo";
         List<String> opts = Arrays.asList("-profile", badName);
@@ -82,7 +82,7 @@
     }
 
     @Test
-    void testInvalidProfile_API() throws Exception {
+    void testInvalidProfile_CommandLine() throws Exception {
         String badName = "foo";
         String[] opts = { "-profile", badName };
         StringWriter sw = new StringWriter();
@@ -115,10 +115,17 @@
                 opts.add("-Xlint:-options"); // dont warn about no -bootclasspath
                 if (p != Profile.DEFAULT)
                     opts.addAll(Arrays.asList("-profile", p.name));
+
+                IllegalStateException ise;
                 StringWriter sw = new StringWriter();
-                JavacTask task = (JavacTask) javac.getTask(sw, fm, null, opts, null,
-                        Arrays.asList(fo));
-                task.analyze();
+                try {
+                    JavacTask task = (JavacTask) javac.getTask(sw, fm, null, opts, null,
+                            Arrays.asList(fo));
+                    task.analyze();
+                    ise = null;
+                } catch (IllegalStateException e) {
+                    ise = e;
+                }
 
                 // sadly, command line errors are not (yet?) reported to
                 // the diag listener
@@ -129,14 +136,17 @@
                 switch (t) {
                     case JDK1_8:
                     case JDK1_9:
-                        if (!out.isEmpty())
-                            error("unexpected output from compiler");
+                        if (ise != null)
+                            error("unexpected exception from compiler: " + ise);
                         break;
                     default:
-                        if (p != Profile.DEFAULT
-                                && !out.contains("profile " + p.name
+                        if (p == Profile.DEFAULT)
+                            break;
+                        if (ise == null)
+                            error("IllegalStateException not thrown as expected");
+                        else if (!ise.getMessage().contains("profile " + p.name
                                     + " is not valid for target release " + t.name)) {
-                            error("expected message not found");
+                            error("exception not thrown as expected: " + ise);
                         }
                 }
             }
--- a/langtools/test/tools/javac/versions/Versions.java	Fri Aug 22 12:25:01 2014 +0200
+++ b/langtools/test/tools/javac/versions/Versions.java	Fri Aug 22 16:28:16 2014 -0700
@@ -279,7 +279,13 @@
             options, // Iterable<String>
             null,    // Iterable<String> classes
             files);  // Iterable<? extends JavaFileObject>
-        return jctask.call();
+
+        try {
+            return jctask.call();
+        } catch (IllegalStateException e) {
+            System.err.println(e);
+            return false;
+        }
     }