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/IceCompiler.cpp b/src/IceCompiler.cpp
new file mode 100644
index 0000000..47f1ba4
--- /dev/null
+++ b/src/IceCompiler.cpp
@@ -0,0 +1,164 @@
+//===- subzero/src/IceCompiler.cpp - Driver for bitcode translation -------===//
+//
+//                        The Subzero Code Generator
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a driver for translating PNaCl bitcode into native code.
+// It can either directly parse the binary bitcode file, or use LLVM routines to
+// parse a textual bitcode file into LLVM IR and then convert LLVM IR into ICE.
+// In either case, the high-level ICE is then compiled down to native code, as
+// either an ELF object file or a textual asm file.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IRReader/IRReader.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/StreamingMemoryObject.h"
+
+#include "IceCfg.h"
+#include "IceClFlags.h"
+#include "IceClFlagsExtra.h"
+#include "IceCompiler.h"
+#include "IceConverter.h"
+#include "IceELFObjectWriter.h"
+#include "PNaClTranslator.h"
+namespace Ice {
+
+namespace {
+
+struct {
+  const char *FlagName;
+  int FlagValue;
+} ConditionalBuildAttributes[] = {{"dump", ALLOW_DUMP},
+                                  {"disable_ir_gen", ALLOW_DISABLE_IR_GEN},
+                                  {"llvm_cl", ALLOW_LLVM_CL},
+                                  {"llvm_ir", ALLOW_LLVM_IR},
+                                  {"llvm_ir_as_input", ALLOW_LLVM_IR_AS_INPUT},
+                                  {"minimal_build", ALLOW_MINIMAL_BUILD},
+                                  {"browser_mode", PNACL_BROWSER_TRANSLATOR}};
+
+// Validates values of build attributes. Prints them to Stream if
+// Stream is non-null.
+void ValidateAndGenerateBuildAttributes(const ClFlags &Flags, Ostream *Stream) {
+  if (Stream)
+    *Stream << Flags.getTargetArch() << "\n";
+
+  for (size_t i = 0; i < llvm::array_lengthof(ConditionalBuildAttributes);
+       ++i) {
+    switch (ConditionalBuildAttributes[i].FlagValue) {
+    case 0:
+      if (Stream)
+        *Stream << "no_" << ConditionalBuildAttributes[i].FlagName << "\n";
+      break;
+    case 1:
+      if (Stream)
+        *Stream << "allow_" << ConditionalBuildAttributes[i].FlagName << "\n";
+      break;
+    default: {
+      std::string Buffer;
+      llvm::raw_string_ostream StrBuf(Buffer);
+      StrBuf << "Flag " << ConditionalBuildAttributes[i].FlagName
+             << " must be defined as 0/1. Found: "
+             << ConditionalBuildAttributes[i].FlagValue;
+      llvm::report_fatal_error(StrBuf.str());
+    }
+    }
+  }
+}
+
+} // end of anonymous namespace
+
+void Compiler::run(const Ice::ClFlagsExtra &ExtraFlags, GlobalContext &Ctx,
+                   std::unique_ptr<llvm::DataStreamer> &&InputStream) {
+  ValidateAndGenerateBuildAttributes(
+      Ctx.getFlags(),
+      ExtraFlags.getGenerateBuildAtts() ? &Ctx.getStrDump() : nullptr);
+  if (ExtraFlags.getGenerateBuildAtts())
+    return Ctx.getErrorStatus()->assign(EC_None);
+
+  if (!ALLOW_DISABLE_IR_GEN && Ctx.getFlags().getDisableIRGeneration()) {
+    Ctx.getStrDump() << "Error: Build doesn't allow --no-ir-gen when not "
+                     << "ALLOW_DISABLE_IR_GEN!\n";
+    return Ctx.getErrorStatus()->assign(EC_Args);
+  }
+
+  // Force -build-on-read=0 for .ll files.
+  const std::string LLSuffix = ".ll";
+  const IceString &IRFilename = ExtraFlags.getIRFilename();
+  bool BuildOnRead = ExtraFlags.getBuildOnRead();
+  if (ALLOW_LLVM_IR_AS_INPUT && IRFilename.length() >= LLSuffix.length() &&
+      IRFilename.compare(IRFilename.length() - LLSuffix.length(),
+                         LLSuffix.length(), LLSuffix) == 0)
+    BuildOnRead = false;
+
+  TimerMarker T(Ice::TimerStack::TT_szmain, &Ctx);
+
+  if (Ctx.getFlags().getOutFileType() == FT_Elf) {
+    TimerMarker T1(Ice::TimerStack::TT_emit, &Ctx);
+    Ctx.getObjectWriter()->writeInitialELFHeader();
+  }
+
+  Ctx.startWorkerThreads();
+
+  std::unique_ptr<Translator> Translator;
+  if (BuildOnRead) {
+    std::unique_ptr<PNaClTranslator> PTranslator(new PNaClTranslator(&Ctx));
+    std::unique_ptr<llvm::StreamingMemoryObject> MemObj(
+        new llvm::StreamingMemoryObjectImpl(InputStream.release()));
+    PTranslator->translate(IRFilename, std::move(MemObj));
+    Translator.reset(PTranslator.release());
+  } else if (ALLOW_LLVM_IR) {
+    if (PNACL_BROWSER_TRANSLATOR) {
+      Ctx.getStrDump()
+          << "non BuildOnRead is not supported w/ PNACL_BROWSER_TRANSLATOR\n";
+      return Ctx.getErrorStatus()->assign(EC_Args);
+    }
+    // Parse the input LLVM IR file into a module.
+    llvm::SMDiagnostic Err;
+    TimerMarker T1(Ice::TimerStack::TT_parse, &Ctx);
+    llvm::raw_ostream *Verbose =
+        ExtraFlags.getLLVMVerboseErrors() ? &llvm::errs() : nullptr;
+    std::unique_ptr<llvm::Module> Mod =
+        NaClParseIRFile(IRFilename, ExtraFlags.getInputFileFormat(), Err,
+                        Verbose, llvm::getGlobalContext());
+    if (!Mod) {
+      Err.print(ExtraFlags.getAppName().c_str(), llvm::errs());
+      return Ctx.getErrorStatus()->assign(EC_Bitcode);
+    }
+
+    std::unique_ptr<Converter> Converter(new class Converter(Mod.get(), &Ctx));
+    Converter->convertToIce();
+    Translator.reset(Converter.release());
+  } else {
+    Ctx.getStrDump() << "Error: Build doesn't allow LLVM IR, "
+                     << "--build-on-read=0 not allowed\n";
+    return Ctx.getErrorStatus()->assign(EC_Args);
+  }
+
+  Ctx.waitForWorkerThreads();
+  Translator->transferErrorCode();
+  Translator->emitConstants();
+
+  if (Ctx.getFlags().getOutFileType() == FT_Elf) {
+    TimerMarker T1(Ice::TimerStack::TT_emit, &Ctx);
+    Ctx.getObjectWriter()->setUndefinedSyms(Ctx.getConstantExternSyms());
+    Ctx.getObjectWriter()->writeNonUserSections();
+  }
+  if (Ctx.getFlags().getSubzeroTimingEnabled())
+    Ctx.dumpTimers();
+  if (Ctx.getFlags().getTimeEachFunction()) {
+    const bool DumpCumulative = false;
+    Ctx.dumpTimers(GlobalContext::TSK_Funcs, DumpCumulative);
+  }
+  const bool FinalStats = true;
+  Ctx.dumpStats("_FINAL_", FinalStats);
+}
+
+} // end of namespace Ice