private void doCompile(@NotNull final ModuleChunk chunk, @NotNull String outputDir)
      throws IOException {
    myCompileContext.getProgressIndicator().checkCanceled();

    if (ApplicationManager.getApplication()
        .runReadAction(
            new Computable<Boolean>() {
              public Boolean compute() {
                return chunk.getFilesToCompile().isEmpty() ? Boolean.TRUE : Boolean.FALSE;
              }
            })
        .booleanValue()) {
      return; // should not invoke javac with empty sources list
    }

    int exitValue = 0;
    try {
      final Process process = myCompiler.launchProcess(chunk, outputDir, myCompileContext);
      final long compilationStart = System.currentTimeMillis();
      final ClassParsingThread classParsingThread =
          new ClassParsingThread(isJdk6(JavaSdkUtil.getSdkForCompilation(chunk)), outputDir);
      final Future<?> classParsingThreadFuture =
          ApplicationManager.getApplication().executeOnPooledThread(classParsingThread);

      OutputParser errorParser = myCompiler.createErrorParser(outputDir, process);
      CompilerParsingThread errorParsingThread =
          errorParser == null
              ? null
              : new SynchedCompilerParsing(
                  process,
                  myCompileContext,
                  errorParser,
                  classParsingThread,
                  true,
                  errorParser.isTrimLines());
      Future<?> errorParsingThreadFuture = null;
      if (errorParsingThread != null) {
        errorParsingThreadFuture =
            ApplicationManager.getApplication().executeOnPooledThread(errorParsingThread);
      }

      OutputParser outputParser = myCompiler.createOutputParser(outputDir);
      CompilerParsingThread outputParsingThread =
          outputParser == null
              ? null
              : new SynchedCompilerParsing(
                  process,
                  myCompileContext,
                  outputParser,
                  classParsingThread,
                  false,
                  outputParser.isTrimLines());
      Future<?> outputParsingThreadFuture = null;
      if (outputParsingThread != null) {
        outputParsingThreadFuture =
            ApplicationManager.getApplication().executeOnPooledThread(outputParsingThread);
      }

      try {
        exitValue = process.waitFor();
      } catch (InterruptedException e) {
        process.destroy();
        exitValue = process.exitValue();
      } catch (Error e) {
        process.destroy();
        exitValue = process.exitValue();
        throw e;
      } finally {
        if (CompileDriver.ourDebugMode) {
          System.out.println("Compiler exit code is " + exitValue);
        }
        if (errorParsingThread != null) {
          errorParsingThread.setProcessTerminated(true);
        }
        if (outputParsingThread != null) {
          outputParsingThread.setProcessTerminated(true);
        }
        joinThread(errorParsingThreadFuture);
        joinThread(outputParsingThreadFuture);
        classParsingThread.stopParsing();
        joinThread(classParsingThreadFuture);

        registerParsingException(outputParsingThread);
        registerParsingException(errorParsingThread);
        assert outputParsingThread == null || !outputParsingThread.processing;
        assert errorParsingThread == null || !errorParsingThread.processing;
        assert classParsingThread == null || !classParsingThread.processing;
      }
    } finally {
      compileFinished(exitValue, chunk, outputDir);
      myModuleName = null;
    }
  }