src/share/classes/com/sun/tools/sjavac/server/CompilerThread.java

Thu, 15 Aug 2013 17:24:35 +0200

author
erikj
date
Thu, 15 Aug 2013 17:24:35 +0200
changeset 1953
71b0089b146f
parent 1763
445b8b5ae9f4
child 2413
fe033d997ddf
permissions
-rw-r--r--

8015145: Smartjavac needs more flexibility with linking to sources
Reviewed-by: jjg, ohrstrom

     1 /*
     2  * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    26 package com.sun.tools.sjavac.server;
    28 import java.io.BufferedReader;
    29 import java.io.File;
    30 import java.io.IOException;
    31 import java.io.InputStreamReader;
    32 import java.io.OutputStreamWriter;
    33 import java.io.PrintWriter;
    34 import java.io.StringWriter;
    35 import java.net.Socket;
    36 import java.net.URI;
    37 import java.net.URISyntaxException;
    38 import java.util.ArrayList;
    39 import java.util.Arrays;
    40 import java.util.HashSet;
    41 import java.util.List;
    42 import java.util.Set;
    43 import java.util.Map;
    44 import java.util.concurrent.Future;
    45 import javax.tools.JavaFileManager;
    46 import javax.tools.JavaFileObject;
    47 import javax.tools.StandardJavaFileManager;
    49 import com.sun.tools.javac.util.Context;
    50 import com.sun.tools.javac.util.Log;
    51 import com.sun.tools.javac.util.BaseFileManager;
    52 import com.sun.tools.sjavac.comp.Dependencies;
    53 import com.sun.tools.sjavac.comp.JavaCompilerWithDeps;
    54 import com.sun.tools.sjavac.comp.SmartFileManager;
    55 import com.sun.tools.sjavac.comp.ResolveWithDeps;
    57 /**
    58  * The compiler thread maintains a JavaCompiler instance and
    59  * can receive a request from the client, perform the compilation
    60  * requested and report back the results.
    61  *
    62  *  * <p><b>This is NOT part of any supported API.
    63  * If you write code that depends on this, you do so at your own
    64  * risk.  This code and its internal interfaces are subject to change
    65  * or deletion without notice.</b></p>
    66  */
    67 public class CompilerThread implements Runnable {
    68     private JavacServer javacServer;
    69     private CompilerPool compilerPool;
    70     private List<Future<?>> subTasks;
    72     // Communicating over this socket.
    73     private Socket socket;
    75     // The necessary classes to do a compilation.
    76     private com.sun.tools.javac.api.JavacTool compiler;
    77     private StandardJavaFileManager fileManager;
    78     private BaseFileManager fileManagerBase;
    79     private SmartFileManager smartFileManager;
    80     private Context context;
    82     // If true, then this thread is serving a request.
    83     private boolean inUse = false;
    85     CompilerThread(CompilerPool cp) {
    86         compilerPool = cp;
    87         javacServer = cp.getJavacServer();
    88     }
    90     /**
    91      * Execute a minor task, for example generating bytecodes and writing them to disk,
    92      * that belong to a major compiler thread task.
    93      */
    94     public synchronized void executeSubtask(Runnable r) {
    95         subTasks.add(compilerPool.executeSubtask(this, r));
    96     }
    98     /**
    99      * Count the number of active sub tasks.
   100      */
   101     public synchronized int numActiveSubTasks() {
   102         int c = 0;
   103         for (Future<?> f : subTasks) {
   104             if (!f.isDone() && !f.isCancelled()) {
   105                 c++;
   106             }
   107         }
   108         return c;
   109     }
   111     /**
   112      * Use this socket for the upcoming request.
   113      */
   114     public void setSocket(Socket s) {
   115         socket = s;
   116     }
   118     /**
   119      * Prepare the compiler thread for use. It is not yet started.
   120      * It will be started by the executor service.
   121      */
   122     public synchronized void use() {
   123         assert(!inUse);
   124         inUse = true;
   125         compiler = com.sun.tools.javac.api.JavacTool.create();
   126         fileManager = compiler.getStandardFileManager(null, null, null);
   127         fileManagerBase = (BaseFileManager)fileManager;
   128         smartFileManager = new SmartFileManager(fileManager);
   129         context = new Context();
   130         context.put(JavaFileManager.class, smartFileManager);
   131         ResolveWithDeps.preRegister(context);
   132         JavaCompilerWithDeps.preRegister(context, this);
   133         subTasks = new ArrayList<Future<?>>();
   134     }
   136     /**
   137      * Prepare the compiler thread for idleness.
   138      */
   139     public synchronized void unuse() {
   140         assert(inUse);
   141         inUse = false;
   142         compiler = null;
   143         fileManager = null;
   144         fileManagerBase = null;
   145         smartFileManager = null;
   146         context = null;
   147         subTasks = null;
   148     }
   150     /**
   151      * Expect this key on the next line read from the reader.
   152      */
   153     private static boolean expect(BufferedReader in, String key) throws IOException {
   154         String s = in.readLine();
   155         if (s != null && s.equals(key)) {
   156             return true;
   157         }
   158         return false;
   159     }
   161     // The request identifier, for example GENERATE_NEWBYTECODE
   162     String id = "";
   164     public String currentRequestId() {
   165         return id;
   166     }
   168     PrintWriter stdout;
   169     PrintWriter stderr;
   170     int forcedExitCode = 0;
   172     public void logError(String msg) {
   173         stderr.println(msg);
   174         forcedExitCode = -1;
   175     }
   177     /**
   178      * Invoked by the executor service.
   179      */
   180     public void run() {
   181         // Unique nr that identifies this request.
   182         int thisRequest = compilerPool.startRequest();
   183         long start = System.currentTimeMillis();
   184         int numClasses = 0;
   185         StringBuilder compiledPkgs = new StringBuilder();
   186         use();
   188         PrintWriter out = null;
   189         try {
   190             javacServer.log("<"+thisRequest+"> Connect from "+socket.getRemoteSocketAddress()+" activethreads="+compilerPool.numActiveRequests());
   191             BufferedReader in = new BufferedReader(new InputStreamReader(
   192                                                        socket.getInputStream()));
   193             out = new PrintWriter(new OutputStreamWriter(
   194                                                   socket.getOutputStream()));
   195             if (!expect(in, JavacServer.PROTOCOL_COOKIE_VERSION)) {
   196                 javacServer.log("<"+thisRequest+"> Bad protocol from ip "+socket.getRemoteSocketAddress());
   197                 return;
   198             }
   200             String cookie = in.readLine();
   201             if (cookie == null || !cookie.equals(""+javacServer.getCookie())) {
   202                 javacServer.log("<"+thisRequest+"> Bad cookie from ip "+socket.getRemoteSocketAddress());
   203                 return;
   204             }
   205             if (!expect(in, JavacServer.PROTOCOL_CWD)) {
   206                 return;
   207             }
   208             String cwd = in.readLine();
   209             if (cwd == null)
   210                 return;
   211             if (!expect(in, JavacServer.PROTOCOL_ID)) {
   212                 return;
   213             }
   214             id = in.readLine();
   215             if (id == null)
   216                 return;
   217             if (!expect(in, JavacServer.PROTOCOL_ARGS)) {
   218                 return;
   219             }
   220             ArrayList<String> the_options = new ArrayList<String>();
   221             ArrayList<File> the_classes = new ArrayList<File>();
   222             Iterable<File> path = Arrays.<File> asList(new File(cwd));
   224             for (;;) {
   225                 String l = in.readLine();
   226                 if (l == null)
   227                     return;
   228                 if (l.equals(JavacServer.PROTOCOL_SOURCES_TO_COMPILE))
   229                     break;
   230                 if (l.startsWith("--server:"))
   231                     continue;
   232                 if (!l.startsWith("-") && l.endsWith(".java")) {
   233                     the_classes.add(new File(l));
   234                     numClasses++;
   235                 } else {
   236                     the_options.add(l);
   237                 }
   238                 continue;
   239             }
   241             // Load sources to compile
   242             Set<URI> sourcesToCompile = new HashSet<URI>();
   243             for (;;) {
   244                 String l = in.readLine();
   245                 if (l == null)
   246                     return;
   247                 if (l.equals(JavacServer.PROTOCOL_VISIBLE_SOURCES))
   248                     break;
   249                 try {
   250                     sourcesToCompile.add(new URI(l));
   251                     numClasses++;
   252                 } catch (URISyntaxException e) {
   253                     return;
   254                 }
   255             }
   256             // Load visible sources
   257             Set<URI> visibleSources = new HashSet<URI>();
   258             boolean fix_drive_letter_case =
   259                 System.getProperty("os.name").toLowerCase().startsWith("windows");
   260             for (;;) {
   261                 String l = in.readLine();
   262                 if (l == null)
   263                     return;
   264                 if (l.equals(JavacServer.PROTOCOL_END))
   265                     break;
   266                 try {
   267                     URI u = new URI(l);
   268                     if (fix_drive_letter_case) {
   269                         // Make sure the driver letter is lower case.
   270                         String s = u.toString();
   271                         if (s.startsWith("file:/") &&
   272                             Character.isUpperCase(s.charAt(6))) {
   273                             u = new URI("file:/"+Character.toLowerCase(s.charAt(6))+s.substring(7));
   274                         }
   275                     }
   276                     visibleSources.add(u);
   277                 } catch (URISyntaxException e) {
   278                     return;
   279                 }
   280             }
   282             // A completed request has been received.
   284             // Now setup the actual compilation....
   285             // First deal with explicit source files on cmdline and in at file.
   286             com.sun.tools.javac.util.ListBuffer<JavaFileObject> compilationUnits =
   287                 new com.sun.tools.javac.util.ListBuffer<JavaFileObject>();
   288             for (JavaFileObject i : fileManager.getJavaFileObjectsFromFiles(the_classes)) {
   289                 compilationUnits.append(i);
   290             }
   291             // Now deal with sources supplied as source_to_compile.
   292             com.sun.tools.javac.util.ListBuffer<File> sourcesToCompileFiles =
   293                 new com.sun.tools.javac.util.ListBuffer<File>();
   294             for (URI u : sourcesToCompile) {
   295                 sourcesToCompileFiles.append(new File(u));
   296             }
   297             for (JavaFileObject i : fileManager.getJavaFileObjectsFromFiles(sourcesToCompileFiles)) {
   298                 compilationUnits.append(i);
   299             }
   300             // Log the options to be used.
   301             StringBuilder options = new StringBuilder();
   302             for (String s : the_options) {
   303                 options.append(">").append(s).append("< ");
   304             }
   305             javacServer.log(id+" <"+thisRequest+"> options "+options.toString());
   307             forcedExitCode = 0;
   308             // Create a new logger.
   309             StringWriter stdoutLog = new StringWriter();
   310             StringWriter stderrLog = new StringWriter();
   311             stdout = new PrintWriter(stdoutLog);
   312             stderr = new PrintWriter(stderrLog);
   313             com.sun.tools.javac.main.Main.Result rc = com.sun.tools.javac.main.Main.Result.OK;
   314             try {
   315                 if (compilationUnits.size() > 0) {
   316                     // Bind the new logger to the existing context.
   317                     context.put(Log.outKey, stderr);
   318                     Log.instance(context).setWriter(Log.WriterKind.NOTICE, stdout);
   319                     Log.instance(context).setWriter(Log.WriterKind.WARNING, stderr);
   320                     Log.instance(context).setWriter(Log.WriterKind.ERROR, stderr);
   321                     // Process the options.
   322                     com.sun.tools.javac.api.JavacTool.processOptions(context, smartFileManager, the_options);
   323                     fileManagerBase.setContext(context);
   324                     smartFileManager.setVisibleSources(visibleSources);
   325                     smartFileManager.cleanArtifacts();
   326                     smartFileManager.setLog(stdout);
   327                     Dependencies.instance(context).reset();
   329                     com.sun.tools.javac.main.Main ccompiler = new com.sun.tools.javac.main.Main("javacTask", stderr);
   330                     String[] aa = the_options.toArray(new String[0]);
   332                     // Do the compilation!
   333                     rc = ccompiler.compile(aa, context, compilationUnits.toList(), null);
   335                     while (numActiveSubTasks()>0) {
   336                         try { Thread.sleep(1000); } catch (InterruptedException e) { }
   337                     }
   339                     smartFileManager.flush();
   340                 }
   341             } catch (Exception e) {
   342                 stderr.println(e.getMessage());
   343                 forcedExitCode = -1;
   344             }
   346             // Send the response..
   347             out.println(JavacServer.PROTOCOL_STDOUT);
   348             out.print(stdoutLog);
   349             out.println(JavacServer.PROTOCOL_STDERR);
   350             out.print(stderrLog);
   351             // The compilation is complete! And errors will have already been printed on out!
   352             out.println(JavacServer.PROTOCOL_PACKAGE_ARTIFACTS);
   353             Map<String,Set<URI>> pa = smartFileManager.getPackageArtifacts();
   354             for (String aPkgName : pa.keySet()) {
   355                 out.println("+"+aPkgName);
   356                 Set<URI> as = pa.get(aPkgName);
   357                 for (URI a : as) {
   358                     out.println(" "+a.toString());
   359                 }
   360             }
   361             Dependencies deps = Dependencies.instance(context);
   362             out.println(JavacServer.PROTOCOL_PACKAGE_DEPENDENCIES);
   363             Map<String,Set<String>> pd = deps.getDependencies();
   364             for (String aPkgName : pd.keySet()) {
   365                 out.println("+"+aPkgName);
   366                 Set<String> ds = pd.get(aPkgName);
   367                     // Everything depends on java.lang
   368                     if (!ds.contains(":java.lang")) ds.add(":java.lang");
   369                 for (String d : ds) {
   370                     out.println(" "+d);
   371                 }
   372             }
   373             out.println(JavacServer.PROTOCOL_PACKAGE_PUBLIC_APIS);
   374             Map<String,String> pp = deps.getPubapis();
   375             for (String aPkgName : pp.keySet()) {
   376                 out.println("+"+aPkgName);
   377                 String ps = pp.get(aPkgName);
   378                 // getPubapis added a space to each line!
   379                 out.println(ps);
   380                 compiledPkgs.append(aPkgName+" ");
   381             }
   382             out.println(JavacServer.PROTOCOL_SYSINFO);
   383             out.println("num_cores=" + Runtime.getRuntime().availableProcessors());
   384             out.println("max_memory=" + Runtime.getRuntime().maxMemory());
   385             out.println(JavacServer.PROTOCOL_RETURN_CODE);
   387             // Errors from sjavac that affect compilation status!
   388             int rcv = rc.exitCode;
   389             if (rcv == 0 && forcedExitCode != 0) {
   390                 rcv = forcedExitCode;
   391             }
   392             out.println("" + rcv);
   393             out.println(JavacServer.PROTOCOL_END);
   394             out.flush();
   395         } catch (IOException e) {
   396             e.printStackTrace();
   397         } finally {
   398             try {
   399                 if (out != null) out.close();
   400                 if (!socket.isClosed()) {
   401                     socket.close();
   402                 }
   403                 socket = null;
   404             } catch (Exception e) {
   405                 javacServer.log("ERROR "+e);
   406                 e.printStackTrace();
   407             }
   408             compilerPool.stopRequest();
   409             long duration = System.currentTimeMillis()-start;
   410             javacServer.addBuildTime(duration);
   411             float classpersec = ((float)numClasses)*(((float)1000.0)/((float)duration));
   412             javacServer.log(id+" <"+thisRequest+"> "+compiledPkgs+" duration " + duration+ " ms    num_classes="+numClasses+
   413                              "     classpersec="+classpersec+" subtasks="+subTasks.size());
   414             javacServer.flushLog();
   415             unuse();
   416             compilerPool.returnCompilerThread(this);
   417         }
   418     }
   419 }

mercurial