| Index: src/IceBrowserCompileServer.cpp
|
| diff --git a/src/IceBrowserCompileServer.cpp b/src/IceBrowserCompileServer.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..6a9ee65912eaaa27238a1fcbcb9291872070dfbe
|
| --- /dev/null
|
| +++ b/src/IceBrowserCompileServer.cpp
|
| @@ -0,0 +1,150 @@
|
| +//===- subzero/src/IceBrowserCompileServer.cpp - Browser 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 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 <cstring>
|
| +#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 compile IRT interface");
|
| +}
|
| +
|
| +char *onInitCallback(uint32_t NumThreads, int *ObjFileFDs,
|
| + size_t ObjFileFDCount, char **argv, size_t argc) {
|
| + if (ObjFileFDCount < 1) {
|
| + std::string Buffer;
|
| + llvm::raw_string_ostream StrBuf(Buffer);
|
| + StrBuf << "Invalid number of FDs for onInitCallback " << ObjFileFDCount
|
| + << "\n";
|
| + return strdup(StrBuf.str().c_str());
|
| + }
|
| + int ObjFileFD = ObjFileFDs[0];
|
| + if (ObjFileFD < 0) {
|
| + std::string Buffer;
|
| + llvm::raw_string_ostream StrBuf(Buffer);
|
| + StrBuf << "Invalid FD given for onInitCallback " << ObjFileFD << "\n";
|
| + return strdup(StrBuf.str().c_str());
|
| + }
|
| + // NOTE: argv is owned by the caller, but we parse here before returning.
|
| + gCompileServer->getParsedFlags(NumThreads, argc, argv);
|
| + gCompileServer->startCompileThread(ObjFileFD);
|
| + return nullptr;
|
| +}
|
| +
|
| +int onDataCallback(const void *Data, size_t NumBytes) {
|
| + return gCompileServer->pushInputBytes(Data, NumBytes) ? 1 : 0;
|
| +}
|
| +
|
| +char *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.
|
| + if (gCompileServer->getErrorCode().value()) {
|
| + return strdup("Some error occurred");
|
| + }
|
| + return nullptr;
|
| +}
|
| +
|
| +struct nacl_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(const void *Data, size_t NumBytes) {
|
| + return InputStream->PutBytes(
|
| + const_cast<unsigned char *>(
|
| + reinterpret_cast<const unsigned char *>(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
|
|
|