Bug 1503142 - Check for pending compile error on off-main-thread parsing BinAST. r=Waldo
authorTooru Fujisawa <arai_a@mac.com>
Wed, 14 Nov 2018 13:00:33 +0900
changeset 502590 598f4654a06cb0bc7e1525e61b7d97acd6ba0d51
parent 502589 b90ad12e6e7004e90b903c31c52c847df3bb03de
child 502591 a4fb56d2819e636de6c7ae756028e537efae48d0
push id10290
push userffxbld-merge
push dateMon, 03 Dec 2018 16:23:23 +0000
treeherdermozilla-beta@700bed2445e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersWaldo
bugs1503142
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1503142 - Check for pending compile error on off-main-thread parsing BinAST. r=Waldo
js/src/frontend/BinTokenReaderBase.cpp
js/src/frontend/BinTokenReaderBase.h
js/src/frontend/BinTokenReaderMultipart.cpp
js/src/frontend/BinTokenReaderTester.cpp
js/src/vm/HelperThreads.cpp
js/src/vm/JSContext.h
--- a/js/src/frontend/BinTokenReaderBase.cpp
+++ b/js/src/frontend/BinTokenReaderBase.cpp
@@ -25,17 +25,17 @@ BinTokenReaderBase::updateLatestKnownGoo
     const size_t update = current_ - start_;
     MOZ_ASSERT(update >= latestKnownGoodPos_);
     latestKnownGoodPos_ = update;
 }
 
 ErrorResult<JS::Error&>
 BinTokenReaderBase::raiseError(const char* description)
 {
-    MOZ_ASSERT(!cx_->isExceptionPending());
+    MOZ_ASSERT(!hasRaisedError());
     if (MOZ_LIKELY(errorReporter_)) {
         errorReporter_->reportErrorNoOffset(JSMSG_BINAST, description);
     } else {
         // Only true in testing code.
         TokenPos pos = this->pos();
         JS_ReportErrorASCII(cx_, "BinAST parsing error: %s at offsets %u => %u",
                             description, pos.begin, pos.end);
     }
@@ -63,23 +63,27 @@ ErrorResult<JS::Error&>
 BinTokenReaderBase::raiseInvalidField(const char* kind, const BinField field)
 {
     Sprinter out(cx_);
     BINJS_TRY(out.init());
     BINJS_TRY(out.printf("In %s, invalid field '%s'", kind, describeBinField(field)));
     return raiseError(out.string());
 }
 
-#ifdef DEBUG
 bool
 BinTokenReaderBase::hasRaisedError() const
 {
+    if (cx_->helperThread()) {
+        // When performing off-main-thread parsing, we don't set a pending
+        // exception but instead add a pending compile error.
+        return cx_->isCompileErrorPending();
+    }
+
     return cx_->isExceptionPending();
 }
-#endif
 
 size_t
 BinTokenReaderBase::offset() const
 {
     return current_ - start_;
 }
 
 TokenPos
@@ -104,17 +108,17 @@ BinTokenReaderBase::seek(size_t offset)
     MOZ_ASSERT(start_ + offset >= start_ &&
                start_ + offset < stop_);
     current_ = start_ + offset;
 }
 
 JS::Result<Ok>
 BinTokenReaderBase::readBuf(uint8_t* bytes, uint32_t len)
 {
-    MOZ_ASSERT(!cx_->isExceptionPending());
+    MOZ_ASSERT(!hasRaisedError());
     MOZ_ASSERT(len > 0);
 
     if (stop_ < current_ + len) {
         return raiseError("Buffer exceeds length");
     }
 
     for (uint32_t i = 0; i < len; ++i) {
         *bytes++ = *current_++;
--- a/js/src/frontend/BinTokenReaderBase.h
+++ b/js/src/frontend/BinTokenReaderBase.h
@@ -146,19 +146,17 @@ class MOZ_STACK_CLASS BinTokenReaderBase
         // Looks like we have a match. Now perform side-effects
         current_ += N + (expectNul ? 0 : -1);
         updateLatestKnownGood();
         return true;
     }
 
     void updateLatestKnownGood();
 
-#ifdef DEBUG
     bool hasRaisedError() const;
-#endif
 
     JSContext* cx_;
 
     ErrorReporter* errorReporter_;
 
     // `true` if we have encountered an error. Errors are non recoverable.
     // Attempting to read from a poisoned tokenizer will cause assertion errors.
     bool poisoned_;
--- a/js/src/frontend/BinTokenReaderMultipart.cpp
+++ b/js/src/frontend/BinTokenReaderMultipart.cpp
@@ -427,17 +427,17 @@ BinTokenReaderMultipart::AutoBase::AutoB
     , reader_(reader)
 { }
 
 BinTokenReaderMultipart::AutoBase::~AutoBase()
 {
     // By now, the `AutoBase` must have been deinitialized by calling `done()`.
     // The only case in which we can accept not calling `done()` is if we have
     // bailed out because of an error.
-    MOZ_ASSERT_IF(initialized_, reader_.cx_->isExceptionPending());
+    MOZ_ASSERT_IF(initialized_, reader_.hasRaisedError());
 }
 
 JS::Result<Ok>
 BinTokenReaderMultipart::AutoBase::checkPosition(const uint8_t* expectedEnd)
 {
     if (reader_.current_ != expectedEnd) {
         return reader_.raiseError("Caller did not consume the expected set of bytes");
     }
@@ -457,17 +457,17 @@ BinTokenReaderMultipart::AutoList::init(
     AutoBase::init();
 }
 
 JS::Result<Ok>
 BinTokenReaderMultipart::AutoList::done()
 {
     MOZ_ASSERT(initialized_);
     initialized_ = false;
-    if (reader_.cx_->isExceptionPending()) {
+    if (reader_.hasRaisedError()) {
         // Already errored, no need to check further.
         return reader_.cx_->alreadyReportedError();
     }
 
     return Ok();
 }
 
 
@@ -508,34 +508,34 @@ BinTokenReaderMultipart::AutoTaggedTuple
     : AutoBase(reader)
 { }
 
 JS::Result<Ok>
 BinTokenReaderMultipart::AutoTaggedTuple::done()
 {
     MOZ_ASSERT(initialized_);
     initialized_ = false;
-    if (reader_.cx_->isExceptionPending()) {
+    if (reader_.hasRaisedError()) {
         // Already errored, no need to check further.
         return reader_.cx_->alreadyReportedError();
     }
 
     return Ok();
 }
 
 BinTokenReaderMultipart::AutoTuple::AutoTuple(BinTokenReaderMultipart& reader)
     : AutoBase(reader)
 { }
 
 JS::Result<Ok>
 BinTokenReaderMultipart::AutoTuple::done()
 {
     MOZ_ASSERT(initialized_);
     initialized_ = false;
-    if (reader_.cx_->isExceptionPending()) {
+    if (reader_.hasRaisedError()) {
         // Already errored, no need to check further.
         return reader_.cx_->alreadyReportedError();
     }
 
     // Check suffix.
     return Ok();
 }
 
--- a/js/src/frontend/BinTokenReaderTester.cpp
+++ b/js/src/frontend/BinTokenReaderTester.cpp
@@ -394,17 +394,17 @@ BinTokenReaderTester::AutoBase::AutoBase
     , reader_(reader)
 { }
 
 BinTokenReaderTester::AutoBase::~AutoBase()
 {
     // By now, the `AutoBase` must have been deinitialized by calling `done()`.
     // The only case in which we can accept not calling `done()` is if we have
     // bailed out because of an error.
-    MOZ_ASSERT_IF(initialized_, reader_.cx_->isExceptionPending());
+    MOZ_ASSERT_IF(initialized_, reader_.hasRaisedError());
 }
 
 JS::Result<Ok>
 BinTokenReaderTester::AutoBase::checkPosition(const uint8_t* expectedEnd)
 {
     if (reader_.current_ != expectedEnd) {
         return reader_.raiseError("Caller did not consume the expected set of bytes");
     }
@@ -422,17 +422,17 @@ BinTokenReaderTester::AutoList::init()
     AutoBase::init();
 }
 
 JS::Result<Ok>
 BinTokenReaderTester::AutoList::done()
 {
     MOZ_ASSERT(initialized_);
     initialized_ = false;
-    if (reader_.cx_->isExceptionPending()) {
+    if (reader_.hasRaisedError()) {
         // Already errored, no need to check further.
         return reader_.cx_->alreadyReportedError();
     }
 
     // Check suffix.
     MOZ_TRY(reader_.readConst("</list>"));
 
     return Ok();
@@ -442,17 +442,17 @@ BinTokenReaderTester::AutoTaggedTuple::A
     : AutoBase(reader)
 { }
 
 JS::Result<Ok>
 BinTokenReaderTester::AutoTaggedTuple::done()
 {
     MOZ_ASSERT(initialized_);
     initialized_ = false;
-    if (reader_.cx_->isExceptionPending()) {
+    if (reader_.hasRaisedError()) {
         // Already errored, no need to check further.
         return reader_.cx_->alreadyReportedError();
     }
 
     // Check suffix.
     MOZ_TRY(reader_.readConst("</tuple>"));
 
     return Ok();
@@ -462,17 +462,17 @@ BinTokenReaderTester::AutoTuple::AutoTup
     : AutoBase(reader)
 { }
 
 JS::Result<Ok>
 BinTokenReaderTester::AutoTuple::done()
 {
     MOZ_ASSERT(initialized_);
     initialized_ = false;
-    if (reader_.cx_->isExceptionPending()) {
+    if (reader_.hasRaisedError()) {
         // Already errored, no need to check further.
         return reader_.cx_->alreadyReportedError();
     }
 
     // Check suffix.
     MOZ_TRY(reader_.readConst("</tuple>"));
 
     return Ok();
--- a/js/src/vm/HelperThreads.cpp
+++ b/js/src/vm/HelperThreads.cpp
@@ -2195,16 +2195,23 @@ JSContext::addPendingCompileError(js::Co
     if (!parseTask->errors.append(std::move(errorPtr))) {
         ReportOutOfMemory(this);
         return false;
     }
     *error = parseTask->errors.back().get();
     return true;
 }
 
+bool
+JSContext::isCompileErrorPending() const
+{
+    ParseTask* parseTask = helperThread()->parseTask();
+    return parseTask->errors.length() > 0;
+}
+
 void
 JSContext::addPendingOverRecursed()
 {
     if (helperThread()->parseTask()) {
         helperThread()->parseTask()->overRecursed = true;
     }
 }
 
--- a/js/src/vm/JSContext.h
+++ b/js/src/vm/JSContext.h
@@ -359,16 +359,18 @@ struct JSContext : public JS::RootingCon
         atomMarking().markAtomValue(this, value);
     }
 
     // Methods specific to any HelperThread for the context.
     bool addPendingCompileError(js::CompileError** err);
     void addPendingOverRecursed();
     void addPendingOutOfMemory();
 
+    bool isCompileErrorPending() const;
+
     JSRuntime* runtime() { return runtime_; }
     const JSRuntime* runtime() const { return runtime_; }
 
     static size_t offsetOfRealm() {
         return offsetof(JSContext, realm_);
     }
 
     friend class JS::AutoSaveExceptionState;