Commit 2f67b929 by Karl Schimpf

First attempt to capture parser/translation errors in browser.

Adds a notion of an (optional) error stream to the existing log and emit streams. If not specified, the log stream is used. Error messages in parser/translation are sent to this new error stream. In the browser compiler server, a separate error (string) stream is created to capture errors. Method onEndCallBack returns the contents of the error stream (if non-empty) instead of a generic error message. BUG= https://code.google.com/p/nativeclient/issues/detail?id=4138 R=jvoung@chromium.org Review URL: https://codereview.chromium.org/1052833003
parent b36ad9b4
...@@ -81,7 +81,8 @@ char *onEndCallback() { ...@@ -81,7 +81,8 @@ char *onEndCallback() {
// TODO(jvoung): Also return an error string, and UMA data. // TODO(jvoung): Also return an error string, and UMA data.
// Set up a report_fatal_error handler to grab that string. // Set up a report_fatal_error handler to grab that string.
if (gCompileServer->getErrorCode().value()) { if (gCompileServer->getErrorCode().value()) {
return strdup("Some error occurred"); const std::string Error = gCompileServer->getErrorStream().getContents();
return strdup(Error.empty() ? "Some error occurred" : Error.c_str());
} }
return nullptr; return nullptr;
} }
...@@ -142,9 +143,12 @@ void BrowserCompileServer::startCompileThread(int ObjFD) { ...@@ -142,9 +143,12 @@ void BrowserCompileServer::startCompileThread(int ObjFD) {
LogStream->SetUnbuffered(); LogStream->SetUnbuffered();
EmitStream = getOutputStream(ObjFD); EmitStream = getOutputStream(ObjFD);
EmitStream->SetBufferSize(1 << 14); EmitStream->SetBufferSize(1 << 14);
std::unique_ptr<StringStream> ErrStrm(new StringStream());
ErrorStream = std::move(ErrStrm);
ELFStream.reset(new ELFStreamer(*EmitStream.get())); ELFStream.reset(new ELFStreamer(*EmitStream.get()));
Ctx.reset(new GlobalContext(LogStream.get(), EmitStream.get(), Ctx.reset(new GlobalContext(LogStream.get(), EmitStream.get(),
ELFStream.get(), Flags)); &ErrorStream->getStream(), ELFStream.get(),
Flags));
CompileThread = std::thread([this]() { CompileThread = std::thread([this]() {
Ctx->initParserThread(); Ctx->initParserThread();
this->getCompiler().run(ExtraFlags, *Ctx.get(), this->getCompiler().run(ExtraFlags, *Ctx.get(),
......
...@@ -39,6 +39,7 @@ class BrowserCompileServer : public CompileServer { ...@@ -39,6 +39,7 @@ class BrowserCompileServer : public CompileServer {
BrowserCompileServer() = delete; BrowserCompileServer() = delete;
BrowserCompileServer(const BrowserCompileServer &) = delete; BrowserCompileServer(const BrowserCompileServer &) = delete;
BrowserCompileServer &operator=(const BrowserCompileServer &) = delete; BrowserCompileServer &operator=(const BrowserCompileServer &) = delete;
class StringStream;
public: public:
explicit BrowserCompileServer(Compiler &Comp) explicit BrowserCompileServer(Compiler &Comp)
...@@ -74,7 +75,20 @@ public: ...@@ -74,7 +75,20 @@ public:
ELFStream.reset(nullptr); ELFStream.reset(nullptr);
} }
StringStream &getErrorStream() {
return *ErrorStream;
}
private: private:
class StringStream {
public:
StringStream() : StrBuf(Buffer) {}
const IceString &getContents() { return StrBuf.str(); }
Ostream &getStream() { return StrBuf; }
private:
std::string Buffer;
llvm::raw_string_ostream StrBuf;
};
// This currently only handles a single compile request, hence one copy // This currently only handles a single compile request, hence one copy
// of the state. // of the state.
std::unique_ptr<GlobalContext> Ctx; std::unique_ptr<GlobalContext> Ctx;
...@@ -84,6 +98,7 @@ private: ...@@ -84,6 +98,7 @@ private:
llvm::QueueStreamer *InputStream; llvm::QueueStreamer *InputStream;
std::unique_ptr<Ostream> LogStream; std::unique_ptr<Ostream> LogStream;
std::unique_ptr<llvm::raw_fd_ostream> EmitStream; std::unique_ptr<llvm::raw_fd_ostream> EmitStream;
std::unique_ptr<StringStream> ErrorStream;
std::unique_ptr<ELFStreamer> ELFStream; std::unique_ptr<ELFStreamer> ELFStream;
ClFlags Flags; ClFlags Flags;
ClFlagsExtra ExtraFlags; ClFlagsExtra ExtraFlags;
......
...@@ -96,7 +96,8 @@ void CLCompileServer::run() { ...@@ -96,7 +96,8 @@ void CLCompileServer::run() {
return transferErrorCode(getReturnValue(ExtraFlags, Ice::EC_Bitcode)); return transferErrorCode(getReturnValue(ExtraFlags, Ice::EC_Bitcode));
} }
Ctx.reset(new GlobalContext(Ls.get(), Os.get(), ELFStr.get(), Flags)); Ctx.reset(new GlobalContext(Ls.get(), Os.get(), Ls.get(), ELFStr.get(),
Flags));
if (Ctx->getFlags().getNumTranslationThreads() != 0) { if (Ctx->getFlags().getNumTranslationThreads() != 0) {
std::thread CompileThread([this, &ExtraFlags, &InputStream]() { std::thread CompileThread([this, &ExtraFlags, &InputStream]() {
Ctx->initParserThread(); Ctx->initParserThread();
......
...@@ -213,14 +213,18 @@ void GlobalContext::CodeStats::dump(const IceString &Name, Ostream &Str) { ...@@ -213,14 +213,18 @@ void GlobalContext::CodeStats::dump(const IceString &Name, Ostream &Str) {
Str << "\n"; Str << "\n";
} }
GlobalContext::GlobalContext(Ostream *OsDump, Ostream *OsEmit, GlobalContext::GlobalContext(Ostream *OsDump, Ostream *OsEmit, Ostream *OsError,
ELFStreamer *ELFStr, const ClFlags &Flags) ELFStreamer *ELFStr, const ClFlags &Flags)
: ConstPool(new ConstantPool()), ErrorStatus(), StrDump(OsDump), : ConstPool(new ConstantPool()), ErrorStatus(), StrDump(OsDump),
StrEmit(OsEmit), Flags(Flags), RNG(Flags.getRandomSeed()), ObjectWriter(), StrEmit(OsEmit), StrError(OsError), Flags(Flags),
RNG(Flags.getRandomSeed()), ObjectWriter(),
OptQ(/*Sequential=*/Flags.isSequential(), OptQ(/*Sequential=*/Flags.isSequential(),
/*MaxSize=*/Flags.getNumTranslationThreads()), /*MaxSize=*/Flags.getNumTranslationThreads()),
// EmitQ is allowed unlimited size. // EmitQ is allowed unlimited size.
EmitQ(/*Sequential=*/Flags.isSequential()) { EmitQ(/*Sequential=*/Flags.isSequential()) {
assert(OsDump && "OsDump is not defined for GlobalContext");
assert(OsEmit && "OsEmit is not defined for GlobalContext");
assert(OsError && "OsError is not defined for GlobalContext");
// Make sure thread_local fields are properly initialized before any // Make sure thread_local fields are properly initialized before any
// accesses are made. Do this here instead of at the start of // accesses are made. Do this here instead of at the start of
// main() so that all clients (e.g. unit tests) can benefit for // main() so that all clients (e.g. unit tests) can benefit for
...@@ -278,7 +282,7 @@ void GlobalContext::translateFunctions() { ...@@ -278,7 +282,7 @@ void GlobalContext::translateFunctions() {
if (Func->hasError()) { if (Func->hasError()) {
getErrorStatus()->assign(EC_Translation); getErrorStatus()->assign(EC_Translation);
OstreamLocker L(this); OstreamLocker L(this);
getStrDump() << "ICE translation error: " << Func->getFunctionName() getStrError() << "ICE translation error: " << Func->getFunctionName()
<< ": " << Func->getError() << "\n"; << ": " << Func->getError() << "\n";
Item = new EmitterWorkItem(Func->getSequenceNumber()); Item = new EmitterWorkItem(Func->getSequenceNumber());
} else { } else {
......
...@@ -145,14 +145,17 @@ class GlobalContext { ...@@ -145,14 +145,17 @@ class GlobalContext {
}; };
public: public:
GlobalContext(Ostream *OsDump, Ostream *OsEmit, ELFStreamer *ELFStreamer, // The dump stream is a log stream while emit is the stream code
const ClFlags &Flags); // is emitted to. The error stream is strictly for logging errors.
GlobalContext(Ostream *OsDump, Ostream *OsEmit, Ostream *OsError,
ELFStreamer *ELFStreamer, const ClFlags &Flags);
~GlobalContext(); ~GlobalContext();
// The dump and emit streams need to be used by only one thread at a //
// time. This is done by exclusively reserving the streams via // The dump, error, and emit streams need to be used by only one
// lockStr() and unlockStr(). The OstreamLocker class can be used // thread at a time. This is done by exclusively reserving the
// to conveniently manage this. // streams via lockStr() and unlockStr(). The OstreamLocker class
// can be used to conveniently manage this.
// //
// The model is that a thread grabs the stream lock, then does an // The model is that a thread grabs the stream lock, then does an
// arbitrary amount of work during which far-away callees may grab // arbitrary amount of work during which far-away callees may grab
...@@ -163,6 +166,7 @@ public: ...@@ -163,6 +166,7 @@ public:
void lockStr() { StrLock.lock(); } void lockStr() { StrLock.lock(); }
void unlockStr() { StrLock.unlock(); } void unlockStr() { StrLock.unlock(); }
Ostream &getStrDump() { return *StrDump; } Ostream &getStrDump() { return *StrDump; }
Ostream &getStrError() { return *StrError; }
Ostream &getStrEmit() { return *StrEmit; } Ostream &getStrEmit() { return *StrEmit; }
LockedPtr<ErrorCode> getErrorStatus() { LockedPtr<ErrorCode> getErrorStatus() {
...@@ -418,6 +422,7 @@ private: ...@@ -418,6 +422,7 @@ private:
StrLockType StrLock; StrLockType StrLock;
Ostream *StrDump; // Stream for dumping / diagnostics Ostream *StrDump; // Stream for dumping / diagnostics
Ostream *StrEmit; // Stream for code emission Ostream *StrEmit; // Stream for code emission
Ostream *StrError; // Stream for logging errors.
ICE_CACHELINE_BOUNDARY; ICE_CACHELINE_BOUNDARY;
......
...@@ -488,7 +488,7 @@ bool TopLevelParser::ErrorAt(naclbitc::ErrorLevel Level, uint64_t Bit, ...@@ -488,7 +488,7 @@ bool TopLevelParser::ErrorAt(naclbitc::ErrorLevel Level, uint64_t Bit,
Ice::GlobalContext *Context = Translator.getContext(); Ice::GlobalContext *Context = Translator.getContext();
{ // Lock while printing out error message. { // Lock while printing out error message.
Ice::OstreamLocker L(Context); Ice::OstreamLocker L(Context);
raw_ostream &OldErrStream = setErrStream(Context->getStrDump()); raw_ostream &OldErrStream = setErrStream(Context->getStrError());
NaClBitcodeParser::ErrorAt(Level, Bit, Message); NaClBitcodeParser::ErrorAt(Level, Bit, Message);
setErrStream(OldErrStream); setErrStream(OldErrStream);
} }
......
...@@ -38,7 +38,7 @@ bool IceTest::SubzeroBitcodeMunger::runTest(const char *TestName, ...@@ -38,7 +38,7 @@ bool IceTest::SubzeroBitcodeMunger::runTest(const char *TestName,
size_t MungeSize) { size_t MungeSize) {
const bool AddHeader = true; const bool AddHeader = true;
setupTest(TestName, Munges, MungeSize, AddHeader); setupTest(TestName, Munges, MungeSize, AddHeader);
Ice::GlobalContext Ctx(DumpStream, DumpStream, nullptr, Flags); Ice::GlobalContext Ctx(DumpStream, DumpStream, DumpStream, nullptr, Flags);
Ice::PNaClTranslator Translator(&Ctx); Ice::PNaClTranslator Translator(&Ctx);
Translator.translateBuffer(TestName, MungedInput.get()); Translator.translateBuffer(TestName, MungedInput.get());
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment