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; |
| 83 if (BuildDefs::minimal()) |
| 84 return ExternalArgs; |
| 85 char ArgsFileVar[] = "SZARGFILE"; |
| 86 char ArgsListVar[] = "SZARGLIST"; |
| 87 if (const char *ArgsFilename = getenv(ArgsFileVar)) { |
| 88 std::ifstream ArgsStream(ArgsFilename); |
| 89 std::string Arg; |
| 90 while (ArgsStream >> std::ws, std::getline(ArgsStream, Arg)) { |
| 91 if (!Arg.empty() && Arg[0] == '#') |
| 92 continue; |
| 93 ExternalArgs.emplace_back(Arg); |
| 94 } |
| 95 if (ExternalArgs.empty()) { |
| 96 llvm::report_fatal_error("Failed to read arguments from file '" + |
| 97 std::string(ArgsFilename) + "'"); |
| 98 } |
| 99 } else if (const char *ArgsList = getenv(ArgsListVar)) { |
| 100 // Leverage the RangeSpec tokenizer. |
| 101 auto Args = RangeSpec::tokenize(ArgsList, '|'); |
| 102 ExternalArgs.insert(ExternalArgs.end(), Args.begin(), Args.end()); |
| 103 } |
| 104 return ExternalArgs; |
| 105 } |
| 106 |
51 char *onInitCallback(uint32_t NumThreads, int *ObjFileFDs, | 107 char *onInitCallback(uint32_t NumThreads, int *ObjFileFDs, |
52 size_t ObjFileFDCount, char **CLArgs, size_t CLArgsLen) { | 108 size_t ObjFileFDCount, char **CLArgs, size_t CLArgsLen) { |
53 if (ObjFileFDCount < 1) { | 109 if (ObjFileFDCount < 1) { |
54 std::string Buffer; | 110 std::string Buffer; |
55 llvm::raw_string_ostream StrBuf(Buffer); | 111 llvm::raw_string_ostream StrBuf(Buffer); |
56 StrBuf << "Invalid number of FDs for onInitCallback " << ObjFileFDCount | 112 StrBuf << "Invalid number of FDs for onInitCallback " << ObjFileFDCount |
57 << "\n"; | 113 << "\n"; |
58 return strdup(StrBuf.str().c_str()); | 114 return strdup(StrBuf.str().c_str()); |
59 } | 115 } |
60 int ObjFileFD = ObjFileFDs[0]; | 116 int ObjFileFD = ObjFileFDs[0]; |
61 if (ObjFileFD < 0) { | 117 if (ObjFileFD < 0) { |
62 std::string Buffer; | 118 std::string Buffer; |
63 llvm::raw_string_ostream StrBuf(Buffer); | 119 llvm::raw_string_ostream StrBuf(Buffer); |
64 StrBuf << "Invalid FD given for onInitCallback " << ObjFileFD << "\n"; | 120 StrBuf << "Invalid FD given for onInitCallback " << ObjFileFD << "\n"; |
65 return strdup(StrBuf.str().c_str()); | 121 return strdup(StrBuf.str().c_str()); |
66 } | 122 } |
67 // CLArgs is almost an "argv", but is missing the argv[0] program name. | 123 // CLArgs is almost an "argv", but is missing the argv[0] program name. |
68 std::vector<char *> Argv; | 124 std::vector<const char *> Argv; |
69 char ProgramName[] = "pnacl-sz.nexe"; | 125 constexpr static char ProgramName[] = "pnacl-sz.nexe"; |
70 Argv.reserve(CLArgsLen + 1); | 126 Argv.reserve(CLArgsLen + 1); |
71 Argv.push_back(ProgramName); | 127 Argv.push_back(ProgramName); |
72 for (size_t i = 0; i < CLArgsLen; ++i) { | 128 |
73 Argv.push_back(CLArgs[i]); | 129 bool UseNumThreadsFromBrowser = true; |
| 130 auto ExternalArgs = getExternalArgs(); |
| 131 if (ExternalArgs.empty()) { |
| 132 for (size_t i = 0; i < CLArgsLen; ++i) { |
| 133 Argv.push_back(CLArgs[i]); |
| 134 } |
| 135 } else { |
| 136 for (auto &Arg : ExternalArgs) { |
| 137 Argv.emplace_back(Arg.c_str()); |
| 138 } |
| 139 UseNumThreadsFromBrowser = false; |
74 } | 140 } |
75 // NOTE: strings pointed to by argv are owned by the caller, but we parse | 141 // NOTE: strings pointed to by argv are owned by the caller, but we parse |
76 // here before returning and don't store them. | 142 // here before returning and don't store them. |
77 gCompileServer->getParsedFlags(NumThreads, Argv.size(), Argv.data()); | 143 gCompileServer->getParsedFlags(UseNumThreadsFromBrowser, NumThreads, |
| 144 Argv.size(), Argv.data()); |
78 gCompileServer->startCompileThread(ObjFileFD); | 145 gCompileServer->startCompileThread(ObjFileFD); |
79 return nullptr; | 146 return nullptr; |
80 } | 147 } |
81 | 148 |
82 int onDataCallback(const void *Data, size_t NumBytes) { | 149 int onDataCallback(const void *Data, size_t NumBytes) { |
83 return gCompileServer->pushInputBytes(Data, NumBytes) ? 1 : 0; | 150 return gCompileServer->pushInputBytes(Data, NumBytes) ? 1 : 0; |
84 } | 151 } |
85 | 152 |
86 char *onEndCallback() { | 153 char *onEndCallback() { |
87 gCompileServer->endInputStream(); | 154 gCompileServer->endInputStream(); |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
155 } // end of anonymous namespace | 222 } // end of anonymous namespace |
156 | 223 |
157 BrowserCompileServer::~BrowserCompileServer() = default; | 224 BrowserCompileServer::~BrowserCompileServer() = default; |
158 | 225 |
159 void BrowserCompileServer::run() { | 226 void BrowserCompileServer::run() { |
160 gCompileServer = this; | 227 gCompileServer = this; |
161 getIRTInterfaces(); | 228 getIRTInterfaces(); |
162 gIRTFuncs.serve_translate_request(&SubzeroCallbacks); | 229 gIRTFuncs.serve_translate_request(&SubzeroCallbacks); |
163 } | 230 } |
164 | 231 |
165 void BrowserCompileServer::getParsedFlags(uint32_t NumThreads, int argc, | 232 void BrowserCompileServer::getParsedFlags(bool UseNumThreadsFromBrowser, |
166 char **argv) { | 233 uint32_t NumThreads, int argc, |
| 234 const char *const *argv) { |
167 ClFlags::parseFlags(argc, argv); | 235 ClFlags::parseFlags(argc, argv); |
168 ClFlags::getParsedClFlags(ClFlags::Flags); | 236 ClFlags::getParsedClFlags(ClFlags::Flags); |
169 // Set some defaults which aren't specified via the argv string. | 237 // Set some defaults which aren't specified via the argv string. |
170 ClFlags::Flags.setNumTranslationThreads(NumThreads); | 238 if (UseNumThreadsFromBrowser) |
| 239 ClFlags::Flags.setNumTranslationThreads(NumThreads); |
171 ClFlags::Flags.setUseSandboxing(true); | 240 ClFlags::Flags.setUseSandboxing(true); |
172 ClFlags::Flags.setOutFileType(FT_Elf); | 241 ClFlags::Flags.setOutFileType(FT_Elf); |
173 ClFlags::Flags.setTargetArch(getTargetArch()); | 242 ClFlags::Flags.setTargetArch(getTargetArch()); |
174 ClFlags::Flags.setInputFileFormat(llvm::PNaClFormat); | 243 ClFlags::Flags.setInputFileFormat(llvm::PNaClFormat); |
175 } | 244 } |
176 | 245 |
177 bool BrowserCompileServer::pushInputBytes(const void *Data, size_t NumBytes) { | 246 bool BrowserCompileServer::pushInputBytes(const void *Data, size_t NumBytes) { |
178 // If there was an earlier error, do not attempt to push bytes to the | 247 // If there was an earlier error, do not attempt to push bytes to the |
179 // QueueStreamer. Otherwise the thread could become blocked. | 248 // QueueStreamer. Otherwise the thread could become blocked. |
180 if (HadError.load()) | 249 if (HadError.load()) |
(...skipping 18 matching lines...) Expand all Loading... |
199 // some error category. | 268 // some error category. |
200 LastError.assign(EC_Translation); | 269 LastError.assign(EC_Translation); |
201 } | 270 } |
202 return LastError; | 271 return LastError; |
203 } | 272 } |
204 | 273 |
205 void BrowserCompileServer::endInputStream() { InputStream->SetDone(); } | 274 void BrowserCompileServer::endInputStream() { InputStream->SetDone(); } |
206 | 275 |
207 void BrowserCompileServer::startCompileThread(int ObjFD) { | 276 void BrowserCompileServer::startCompileThread(int ObjFD) { |
208 InputStream = new llvm::QueueStreamer(); | 277 InputStream = new llvm::QueueStreamer(); |
209 LogStream = getOutputStream(STDOUT_FILENO); | 278 bool LogStreamFailure = false; |
| 279 int LogFD = STDOUT_FILENO; |
| 280 if (getFlags().getLogFilename() == "/dev/stderr") { |
| 281 LogFD = STDERR_FILENO; |
| 282 } else { |
| 283 LogStreamFailure = true; |
| 284 } |
| 285 LogStream = getOutputStream(LogFD); |
210 LogStream->SetUnbuffered(); | 286 LogStream->SetUnbuffered(); |
| 287 if (LogStreamFailure) { |
| 288 *LogStream |
| 289 << "Warning: Log file name must be either '-' or '/dev/stderr'\n"; |
| 290 } |
211 EmitStream = getOutputStream(ObjFD); | 291 EmitStream = getOutputStream(ObjFD); |
212 EmitStream->SetBufferSize(1 << 14); | 292 EmitStream->SetBufferSize(1 << 14); |
213 std::unique_ptr<StringStream> ErrStrm(new StringStream()); | 293 std::unique_ptr<StringStream> ErrStrm(new StringStream()); |
214 ErrorStream = std::move(ErrStrm); | 294 ErrorStream = std::move(ErrStrm); |
215 ELFStream.reset(new ELFStreamer(*EmitStream.get())); | 295 ELFStream.reset(new ELFStreamer(*EmitStream.get())); |
216 Ctx.reset(new GlobalContext(LogStream.get(), EmitStream.get(), | 296 Ctx.reset(new GlobalContext(LogStream.get(), EmitStream.get(), |
217 &ErrorStream->getStream(), ELFStream.get())); | 297 &ErrorStream->getStream(), ELFStream.get())); |
218 CompileThread = std::thread([this]() { | 298 CompileThread = std::thread([this]() { |
219 llvm::install_fatal_error_handler(fatalErrorHandler, this); | 299 llvm::install_fatal_error_handler(fatalErrorHandler, this); |
220 Ctx->initParserThread(); | 300 Ctx->initParserThread(); |
(...skipping 18 matching lines...) Expand all Loading... |
239 llvm::report_fatal_error("no browser hookups"); | 319 llvm::report_fatal_error("no browser hookups"); |
240 } | 320 } |
241 | 321 |
242 ErrorCode &BrowserCompileServer::getErrorCode() { | 322 ErrorCode &BrowserCompileServer::getErrorCode() { |
243 llvm::report_fatal_error("no browser hookups"); | 323 llvm::report_fatal_error("no browser hookups"); |
244 } | 324 } |
245 | 325 |
246 } // end of namespace Ice | 326 } // end of namespace Ice |
247 | 327 |
248 #endif // PNACL_BROWSER_TRANSLATOR | 328 #endif // PNACL_BROWSER_TRANSLATOR |
OLD | NEW |