Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 //===- subzero/src/IceBrowserCompileServer.cpp - Browser compile server ---===// | 1 //===- subzero/src/IceBrowserCompileServer.cpp - Browser compile server ---===// |
| 2 // | 2 // |
| 3 // The Subzero Code Generator | 3 // The Subzero Code Generator |
| 4 // | 4 // |
| 5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
| 6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
| 7 // | 7 // |
| 8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
| 9 /// | 9 /// |
| 10 /// \file | 10 /// \file |
| 11 /// \brief Defines the browser-based compile server. | 11 /// \brief Defines the browser-based compile server. |
| 12 /// | 12 /// |
| 13 //===----------------------------------------------------------------------===// | 13 //===----------------------------------------------------------------------===// |
| 14 | 14 |
| 15 // Can only compile this with the NaCl compiler (needs irt.h, and the | 15 // Can only compile this with the NaCl compiler (needs irt.h, and the |
| 16 // unsandboxed LLVM build using the trusted compiler does not have irt.h). | 16 // unsandboxed LLVM build using the trusted compiler does not have irt.h). |
| 17 #include "IceBrowserCompileServer.h" | 17 #include "IceBrowserCompileServer.h" |
| 18 #include "IceRangeSpec.h" | |
| 18 | 19 |
| 19 #if PNACL_BROWSER_TRANSLATOR | 20 #if PNACL_BROWSER_TRANSLATOR |
| 20 | 21 |
| 21 // Headers which are not properly part of the SDK are included by their path in | 22 // Headers which are not properly part of the SDK are included by their path in |
| 22 // the NaCl tree. | 23 // the NaCl tree. |
| 23 #ifdef __pnacl__ | 24 #ifdef __pnacl__ |
| 24 #include "native_client/src/untrusted/nacl/pnacl.h" | 25 #include "native_client/src/untrusted/nacl/pnacl.h" |
| 25 #endif // __pnacl__ | 26 #endif // __pnacl__ |
| 26 | 27 |
| 27 #include "llvm/Support/QueueStreamer.h" | 28 #include "llvm/Support/QueueStreamer.h" |
| 28 | 29 |
| 29 #include <cstring> | 30 #include <cstring> |
| 31 #include <fstream> | |
| 30 #include <irt.h> | 32 #include <irt.h> |
| 31 #include <irt_dev.h> | 33 #include <irt_dev.h> |
| 32 #include <pthread.h> | 34 #include <pthread.h> |
| 33 #include <thread> | 35 #include <thread> |
| 34 | 36 |
| 35 namespace Ice { | 37 namespace Ice { |
| 36 | 38 |
| 37 // Create C wrappers around callback handlers for the IRT interface. | 39 // Create C wrappers around callback handlers for the IRT interface. |
| 38 namespace { | 40 namespace { |
| 39 | 41 |
| 40 BrowserCompileServer *gCompileServer; | 42 BrowserCompileServer *gCompileServer; |
| 41 struct nacl_irt_private_pnacl_translator_compile gIRTFuncs; | 43 struct nacl_irt_private_pnacl_translator_compile gIRTFuncs; |
| 42 | 44 |
| 43 void getIRTInterfaces() { | 45 void getIRTInterfaces() { |
| 44 size_t QueryResult = | 46 size_t QueryResult = |
| 45 nacl_interface_query(NACL_IRT_PRIVATE_PNACL_TRANSLATOR_COMPILE_v0_1, | 47 nacl_interface_query(NACL_IRT_PRIVATE_PNACL_TRANSLATOR_COMPILE_v0_1, |
| 46 &gIRTFuncs, sizeof(gIRTFuncs)); | 48 &gIRTFuncs, sizeof(gIRTFuncs)); |
| 47 if (QueryResult != sizeof(gIRTFuncs)) | 49 if (QueryResult != sizeof(gIRTFuncs)) |
| 48 llvm::report_fatal_error("Failed to get translator compile IRT interface"); | 50 llvm::report_fatal_error("Failed to get translator compile IRT interface"); |
| 49 } | 51 } |
| 50 | 52 |
| 53 // Allow pnacl-sz arguments to be supplied externally, instead of coming from | |
| 54 // the browser. This is meant to be used for debugging. | |
| 55 // | |
| 56 // If the SZARGFILE environment variable is set to a file name, arguments are | |
| 57 // read from that file, one argument per line. This requires setting 3 | |
| 58 // environment variables before starting the browser: | |
| 59 // | |
| 60 // NACL_ENV_PASSTHROUGH=NACL_DANGEROUS_ENABLE_FILE_ACCESS,NACLENV_SZARGFILE | |
| 61 // NACL_DANGEROUS_ENABLE_FILE_ACCESS=1 | |
| 62 // NACLENV_SZARGFILE=/path/to/myargs.txt | |
| 63 // | |
| 64 // In addition, Chrome needs to be launched with the "--no-sandbox" argument. | |
| 65 // | |
| 66 // If the SZARGLIST environment variable is set, arguments are extracted from | |
| 67 // that variable's value, separated by the '|' character (being careful to | |
| 68 // escape/quote special shell characters). This requires setting 2 environment | |
| 69 // variables before starting the browser: | |
| 70 // | |
| 71 // NACL_ENV_PASSTHROUGH=NACLENV_SZARGLIST | |
| 72 // NACLENV_SZARGLIST=arg | |
| 73 // | |
| 74 // This does not require the "--no-sandbox" argument, and is therefore much | |
| 75 // safer, but does require restarting the browser to change the arguments. | |
| 76 // | |
| 77 // If external arguments are supplied, the browser's NumThreads specification is | |
| 78 // ignored, to allow -threads to be specified as an external argument. Note | |
| 79 // that the browser normally supplies the "-O2" argument, so externally supplied | |
| 80 // arguments might want to provide an explicit -O argument. | |
| 81 std::vector<std::string> getExternalArgs() { | |
| 82 std::vector<std::string> ExternalArgs; | |
|
John
2016/04/20 14:17:24
I still think this should be disallowed in a relea
Jim Stichnoth
2016/04/20 16:53:54
I originally felt this way.
Then I changed my min
| |
| 83 char ArgsFileVar[] = "SZARGFILE"; | |
|
John
2016/04/20 14:17:24
const
Jim Stichnoth
2016/04/20 16:53:54
Sadly, archaic getenv() was apparently invented be
| |
| 84 char ArgsListVar[] = "SZARGLIST"; | |
| 85 if (const char *ArgsFilename = getenv(ArgsFileVar)) { | |
| 86 std::ifstream ArgsStream(ArgsFilename); | |
| 87 std::string Arg; | |
| 88 while (ArgsStream >> std::ws, std::getline(ArgsStream, Arg)) { | |
| 89 if (!Arg.empty() && Arg[0] == '#') | |
| 90 continue; | |
| 91 ExternalArgs.emplace_back(Arg); | |
| 92 } | |
| 93 if (ExternalArgs.empty()) { | |
| 94 llvm::report_fatal_error("Failed to read arguments from file '" + | |
| 95 std::string(ArgsFilename) + "'"); | |
| 96 } | |
| 97 } else if (const char *ArgsList = getenv(ArgsListVar)) { | |
| 98 // Leverage the RangeSpec tokenizer. | |
| 99 auto Args = RangeSpec::tokenize(ArgsList, '|'); | |
| 100 ExternalArgs.insert(ExternalArgs.end(), Args.begin(), Args.end()); | |
| 101 } | |
| 102 return ExternalArgs; | |
| 103 } | |
| 104 | |
| 51 char *onInitCallback(uint32_t NumThreads, int *ObjFileFDs, | 105 char *onInitCallback(uint32_t NumThreads, int *ObjFileFDs, |
| 52 size_t ObjFileFDCount, char **CLArgs, size_t CLArgsLen) { | 106 size_t ObjFileFDCount, char **CLArgs, size_t CLArgsLen) { |
| 53 if (ObjFileFDCount < 1) { | 107 if (ObjFileFDCount < 1) { |
| 54 std::string Buffer; | 108 std::string Buffer; |
| 55 llvm::raw_string_ostream StrBuf(Buffer); | 109 llvm::raw_string_ostream StrBuf(Buffer); |
| 56 StrBuf << "Invalid number of FDs for onInitCallback " << ObjFileFDCount | 110 StrBuf << "Invalid number of FDs for onInitCallback " << ObjFileFDCount |
| 57 << "\n"; | 111 << "\n"; |
| 58 return strdup(StrBuf.str().c_str()); | 112 return strdup(StrBuf.str().c_str()); |
| 59 } | 113 } |
| 60 int ObjFileFD = ObjFileFDs[0]; | 114 int ObjFileFD = ObjFileFDs[0]; |
| 61 if (ObjFileFD < 0) { | 115 if (ObjFileFD < 0) { |
| 62 std::string Buffer; | 116 std::string Buffer; |
| 63 llvm::raw_string_ostream StrBuf(Buffer); | 117 llvm::raw_string_ostream StrBuf(Buffer); |
| 64 StrBuf << "Invalid FD given for onInitCallback " << ObjFileFD << "\n"; | 118 StrBuf << "Invalid FD given for onInitCallback " << ObjFileFD << "\n"; |
| 65 return strdup(StrBuf.str().c_str()); | 119 return strdup(StrBuf.str().c_str()); |
| 66 } | 120 } |
| 67 // CLArgs is almost an "argv", but is missing the argv[0] program name. | 121 // CLArgs is almost an "argv", but is missing the argv[0] program name. |
| 68 std::vector<char *> Argv; | 122 std::vector<const char *> Argv; |
| 69 char ProgramName[] = "pnacl-sz.nexe"; | 123 constexpr static char ProgramName[] = "pnacl-sz.nexe"; |
| 70 Argv.reserve(CLArgsLen + 1); | 124 Argv.reserve(CLArgsLen + 1); |
| 71 Argv.push_back(ProgramName); | 125 Argv.push_back(ProgramName); |
| 72 for (size_t i = 0; i < CLArgsLen; ++i) { | 126 |
| 73 Argv.push_back(CLArgs[i]); | 127 bool UseNumThreadsFromBrowser = true; |
| 128 auto ExternalArgs = getExternalArgs(); | |
| 129 if (ExternalArgs.empty()) { | |
| 130 for (size_t i = 0; i < CLArgsLen; ++i) { | |
| 131 Argv.push_back(CLArgs[i]); | |
| 132 } | |
| 133 } else { | |
| 134 for (auto &Arg : ExternalArgs) { | |
| 135 Argv.emplace_back(Arg.c_str()); | |
| 136 } | |
| 137 UseNumThreadsFromBrowser = false; | |
| 74 } | 138 } |
| 75 // NOTE: strings pointed to by argv are owned by the caller, but we parse | 139 // NOTE: strings pointed to by argv are owned by the caller, but we parse |
| 76 // here before returning and don't store them. | 140 // here before returning and don't store them. |
| 77 gCompileServer->getParsedFlags(NumThreads, Argv.size(), Argv.data()); | 141 gCompileServer->getParsedFlags(UseNumThreadsFromBrowser, NumThreads, |
| 78 gCompileServer->startCompileThread(ObjFileFD); | 142 Argv.size(), Argv.data()); |
| 143 int LogFD = STDOUT_FILENO; | |
| 144 if (getFlags().getLogFilename() == "/dev/stderr") { | |
| 145 LogFD = STDERR_FILENO; | |
| 146 } else if (getFlags().getLogFilename() != "-") { | |
| 147 llvm::report_fatal_error( | |
| 148 "Log file name must be either '-' or '/dev/stderr'"); | |
|
John
2016/04/20 14:17:24
Can the user change this option?? It seems like an
Jim Stichnoth
2016/04/20 16:53:54
Done. Pushed the logic down into startCompileThre
| |
| 149 } | |
| 150 gCompileServer->startCompileThread(ObjFileFD, LogFD); | |
| 79 return nullptr; | 151 return nullptr; |
| 80 } | 152 } |
| 81 | 153 |
| 82 int onDataCallback(const void *Data, size_t NumBytes) { | 154 int onDataCallback(const void *Data, size_t NumBytes) { |
| 83 return gCompileServer->pushInputBytes(Data, NumBytes) ? 1 : 0; | 155 return gCompileServer->pushInputBytes(Data, NumBytes) ? 1 : 0; |
| 84 } | 156 } |
| 85 | 157 |
| 86 char *onEndCallback() { | 158 char *onEndCallback() { |
| 87 gCompileServer->endInputStream(); | 159 gCompileServer->endInputStream(); |
| 88 gCompileServer->waitForCompileThread(); | 160 gCompileServer->waitForCompileThread(); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 155 } // end of anonymous namespace | 227 } // end of anonymous namespace |
| 156 | 228 |
| 157 BrowserCompileServer::~BrowserCompileServer() = default; | 229 BrowserCompileServer::~BrowserCompileServer() = default; |
| 158 | 230 |
| 159 void BrowserCompileServer::run() { | 231 void BrowserCompileServer::run() { |
| 160 gCompileServer = this; | 232 gCompileServer = this; |
| 161 getIRTInterfaces(); | 233 getIRTInterfaces(); |
| 162 gIRTFuncs.serve_translate_request(&SubzeroCallbacks); | 234 gIRTFuncs.serve_translate_request(&SubzeroCallbacks); |
| 163 } | 235 } |
| 164 | 236 |
| 165 void BrowserCompileServer::getParsedFlags(uint32_t NumThreads, int argc, | 237 void BrowserCompileServer::getParsedFlags(bool UseNumThreadsFromBrowser, |
| 166 char **argv) { | 238 uint32_t NumThreads, int argc, |
| 239 const char *const *argv) { | |
| 167 ClFlags::parseFlags(argc, argv); | 240 ClFlags::parseFlags(argc, argv); |
| 168 ClFlags::getParsedClFlags(ClFlags::Flags); | 241 ClFlags::getParsedClFlags(ClFlags::Flags); |
| 169 // Set some defaults which aren't specified via the argv string. | 242 // Set some defaults which aren't specified via the argv string. |
| 170 ClFlags::Flags.setNumTranslationThreads(NumThreads); | 243 if (UseNumThreadsFromBrowser) |
| 244 ClFlags::Flags.setNumTranslationThreads(NumThreads); | |
| 171 ClFlags::Flags.setUseSandboxing(true); | 245 ClFlags::Flags.setUseSandboxing(true); |
| 172 ClFlags::Flags.setOutFileType(FT_Elf); | 246 ClFlags::Flags.setOutFileType(FT_Elf); |
| 173 ClFlags::Flags.setTargetArch(getTargetArch()); | 247 ClFlags::Flags.setTargetArch(getTargetArch()); |
| 174 ClFlags::Flags.setInputFileFormat(llvm::PNaClFormat); | 248 ClFlags::Flags.setInputFileFormat(llvm::PNaClFormat); |
| 175 } | 249 } |
| 176 | 250 |
| 177 bool BrowserCompileServer::pushInputBytes(const void *Data, size_t NumBytes) { | 251 bool BrowserCompileServer::pushInputBytes(const void *Data, size_t NumBytes) { |
| 178 // If there was an earlier error, do not attempt to push bytes to the | 252 // If there was an earlier error, do not attempt to push bytes to the |
| 179 // QueueStreamer. Otherwise the thread could become blocked. | 253 // QueueStreamer. Otherwise the thread could become blocked. |
| 180 if (HadError.load()) | 254 if (HadError.load()) |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 197 // HadError means report_fatal_error is called. Make sure that the | 271 // HadError means report_fatal_error is called. Make sure that the |
| 198 // LastError is not EC_None. We don't know the type of error so just pick | 272 // LastError is not EC_None. We don't know the type of error so just pick |
| 199 // some error category. | 273 // some error category. |
| 200 LastError.assign(EC_Translation); | 274 LastError.assign(EC_Translation); |
| 201 } | 275 } |
| 202 return LastError; | 276 return LastError; |
| 203 } | 277 } |
| 204 | 278 |
| 205 void BrowserCompileServer::endInputStream() { InputStream->SetDone(); } | 279 void BrowserCompileServer::endInputStream() { InputStream->SetDone(); } |
| 206 | 280 |
| 207 void BrowserCompileServer::startCompileThread(int ObjFD) { | 281 void BrowserCompileServer::startCompileThread(int ObjFD, int LogFD) { |
| 208 InputStream = new llvm::QueueStreamer(); | 282 InputStream = new llvm::QueueStreamer(); |
| 209 LogStream = getOutputStream(STDOUT_FILENO); | 283 LogStream = getOutputStream(LogFD); |
| 210 LogStream->SetUnbuffered(); | 284 LogStream->SetUnbuffered(); |
| 211 EmitStream = getOutputStream(ObjFD); | 285 EmitStream = getOutputStream(ObjFD); |
| 212 EmitStream->SetBufferSize(1 << 14); | 286 EmitStream->SetBufferSize(1 << 14); |
| 213 std::unique_ptr<StringStream> ErrStrm(new StringStream()); | 287 std::unique_ptr<StringStream> ErrStrm(new StringStream()); |
| 214 ErrorStream = std::move(ErrStrm); | 288 ErrorStream = std::move(ErrStrm); |
| 215 ELFStream.reset(new ELFStreamer(*EmitStream.get())); | 289 ELFStream.reset(new ELFStreamer(*EmitStream.get())); |
| 216 Ctx.reset(new GlobalContext(LogStream.get(), EmitStream.get(), | 290 Ctx.reset(new GlobalContext(LogStream.get(), EmitStream.get(), |
| 217 &ErrorStream->getStream(), ELFStream.get())); | 291 &ErrorStream->getStream(), ELFStream.get())); |
| 218 CompileThread = std::thread([this]() { | 292 CompileThread = std::thread([this]() { |
| 219 llvm::install_fatal_error_handler(fatalErrorHandler, this); | 293 llvm::install_fatal_error_handler(fatalErrorHandler, this); |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 239 llvm::report_fatal_error("no browser hookups"); | 313 llvm::report_fatal_error("no browser hookups"); |
| 240 } | 314 } |
| 241 | 315 |
| 242 ErrorCode &BrowserCompileServer::getErrorCode() { | 316 ErrorCode &BrowserCompileServer::getErrorCode() { |
| 243 llvm::report_fatal_error("no browser hookups"); | 317 llvm::report_fatal_error("no browser hookups"); |
| 244 } | 318 } |
| 245 | 319 |
| 246 } // end of namespace Ice | 320 } // end of namespace Ice |
| 247 | 321 |
| 248 #endif // PNACL_BROWSER_TRANSLATOR | 322 #endif // PNACL_BROWSER_TRANSLATOR |
| OLD | NEW |