Index: src/IceBrowserCompileServer.cpp |
diff --git a/src/IceBrowserCompileServer.cpp b/src/IceBrowserCompileServer.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..911b491eff91564005b07ae6c48a0615bf2c3386 |
--- /dev/null |
+++ b/src/IceBrowserCompileServer.cpp |
@@ -0,0 +1,165 @@ |
+//===- subzero/src/IceBrowserCompileServer.cpp - Browser Compile server ---===// |
Jim Stichnoth
2015/03/25 16:34:06
lowercase compile?
jvoung (off chromium)
2015/03/25 18:14:35
Done.
|
+// |
+// 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 browser-based compile server. |
+// |
+//===----------------------------------------------------------------------===// |
+ |
+// Can only compile this with the NaCl compiler (needs irt.h, and the |
+// unsandboxed LLVM build using the trusted compiler does not have irt.h). |
+#if PNACL_BROWSER_TRANSLATOR |
+ |
+#include <argz.h> |
+#include <cstring> |
+#include <cstdlib> |
+#include <irt.h> |
+#include <irt_dev.h> |
+#include <thread> |
+ |
+#include "llvm/Support/QueueStreamer.h" |
+ |
+#include "IceBrowserCompileServer.h" |
+ |
+namespace Ice { |
+ |
+// Create C wrappers around callback handlers for the IRT interface. |
+namespace { |
+ |
+BrowserCompileServer *gCompileServer; |
+struct nacl_irt_private_pnacl_translator_compile gIRTFuncs; |
+ |
+void getIRTInterfaces() { |
+ size_t QueryResult = |
+ nacl_interface_query(NACL_IRT_PRIVATE_PNACL_TRANSLATOR_COMPILE_v0_1, |
+ &gIRTFuncs, sizeof(gIRTFuncs)); |
+ if (QueryResult != sizeof(gIRTFuncs)) |
+ llvm::report_fatal_error("Failed to get translator_subzero IRT interface"); |
Jim Stichnoth
2015/03/25 16:34:06
Is "translator_subzero" still an accurate descript
jvoung (off chromium)
2015/03/25 18:14:35
Done.
|
+} |
+ |
+int onInitCallback(uint32_t NumThreads, int *ObjFileFDs, size_t ObjFileFDCount, |
+ const char *CmdFlags, size_t CmdFlagsLen) { |
+ if (ObjFileFDCount < 1) { |
+ llvm::errs() << "Invalid number of FDs for onInitCallback " |
+ << ObjFileFDCount << "\n"; |
+ return 1; |
+ } |
+ int ObjFileFD = ObjFileFDs[0]; |
+ if (ObjFileFD < 0) { |
+ llvm::errs() << "Invalid number of FD given for onInitCallback " |
+ << ObjFileFD << "\n"; |
+ return 1; |
+ } |
+ // CmdFlags is a caller owned string, so we make copies. |
+ std::vector<char *> CmdFlagList; |
+ // Push some dummy argument for the program name to satisfy |
+ // the argument parser. |
+ CmdFlagList.push_back(strdup("pnacl-sz")); |
+ const char *NextEntry = CmdFlags; |
+ while (NextEntry != nullptr && CmdFlagsLen) { |
+ CmdFlagList.push_back(strdup(NextEntry)); |
+ // re: const cast -- the string pointed-to by each "NextEntry" is |
+ // only used temporarily by getParsedFlags(), and we make a |
+ // copy anyway. |
+ NextEntry = argz_next(const_cast<char *>(CmdFlags), CmdFlagsLen, NextEntry); |
+ } |
+ // Make an argv array from the CmdFlagList, parse and then free. |
+ size_t argc = CmdFlagList.size(); |
+ char **argv = new char *[argc + 1]; |
+ for (size_t i = 0; i < argc; ++i) |
+ argv[i] = CmdFlagList[i]; |
+ argv[argc] = nullptr; |
+ gCompileServer->getParsedFlags(NumThreads, argc, argv); |
+ for (size_t i = 0; i < argc; ++i) |
+ free(argv[i]); |
+ delete[] argv; |
+ gCompileServer->startCompileThread(ObjFileFD); |
+ return 0; |
+} |
+ |
+int onDataCallback(unsigned char *Data, size_t NumBytes) { |
+ return gCompileServer->pushInputBytes(Data, NumBytes) ? 1 : 0; |
+} |
+ |
+int onEndCallback() { |
+ gCompileServer->endInputStream(); |
+ gCompileServer->waitForCompileThread(); |
+ // TODO(jvoung): Also return an error string, and UMA data. |
+ // Set up a report_fatal_error handler to grab that string. |
+ return gCompileServer->getErrorCode().value(); |
+} |
+ |
+struct irt_pnacl_compile_funcs SubzeroCallbacks { |
+ &onInitCallback, &onDataCallback, &onEndCallback |
+}; |
+ |
+std::unique_ptr<llvm::raw_fd_ostream> getOutputStream(int FD) { |
+ if (FD <= 0) |
+ llvm::report_fatal_error("Invalid output FD"); |
+ const bool CloseOnDtor = true; |
+ const bool Unbuffered = false; |
+ return std::unique_ptr<llvm::raw_fd_ostream>( |
+ new llvm::raw_fd_ostream(FD, CloseOnDtor, Unbuffered)); |
+} |
+ |
+} // end of anonymous namespace |
+ |
+BrowserCompileServer::~BrowserCompileServer() {} |
+ |
+void BrowserCompileServer::run() { |
+ gCompileServer = this; |
+ // TODO(jvoung): make a useful fatal error handler that can |
+ // exit all *worker* threads, keep the server thread alive, |
+ // and be able to handle a server request for the last error string. |
+ getIRTInterfaces(); |
+ gIRTFuncs.serve_translate_request(&SubzeroCallbacks); |
+} |
+ |
+void BrowserCompileServer::getParsedFlags(uint32_t NumThreads, int argc, |
+ char **argv) { |
+ ClFlags::parseFlags(argc, argv); |
+ ClFlags::getParsedClFlags(Flags); |
+ ClFlags::getParsedClFlagsExtra(ExtraFlags); |
+ // Set some defaults which aren't specified via the argv string. |
+ Flags.setNumTranslationThreads(NumThreads); |
+ Flags.setUseSandboxing(true); |
+ Flags.setOutFileType(FT_Elf); |
+ // TODO(jvoung): allow setting different target arches. |
+ Flags.setTargetArch(Target_X8632); |
+ ExtraFlags.setBuildOnRead(true); |
+ ExtraFlags.setInputFileFormat(llvm::PNaClFormat); |
+} |
+ |
+bool BrowserCompileServer::pushInputBytes(unsigned char *Data, |
+ size_t NumBytes) { |
+ return InputStream->PutBytes(Data, NumBytes) != NumBytes; |
+} |
+ |
+void BrowserCompileServer::endInputStream() { InputStream->SetDone(); } |
+ |
+void BrowserCompileServer::startCompileThread(int ObjFD) { |
+ InputStream = new llvm::QueueStreamer(); |
+ LogStream = getOutputStream(STDOUT_FILENO); |
+ LogStream->SetUnbuffered(); |
+ EmitStream = getOutputStream(ObjFD); |
+ EmitStream->SetBufferSize(1 << 14); |
+ ELFStream.reset(new ELFStreamer(*EmitStream.get())); |
+ Ctx.reset(new GlobalContext(LogStream.get(), EmitStream.get(), |
+ ELFStream.get(), Flags)); |
+ CompileThread = std::thread([this]() { |
+ Ctx->initParserThread(); |
+ this->getCompiler().run(ExtraFlags, *Ctx.get(), |
+ // Retain original reference, but the compiler |
+ // (LLVM's MemoryObject) wants to handle deletion. |
+ std::unique_ptr<llvm::DataStreamer>(InputStream)); |
+ }); |
+} |
+ |
+} // end of namespace Ice |
+ |
+#endif // PNACL_BROWSER_TRANSLATOR |