From 17ca379de22cdae97111e735812e387ca3a560e9 Mon Sep 17 00:00:00 2001 From: Ilya Chernikov Date: Sun, 6 Sep 2015 13:53:38 +0200 Subject: [PATCH] Refactoring startup and shutdown, refactoring service implementation, implementing error and info reporting to compiler output, idle autoshutdown mechanisms, fixing TargetId serializability, some other refactoring Fixing stream to log handler (by removing non-working optimization), fixing idle time calculation, reporting refactorings Original commit: c4719175f9bce0b235645d6c311219f60ed69ef3 --- .../compilerRunner/KotlinCompilerRunner.java | 131 +++++++++++------- 1 file changed, 83 insertions(+), 48 deletions(-) diff --git a/jps/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/KotlinCompilerRunner.java b/jps/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/KotlinCompilerRunner.java index 36f347dfb71..e22c84941b6 100644 --- a/jps/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/KotlinCompilerRunner.java +++ b/jps/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/KotlinCompilerRunner.java @@ -27,12 +27,17 @@ import org.jetbrains.kotlin.cli.common.ExitCode; import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments; import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments; import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments; +import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation; +import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity; import org.jetbrains.kotlin.cli.common.messages.MessageCollector; import org.jetbrains.kotlin.cli.common.messages.MessageCollectorUtil; import org.jetbrains.kotlin.config.CompilerSettings; import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache; import org.jetbrains.kotlin.modules.TargetId; import org.jetbrains.kotlin.rmi.*; +import org.jetbrains.kotlin.rmi.kotlinr.DaemonReportCategory; +import org.jetbrains.kotlin.rmi.kotlinr.DaemonReportMessage; +import org.jetbrains.kotlin.rmi.kotlinr.DaemonReportingTargets; import org.jetbrains.kotlin.rmi.kotlinr.KotlinCompilerClient; import org.jetbrains.kotlin.utils.UtilsPackage; @@ -89,6 +94,24 @@ public class KotlinCompilerRunner { incrementalCaches); } + private static void ProcessCompilerOutput( + MessageCollector messageCollector, + OutputItemsCollector collector, + ByteArrayOutputStream stream, + String exitCode + ) { + BufferedReader reader = new BufferedReader(new StringReader(stream.toString())); + CompilerOutputParser.parseCompilerMessagesFromReader(messageCollector, reader, collector); + + if (INTERNAL_ERROR.equals(exitCode)) { + reportInternalCompilerError(messageCollector); + } + } + + private static void reportInternalCompilerError(MessageCollector messageCollector) { + messageCollector.report(ERROR, "Compiler terminated with internal error", NO_LOCATION); + } + private static void runCompiler( String compilerClassName, CommonCompilerArguments arguments, @@ -97,29 +120,6 @@ public class KotlinCompilerRunner { OutputItemsCollector collector, CompilerEnvironment environment, Map incrementalCaches - ) { - ByteArrayOutputStream stream = new ByteArrayOutputStream(); - PrintStream out = new PrintStream(stream); - - String exitCode = execCompiler(compilerClassName, arguments, additionalArguments, environment, incrementalCaches, out, messageCollector); - - BufferedReader reader = new BufferedReader(new StringReader(stream.toString())); - CompilerOutputParser.parseCompilerMessagesFromReader(messageCollector, reader, collector); - - if (INTERNAL_ERROR.equals(exitCode)) { - messageCollector.report(ERROR, "Compiler terminated with internal error", NO_LOCATION); - } - } - - @NotNull - private static String execCompiler( - String compilerClassName, - CommonCompilerArguments arguments, - String additionalArguments, - CompilerEnvironment environment, - Map incrementalCaches, - PrintStream out, - MessageCollector messageCollector ) { try { messageCollector.report(INFO, "Using kotlin-home = " + environment.getKotlinPaths().getHomePath(), NO_LOCATION); @@ -129,38 +129,73 @@ public class KotlinCompilerRunner { String[] argsArray = ArrayUtil.toStringArray(argumentsList); - // trying the daemon first - if (incrementalCaches != null && RmiPackage.isDaemonEnabled()) { - File libPath = CompilerRunnerUtil.getLibPath(environment.getKotlinPaths(), messageCollector); - // TODO: it may be a good idea to cache the compilerId, since making it means calculating digest over jar(s) and if \\ - // the lifetime of JPS process is small anyway, we can neglect the probability of changed compiler - CompilerId compilerId = CompilerId.makeCompilerId(new File(libPath, "kotlin-compiler.jar")); - DaemonOptions daemonOptions = RmiPackage.configureDaemonOptions(); - DaemonJVMOptions daemonJVMOptions = RmiPackage.configureDaemonLaunchingOptions(true); - // TODO: find proper stream to report daemon connection progress - CompileService daemon = KotlinCompilerClient.Companion.connectToCompileService(compilerId, daemonJVMOptions, daemonOptions, System.out, true, true); - if (daemon != null) { - Integer res = KotlinCompilerClient.Companion.incrementalCompile(daemon, argsArray, incrementalCaches, out); - return res.toString(); - } + if (!tryCompileWithDaemon(messageCollector, collector, environment, incrementalCaches, argsArray)) { + // otherwise fallback to in-process + + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + PrintStream out = new PrintStream(stream); + + Object rc = CompilerRunnerUtil.invokeExecMethod( compilerClassName, argsArray, environment, messageCollector, out); + + // exec() returns an ExitCode object, class of which is loaded with a different class loader, + // so we take it's contents through reflection + ProcessCompilerOutput(messageCollector, collector, stream, getReturnCodeFromObject(rc)); } - - // otherwise fallback to in-process - - Object rc = CompilerRunnerUtil.invokeExecMethod( - compilerClassName, argsArray, environment, messageCollector, out - ); - - // exec() returns an ExitCode object, class of which is loaded with a different class loader, - // so we take it's contents through reflection - return getReturnCodeFromObject(rc); } catch (Throwable e) { MessageCollectorUtil.reportException(messageCollector, e); - return INTERNAL_ERROR; + reportInternalCompilerError(messageCollector); } } + private static boolean tryCompileWithDaemon( + MessageCollector messageCollector, + OutputItemsCollector collector, + CompilerEnvironment environment, + Map incrementalCaches, + String[] argsArray + ) throws IOException { + if (incrementalCaches != null && RmiPackage.isDaemonEnabled()) { + File libPath = CompilerRunnerUtil.getLibPath(environment.getKotlinPaths(), messageCollector); + // TODO: it may be a good idea to cache the compilerId, since making it means calculating digest over jar(s) and if \\ + // the lifetime of JPS process is small anyway, we can neglect the probability of changed compiler + CompilerId compilerId = CompilerId.makeCompilerId(new File(libPath, "kotlin-compiler.jar")); + DaemonOptions daemonOptions = RmiPackage.configureDaemonOptions(); + DaemonJVMOptions daemonJVMOptions = RmiPackage.configureDaemonJVMOptions(true); + + ArrayList daemonReportMessages = new ArrayList(); + + CompileService daemon = KotlinCompilerClient.Companion.connectToCompileService(compilerId, daemonJVMOptions, daemonOptions, new DaemonReportingTargets(null, daemonReportMessages), true, true); + + for (DaemonReportMessage msg: daemonReportMessages) { + if (msg.getCategory() == DaemonReportCategory.EXCEPTION && daemon == null) { + messageCollector.report(CompilerMessageSeverity.INFO, + "Falling back to compilation without daemon due to error: " + msg.getMessage(), + CompilerMessageLocation.NO_LOCATION); + } + else { + messageCollector.report(CompilerMessageSeverity.INFO, msg.getMessage(), CompilerMessageLocation.NO_LOCATION); + } + } + + if (daemon != null) { + ByteArrayOutputStream compilerOut = new ByteArrayOutputStream(); + ByteArrayOutputStream daemonOut = new ByteArrayOutputStream(); + + Integer res = KotlinCompilerClient.Companion.incrementalCompile(daemon, argsArray, incrementalCaches, compilerOut, daemonOut); + + ProcessCompilerOutput(messageCollector, collector, compilerOut, res.toString()); + BufferedReader reader = new BufferedReader(new StringReader(daemonOut.toString())); + String line = null; + while ((line = reader.readLine()) != null) { + messageCollector.report(CompilerMessageSeverity.INFO, line, CompilerMessageLocation.NO_LOCATION); + } + return true; + } + } + return false; + } + @NotNull private static String getReturnCodeFromObject(@Nullable Object rc) throws Exception { if (rc == null) {