Refactor Subzero initialization and add a browser callback handler.

Handlers are represented as a "compile server" even though
right now it can really only handle a single
compile request.

Then there can be a commandline-based server and a
browser-based server. This server takes over the main
thread. In the browser-based case the server can block,
waiting on bytes to be pushed. This becomes a producer of
bitcode bytes.

The original main thread which did bitcode reading is now
shifted to yet another worker thread, which is then the
consumer of bitcode bytes.

This uses an IRT interface for listening to messages
from the browser:
https://codereview.chromium.org/984713003/

TEST=Build the IRT core nexe w/ the above patch and compile w/ something like:

echo """
readwrite_file objfile /tmp/temp.nexe---gcc.opt.stripped.pexe---.o
rpc StreamInitWithSplit i(4) h(objfile) h(invalid) h(invalid) h(invalid) h(invalid) h(invalid) h(invalid) h(invalid) h(invalid) h(invalid) h(invalid) h(invalid) h(invalid) h(invalid) h(invalid) h(invalid) C(4,-O2\x00) * s()
stream_file /usr/local/google/home/jvoung/pexe_tests/gcc.opt.stripped.pexe 65536 1000000000
rpc StreamEnd * i() s() s() s()
echo "pnacl-sz complete"
""" | scons-out/opt-linux-x86-32/staging/sel_universal \
    -a -B scons-out/nacl_irt-x86-32/staging/irt_core.nexe \
    --abort_on_error \
    -- toolchain/linux_x86/pnacl_translator/translator/x86-32/bin/pnacl-sz.nexe

echo """
readwrite_file nexefile /tmp/temp.nexe.tmp
readonly_file objfile0 /tmp/temp.nexe---gcc.opt.stripped.pexe---.o
rpc RunWithSplit i(1) h(objfile0) h(invalid) h(invalid) h(invalid) h(invalid) h(invalid) h(invalid) h(invalid) h(invalid) h(invalid) h(invalid) h(invalid) h(invalid) h(invalid) h(invalid) h(invalid) h(nexefile) *
echo "ld complete"
""" | /usr/local/google/home/nacl3/native_client/scons-out/opt-linux-x86-32/staging/sel_universal \
    --abort_on_error \
    -a -B \
    scons-out/nacl_irt-x86-32/staging/irt_core.nexe \
    -E NACL_IRT_OPEN_RESOURCE_BASE=toolchain/linux_x86/pnacl_translator/translator/x86-32/lib/ \
    -E NACL_IRT_OPEN_RESOURCE_REMAP=libpnacl_irt_shim.a:libpnacl_irt_shim_dummy.a \
    -- toolchain/linux_x86/pnacl_translator/translator/x86-32/bin/ld.nexe

BUG= https://code.google.com/p/nativeclient/issues/detail?id=4091
R=kschimpf@google.com, stichnot@chromium.org

Review URL: https://codereview.chromium.org/997773002
diff --git a/src/IceCompileServer.cpp b/src/IceCompileServer.cpp
new file mode 100644
index 0000000..86ebb0b
--- /dev/null
+++ b/src/IceCompileServer.cpp
@@ -0,0 +1,113 @@
+//===- subzero/src/IceCompileServer.cpp - Compile server ------------------===//
+//
+//                        The Subzero Code Generator
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the basic commandline-based compile server.
+//
+//===----------------------------------------------------------------------===//
+
+#include <fstream>
+#include <iostream>
+#include <thread>
+
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/raw_os_ostream.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/StreamingMemoryObject.h"
+
+#include "IceClFlags.h"
+#include "IceClFlagsExtra.h"
+#include "IceCompileServer.h"
+#include "IceELFStreamer.h"
+#include "IceGlobalContext.h"
+
+namespace Ice {
+
+namespace {
+
+std::unique_ptr<Ostream> getStream(const IceString &Filename) {
+  std::ofstream Ofs;
+  if (Filename != "-") {
+    Ofs.open(Filename.c_str(), std::ofstream::out);
+    return std::unique_ptr<Ostream>(new llvm::raw_os_ostream(Ofs));
+  } else {
+    return std::unique_ptr<Ostream>(new llvm::raw_os_ostream(std::cout));
+  }
+}
+
+ErrorCodes getReturnValue(const Ice::ClFlagsExtra &Flags, ErrorCodes Val) {
+  if (Flags.getAlwaysExitSuccess())
+    return EC_None;
+  return Val;
+}
+
+} // end of anonymous namespace
+
+void CLCompileServer::run() {
+  ClFlags::parseFlags(argc, argv);
+  ClFlags Flags;
+  ClFlagsExtra ExtraFlags;
+  ClFlags::getParsedClFlags(Flags);
+  ClFlags::getParsedClFlagsExtra(ExtraFlags);
+
+  std::unique_ptr<Ostream> Ls = getStream(ExtraFlags.getLogFilename());
+  Ls->SetUnbuffered();
+  std::unique_ptr<Ostream> Os;
+  std::unique_ptr<ELFStreamer> ELFStr;
+  switch (Flags.getOutFileType()) {
+  case FT_Elf: {
+    if (ExtraFlags.getOutputFilename() == "-") {
+      *Ls << "Error: writing binary ELF to stdout is unsupported\n";
+      return transferErrorCode(getReturnValue(ExtraFlags, Ice::EC_Args));
+    }
+    std::error_code EC;
+    std::unique_ptr<llvm::raw_fd_ostream> FdOs(new llvm::raw_fd_ostream(
+        ExtraFlags.getOutputFilename(), EC, llvm::sys::fs::F_None));
+    if (EC) {
+      *Ls << "Failed to open output file: " << ExtraFlags.getOutputFilename()
+          << ":\n" << EC.message() << "\n";
+      return transferErrorCode(getReturnValue(ExtraFlags, Ice::EC_Args));
+    }
+    ELFStr.reset(new ELFStreamer(*FdOs.get()));
+    Os.reset(FdOs.release());
+    // NaCl sets st_blksize to 0, and LLVM uses that to pick the
+    // default preferred buffer size. Set to something non-zero.
+    Os->SetBufferSize(1 << 14);
+  } break;
+  case FT_Asm:
+  case FT_Iasm: {
+    Os = getStream(ExtraFlags.getOutputFilename());
+    Os->SetUnbuffered();
+  } break;
+  }
+
+  IceString StrError;
+  std::unique_ptr<llvm::DataStreamer> InputStream(
+      llvm::getDataFileStreamer(ExtraFlags.getIRFilename(), &StrError));
+  if (!StrError.empty() || !InputStream) {
+    llvm::SMDiagnostic Err(ExtraFlags.getIRFilename(),
+                           llvm::SourceMgr::DK_Error, StrError);
+    Err.print(ExtraFlags.getAppName().c_str(), *Ls);
+    return transferErrorCode(getReturnValue(ExtraFlags, Ice::EC_Bitcode));
+  }
+
+  Ctx.reset(new GlobalContext(Ls.get(), Os.get(), ELFStr.get(), Flags));
+  if (Ctx->getFlags().getNumTranslationThreads() != 0) {
+    std::thread CompileThread([this, &ExtraFlags, &InputStream]() {
+      Ctx->initParserThread();
+      getCompiler().run(ExtraFlags, *Ctx.get(), std::move(InputStream));
+    });
+    CompileThread.join();
+  } else {
+    getCompiler().run(ExtraFlags, *Ctx.get(), std::move(InputStream));
+  }
+  transferErrorCode(getReturnValue(
+      ExtraFlags, static_cast<ErrorCodes>(Ctx->getErrorStatus()->value())));
+}
+
+} // end of namespace Ice