merge mozilla-inbound to mozilla-central. r=merge a=merge
authorSebastian Hengst <archaeopteryx@coole-files.de>
Mon, 06 Nov 2017 00:14:30 +0200
changeset 443512 179dae92e4d794e7f45ad080ff01908c80691f31
parent 443511 4e43d3919c51deab933fabe451900504078c3ec6 (current diff)
parent 443500 73a48b92351a1c615108c36324c4900cb8ad41a6 (diff)
child 443513 b7ade96f752be032b1de492c2520c68d242d04ec
child 443526 a73e202ca31d30bc2b96418fa81d1096f8dc731e
child 443528 c9ed5bfc1e34ed57be8cae7b0ccc3e6cac55b7ab
push id1618
push userCallek@gmail.com
push dateThu, 11 Jan 2018 17:45:48 +0000
treeherdermozilla-release@882ca853e05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge, merge
milestone58.0a1
first release with
nightly linux32
179dae92e4d7 / 58.0a1 / 20171106100122 / files
nightly linux64
179dae92e4d7 / 58.0a1 / 20171106100122 / files
nightly mac
179dae92e4d7 / 58.0a1 / 20171106100122 / files
nightly win32
179dae92e4d7 / 58.0a1 / 20171106100122 / files
nightly win64
179dae92e4d7 / 58.0a1 / 20171106100122 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge mozilla-inbound to mozilla-central. r=merge a=merge
js/src/vm/StopIterationObject.h
layout/generic/nsTextFrame.cpp
layout/xul/nsTextBoxFrame.cpp
layout/xul/tree/nsTreeBodyFrame.cpp
--- a/dom/asmjscache/AsmJSCache.cpp
+++ b/dom/asmjscache/AsmJSCache.cpp
@@ -438,19 +438,19 @@ public:
 
   ParentRunnable(const PrincipalInfo& aPrincipalInfo,
                  OpenMode aOpenMode,
                  WriteParams aWriteParams)
   : mOwningEventTarget(GetCurrentThreadEventTarget()),
     mPrincipalInfo(aPrincipalInfo),
     mOpenMode(aOpenMode),
     mWriteParams(aWriteParams),
+    mOperationMayProceed(true),
     mState(eInitial),
     mResult(JS::AsmJSCache_InternalError),
-    mDeleteReceived(false),
     mActorDestroyed(false),
     mOpened(false)
   {
     MOZ_ASSERT(XRE_IsParentProcess());
     AssertIsOnOwningThread();
   }
 
 private:
@@ -481,46 +481,69 @@ private:
 
   void
   AssertIsOnNonOwningThread() const
   {
     MOZ_ASSERT(!IsOnBackgroundThread());
     MOZ_ASSERT(!IsOnOwningThread());
   }
 
+  bool
+  IsActorDestroyed() const
+  {
+    AssertIsOnOwningThread();
+
+    return mActorDestroyed;
+  }
+
+  // May be called on any thread, but you should call IsActorDestroyed() if
+  // you know you're on the background thread because it is slightly faster.
+  bool
+  OperationMayProceed() const
+  {
+    return mOperationMayProceed;
+  }
+
   // This method is called on the owning thread when the JS engine is finished
   // reading/writing the cache entry.
   void
   Close()
   {
     AssertIsOnOwningThread();
     MOZ_ASSERT(mState == eOpened);
+    MOZ_ASSERT(mResult == JS::AsmJSCache_Success);
 
     mState = eFinished;
 
     MOZ_ASSERT(mOpened);
+    mOpened = false;
 
     FinishOnOwningThread();
+
+    if (!mActorDestroyed) {
+      Unused << Send__delete__(this, mResult);
+    }
   }
 
   // This method is called upon any failure that prevents the eventual opening
   // of the cache entry.
   void
   Fail()
   {
     AssertIsOnOwningThread();
     MOZ_ASSERT(mState != eFinished);
+    MOZ_ASSERT(mResult != JS::AsmJSCache_Success);
 
     mState = eFinished;
 
     MOZ_ASSERT(!mOpened);
 
     FinishOnOwningThread();
 
-    if (!mDeleteReceived && !mActorDestroyed) {
+    if (!mActorDestroyed) {
       Unused << Send__delete__(this, mResult);
     }
   }
 
   // The same as method above but is intended to be called off the owning
   // thread.
   void
   FailOnNonOwningThread()
@@ -552,94 +575,130 @@ private:
   void
   FinishOnOwningThread();
 
   void
   DispatchToIOThread()
   {
     AssertIsOnOwningThread();
 
-    // If shutdown just started, the QuotaManager may have been deleted.
-    QuotaManager* qm = QuotaManager::Get();
-    if (!qm) {
-      FailOnNonOwningThread();
+    if (NS_WARN_IF(Client::IsShuttingDownOnBackgroundThread()) ||
+        IsActorDestroyed()) {
+      Fail();
       return;
     }
 
+    QuotaManager* qm = QuotaManager::Get();
+    MOZ_ASSERT(qm);
+
     nsresult rv = qm->IOThread()->Dispatch(this, NS_DISPATCH_NORMAL);
     if (NS_FAILED(rv)) {
-      FailOnNonOwningThread();
+      Fail();
       return;
     }
   }
 
   // OpenDirectoryListener overrides.
   void
   DirectoryLockAcquired(DirectoryLock* aLock) override;
 
   void
   DirectoryLockFailed() override;
 
   // IPDL methods.
-  mozilla::ipc::IPCResult
-  Recv__delete__(const JS::AsmJSCacheResult& aResult) override
-  {
-    AssertIsOnOwningThread();
-    MOZ_ASSERT(mState != eFinished);
-    MOZ_ASSERT(!mDeleteReceived);
-
-    mDeleteReceived = true;
-
-    if (mOpened) {
-      Close();
-    } else {
-      Fail();
-    }
-
-    MOZ_ASSERT(mState == eFinished);
-
-    return IPC_OK();
-  }
-
   void
   ActorDestroy(ActorDestroyReason why) override
   {
     AssertIsOnOwningThread();
     MOZ_ASSERT(!mActorDestroyed);
+    MOZ_ASSERT(mOperationMayProceed);
 
     mActorDestroyed = true;
-
-    // Assume ActorDestroy can happen at any time, so probe the current state to
-    // determine what needs to happen.
+    mOperationMayProceed = false;
 
-    if (mState == eFinished) {
-      return;
-    }
+    // Assume ActorDestroy can happen at any time, so we can't probe the
+    // current state since mState can be modified on any thread (only one
+    // thread at a time based on the state machine).
+    // However we can use mOpened which is only touched on the owning thread.
+    // If mOpened is true, we can also modify mState since we are guaranteed
+    // that there are no pending runnables which would probe mState to decide
+    // what code needs to run (there shouldn't be any running runnables on
+    // other threads either).
 
     if (mOpened) {
       Close();
-    } else {
-      Fail();
+
+      MOZ_ASSERT(mState == eFinished);
     }
 
-    MOZ_ASSERT(mState == eFinished);
+    // We don't have to call Fail() if mOpened is not true since it means that
+    // either nothing has been initialized yet, so nothing to cleanup or there
+    // are pending runnables that will detect that the actor has been destroyed
+    // and call Fail().
   }
 
   mozilla::ipc::IPCResult
-  RecvSelectCacheFileToRead(const uint32_t& aModuleIndex) override
+  RecvSelectCacheFileToRead(const OpenMetadataForReadResponse& aResponse)
+                            override
   {
     AssertIsOnOwningThread();
     MOZ_ASSERT(mState == eWaitingToOpenCacheFileForRead);
     MOZ_ASSERT(mOpenMode == eOpenForRead);
+    MOZ_ASSERT(!mOpened);
 
-    // A cache entry has been selected to open.
+    if (NS_WARN_IF(Client::IsShuttingDownOnBackgroundThread())) {
+      Fail();
+      return IPC_OK();
+    }
+
+    switch (aResponse.type()) {
+      case OpenMetadataForReadResponse::TAsmJSCacheResult: {
+        MOZ_ASSERT(aResponse.get_AsmJSCacheResult() != JS::AsmJSCache_Success);
+
+        mResult = aResponse.get_AsmJSCacheResult();
+
+        // This ParentRunnable can only be held alive by the IPDL. Fail()
+        // clears that last reference. So we need to add a self reference here.
+        RefPtr<ParentRunnable> kungFuDeathGrip = this;
+
+        Fail();
+
+        break;
+      }
+
+      case OpenMetadataForReadResponse::Tuint32_t:
+        // A cache entry has been selected to open.
+        mModuleIndex = aResponse.get_uint32_t();
 
-    mModuleIndex = aModuleIndex;
-    mState = eReadyToOpenCacheFileForRead;
-    DispatchToIOThread();
+        mState = eReadyToOpenCacheFileForRead;
+
+        DispatchToIOThread();
+
+        break;
+
+      default:
+        MOZ_CRASH("Should never get here!");
+    }
+
+    return IPC_OK();
+  }
+
+  mozilla::ipc::IPCResult
+  RecvClose() override
+  {
+    AssertIsOnOwningThread();
+    MOZ_ASSERT(mState == eOpened);
+
+    // This ParentRunnable can only be held alive by the IPDL. Close() clears
+    // that last reference. So we need to add a self reference here.
+    RefPtr<ParentRunnable> kungFuDeathGrip = this;
+
+    Close();
+
+    MOZ_ASSERT(mState == eFinished);
 
     return IPC_OK();
   }
 
   nsCOMPtr<nsIEventTarget> mOwningEventTarget;
   const PrincipalInfo mPrincipalInfo;
   const OpenMode mOpenMode;
   const WriteParams mWriteParams;
@@ -650,16 +709,18 @@ private:
   nsCString mOrigin;
   RefPtr<DirectoryLock> mDirectoryLock;
 
   // State initialized during eReadyToReadMetadata
   nsCOMPtr<nsIFile> mDirectory;
   nsCOMPtr<nsIFile> mMetadataFile;
   Metadata mMetadata;
 
+  Atomic<bool> mOperationMayProceed;
+
   // State initialized during eWaitingToOpenCacheFileForRead
   unsigned mModuleIndex;
 
   enum State {
     eInitial, // Just created, waiting to be dispatched to main thread
     eWaitingToFinishInit, // Waiting to finish initialization
     eWaitingToOpenDirectory, // Waiting to open directory
     eWaitingToOpenMetadata, // Waiting to be called back from OpenDirectory
@@ -670,17 +731,16 @@ private:
     eSendingCacheFile, // Waiting to send OnOpenCacheFile on the owning thread
     eOpened, // Finished calling OnOpenCacheFile, waiting to be closed
     eFailing, // Just failed, waiting to be dispatched to the owning thread
     eFinished, // Terminal state
   };
   State mState;
   JS::AsmJSCacheResult mResult;
 
-  bool mDeleteReceived;
   bool mActorDestroyed;
   bool mOpened;
 };
 
 nsresult
 ParentRunnable::InitOnMainThread()
 {
   MOZ_ASSERT(NS_IsMainThread());
@@ -911,32 +971,39 @@ ParentRunnable::Run()
   nsresult rv;
 
   // All success/failure paths must eventually call Finish() to avoid leaving
   // the parser hanging.
   switch (mState) {
     case eInitial: {
       MOZ_ASSERT(NS_IsMainThread());
 
+      if (NS_WARN_IF(Client::IsShuttingDownOnNonBackgroundThread()) ||
+          !OperationMayProceed()) {
+        FailOnNonOwningThread();
+        return NS_OK;
+      }
+
       rv = InitOnMainThread();
       if (NS_FAILED(rv)) {
         FailOnNonOwningThread();
         return NS_OK;
       }
 
       mState = eWaitingToFinishInit;
       MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget->Dispatch(this, NS_DISPATCH_NORMAL));
 
       return NS_OK;
     }
 
     case eWaitingToFinishInit: {
       AssertIsOnOwningThread();
 
-      if (QuotaManager::IsShuttingDown()) {
+      if (NS_WARN_IF(Client::IsShuttingDownOnBackgroundThread()) ||
+          IsActorDestroyed()) {
         Fail();
         return NS_OK;
       }
 
       if (QuotaManager::Get()) {
         OpenDirectory();
         return NS_OK;
       }
@@ -945,28 +1012,40 @@ ParentRunnable::Run()
       QuotaManager::GetOrCreate(this);
 
       return NS_OK;
     }
 
     case eWaitingToOpenDirectory: {
       AssertIsOnOwningThread();
 
+      if (NS_WARN_IF(Client::IsShuttingDownOnBackgroundThread()) ||
+          IsActorDestroyed()) {
+        Fail();
+        return NS_OK;
+      }
+
       if (NS_WARN_IF(!QuotaManager::Get())) {
         Fail();
         return NS_OK;
       }
 
       OpenDirectory();
       return NS_OK;
     }
 
     case eReadyToReadMetadata: {
       AssertIsOnIOThread();
 
+      if (NS_WARN_IF(Client::IsShuttingDownOnNonBackgroundThread()) ||
+          !OperationMayProceed()) {
+        FailOnNonOwningThread();
+        return NS_OK;
+      }
+
       rv = ReadMetadata();
       if (NS_FAILED(rv)) {
         FailOnNonOwningThread();
         return NS_OK;
       }
 
       if (mOpenMode == eOpenForRead) {
         mState = eSendingMetadataForRead;
@@ -985,58 +1064,78 @@ ParentRunnable::Run()
       MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget->Dispatch(this, NS_DISPATCH_NORMAL));
       return NS_OK;
     }
 
     case eSendingMetadataForRead: {
       AssertIsOnOwningThread();
       MOZ_ASSERT(mOpenMode == eOpenForRead);
 
+      if (NS_WARN_IF(Client::IsShuttingDownOnBackgroundThread()) ||
+          IsActorDestroyed()) {
+        Fail();
+        return NS_OK;
+      }
+
       mState = eWaitingToOpenCacheFileForRead;
 
       // Metadata is now open.
       if (!SendOnOpenMetadataForRead(mMetadata)) {
         Fail();
         return NS_OK;
       }
 
       return NS_OK;
     }
 
     case eReadyToOpenCacheFileForRead: {
       AssertIsOnIOThread();
       MOZ_ASSERT(mOpenMode == eOpenForRead);
 
+      if (NS_WARN_IF(Client::IsShuttingDownOnNonBackgroundThread()) ||
+          !OperationMayProceed()) {
+        FailOnNonOwningThread();
+        return NS_OK;
+      }
+
       rv = OpenCacheFileForRead();
       if (NS_FAILED(rv)) {
         FailOnNonOwningThread();
         return NS_OK;
       }
 
       mState = eSendingCacheFile;
       MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget->Dispatch(this, NS_DISPATCH_NORMAL));
       return NS_OK;
     }
 
     case eSendingCacheFile: {
       AssertIsOnOwningThread();
 
-      mState = eOpened;
+      if (NS_WARN_IF(Client::IsShuttingDownOnBackgroundThread()) ||
+          IsActorDestroyed()) {
+        Fail();
+        return NS_OK;
+      }
 
-      // The entry is now open.
-      MOZ_ASSERT(!mOpened);
-      mOpened = true;
+      mState = eOpened;
 
       FileDescriptor::PlatformHandleType handle =
         FileDescriptor::PlatformHandleType(PR_FileDesc2NativeHandle(mFileDesc));
       if (!SendOnOpenCacheFile(mFileSize, FileDescriptor(handle))) {
         Fail();
         return NS_OK;
       }
 
+      // The entry is now open.
+      MOZ_ASSERT(!mOpened);
+      mOpened = true;
+
+      mResult = JS::AsmJSCache_Success;
+
       return NS_OK;
     }
 
     case eFailing: {
       AssertIsOnOwningThread();
 
       Fail();
 
@@ -1286,25 +1385,26 @@ private:
   // IPDL methods.
   mozilla::ipc::IPCResult
   RecvOnOpenMetadataForRead(const Metadata& aMetadata) override
   {
     MOZ_ASSERT(NS_IsMainThread());
     MOZ_ASSERT(mState == eOpening);
 
     uint32_t moduleIndex;
-    if (!FindHashMatch(aMetadata, mReadParams, &moduleIndex)) {
-      Fail(JS::AsmJSCache_InternalError);
-      Send__delete__(this, JS::AsmJSCache_InternalError);
-      return IPC_OK();
+    bool ok;
+    if (FindHashMatch(aMetadata, mReadParams, &moduleIndex)) {
+      ok = SendSelectCacheFileToRead(moduleIndex);
+    } else {
+      ok = SendSelectCacheFileToRead(JS::AsmJSCache_InternalError);
+    }
+    if (!ok) {
+      return IPC_FAIL_NO_REASON(this);
     }
 
-    if (!SendSelectCacheFileToRead(moduleIndex)) {
-      return IPC_FAIL_NO_REASON(this);
-    }
     return IPC_OK();
   }
 
   mozilla::ipc::IPCResult
   RecvOnOpenCacheFile(const int64_t& aFileSize,
                       const FileDescriptor& aFileDesc) override
   {
     MOZ_ASSERT(NS_IsMainThread());
@@ -1322,19 +1422,30 @@ private:
     Notify(JS::AsmJSCache_Success);
     return IPC_OK();
   }
 
   mozilla::ipc::IPCResult
   Recv__delete__(const JS::AsmJSCacheResult& aResult) override
   {
     MOZ_ASSERT(NS_IsMainThread());
-    MOZ_ASSERT(mState == eOpening);
+    MOZ_ASSERT(mState == eOpening || mState == eFinishing);
+    MOZ_ASSERT_IF(mState == eOpening, aResult != JS::AsmJSCache_Success);
+    MOZ_ASSERT_IF(mState == eFinishing, aResult == JS::AsmJSCache_Success);
 
-    Fail(aResult);
+    if (mState == eOpening) {
+      Fail(aResult);
+    } else {
+      // Match the AddRef in BlockUntilOpen(). The IPDL still holds an
+      // outstanding ref which will keep 'this' alive until ActorDestroy()
+      // is executed.
+      Release();
+
+      mState = eFinished;
+    }
     return IPC_OK();
   }
 
   void
   ActorDestroy(ActorDestroyReason why) override
   {
     MOZ_ASSERT(NS_IsMainThread());
     NoteActorDestroyed();
@@ -1387,20 +1498,20 @@ private:
   ReadParams mReadParams;
   Mutex mMutex;
   CondVar mCondVar;
 
   // Couple enums and bools together
   const OpenMode mOpenMode;
   enum State {
     eInitial, // Just created, waiting to be dispatched to the main thread
-    eBackgroundChildPending, // Waiting for the background child to be created
     eOpening, // Waiting for the parent process to respond
     eOpened, // Parent process opened the entry and sent it back
     eClosing, // Waiting to be dispatched to the main thread to Send__delete__
+    eFinishing, // Waiting for the parent process to close
     eFinished // Terminal state
   };
   State mState;
   JS::AsmJSCacheResult mResult;
 
   bool mActorDestroyed;
   bool mWaiting;
   bool mOpened;
@@ -1450,38 +1561,41 @@ ChildRunnable::Run()
       return NS_OK;
     }
 
     case eClosing: {
       MOZ_ASSERT(NS_IsMainThread());
 
       // Per FileDescriptorHolder::Finish()'s comment, call before
       // releasing the directory lock (which happens in the parent upon receipt
-      // of the Send__delete__ message).
+      // of the Close message).
       FileDescriptorHolder::Finish();
 
       MOZ_ASSERT(mOpened);
       mOpened = false;
 
-      // Match the AddRef in BlockUntilOpen(). The main thread event loop still
-      // holds an outstanding ref which will keep 'this' alive until returning to
-      // the event loop.
-      Release();
+      if (mActorDestroyed) {
+        // Match the AddRef in BlockUntilOpen(). The main thread event loop
+        // still holds an outstanding ref which will keep 'this' alive until
+        // returning to the event loop.
+        Release();
 
-      if (!mActorDestroyed) {
-        Unused << Send__delete__(this, JS::AsmJSCache_Success);
+        mState = eFinished;
+      } else {
+        Unused << SendClose();
+
+        mState = eFinishing;
       }
 
-      mState = eFinished;
       return NS_OK;
     }
 
-    case eBackgroundChildPending:
     case eOpening:
     case eOpened:
+    case eFinishing:
     case eFinished: {
       MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Shouldn't Run() in this state");
     }
   }
 
   MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Corrupt state");
   return NS_OK;
 }
--- a/dom/asmjscache/PAsmJSCacheEntry.ipdl
+++ b/dom/asmjscache/PAsmJSCacheEntry.ipdl
@@ -6,32 +6,48 @@ include protocol PBackground;
 
 using mozilla::dom::asmjscache::Metadata from "mozilla/dom/asmjscache/AsmJSCache.h";
 using JS::AsmJSCacheResult from "mozilla/dom/asmjscache/AsmJSCache.h";
 
 namespace mozilla {
 namespace dom {
 namespace asmjscache {
 
+union OpenMetadataForReadResponse
+{
+  AsmJSCacheResult;
+  uint32_t;
+};
+
 protocol PAsmJSCacheEntry
 {
   manager PBackground;
 
   // When the cache is opened to read, the parent process sends over the
   // origin's Metadata so the child process can select the cache entry to open
   // (based on hash) and notify the parent (via SelectCacheFileToRead).
 child:
   async OnOpenMetadataForRead(Metadata metadata);
 parent:
-  async SelectCacheFileToRead(uint32_t moduleIndex);
+  async SelectCacheFileToRead(OpenMetadataForReadResponse response);
 
 child:
   // Once the cache file has been opened, the child is notified and sent an
   // open file descriptor.
   async OnOpenCacheFile(int64_t fileSize, FileDescriptor fileDesc);
 
-both:
+parent:
+  // When the child process is done with the cache entry, the parent process
+  // is notified (via Close).
+  async Close();
+
+child:
+  // When there's an error during the opening phase, the child process is
+  // notified (via __delete__) and sent an error result.
+  // When the parent process receives the Close message, it closes the cache
+  // entry on the parent side and the child is notified (via __delete__).
+  // The protocol is destroyed in both cases.
   async __delete__(AsmJSCacheResult result);
 };
 
 } // namespace asmjscache
 } // namespace dom
 } // namespace mozilla
--- a/dom/tests/mochitest/general/test_interfaces.js
+++ b/dom/tests/mochitest/general/test_interfaces.js
@@ -58,17 +58,16 @@ var ecmaGlobals =
     "RangeError",
     {name: "ReadableStream", disabled: !SpecialPowers.Cu.getJSTestingFunctions().streamsAreEnabled()},
     "ReferenceError",
     "Reflect",
     "RegExp",
     "Set",
     "SharedArrayBuffer",
     {name: "SIMD", nightly: true},
-    "StopIteration",
     "String",
     "Symbol",
     "SyntaxError",
     {name: "TypedObject", nightly: true},
     "TypeError",
     "Uint16Array",
     "Uint32Array",
     "Uint8Array",
--- a/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js
+++ b/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js
@@ -53,17 +53,16 @@ var ecmaGlobals =
     "RangeError",
     {name: "ReadableStream", optional: true},
     "ReferenceError",
     "Reflect",
     "RegExp",
     "Set",
     "SharedArrayBuffer",
     {name: "SIMD", nightly: true},
-    "StopIteration",
     "String",
     "Symbol",
     "SyntaxError",
     {name: "TypedObject", nightly: true},
     "TypeError",
     "Uint16Array",
     "Uint32Array",
     "Uint8Array",
--- a/dom/workers/test/test_worker_interfaces.js
+++ b/dom/workers/test/test_worker_interfaces.js
@@ -53,17 +53,16 @@ var ecmaGlobals =
     "RangeError",
     {name: "ReadableStream", optional: true},
     "ReferenceError",
     "Reflect",
     "RegExp",
     "Set",
     "SharedArrayBuffer",
     {name: "SIMD", nightly: true},
-    "StopIteration",
     "String",
     "Symbol",
     "SyntaxError",
     {name: "TypedObject", nightly: true},
     "TypeError",
     "Uint16Array",
     "Uint32Array",
     "Uint8Array",
--- a/js/ipc/JavaScriptTypes.ipdlh
+++ b/js/ipc/JavaScriptTypes.ipdlh
@@ -90,20 +90,16 @@ union JSIDVariant
     nsString;
     int32_t;
 };
 
 struct ReturnSuccess
 {
 };
 
-struct ReturnStopIteration
-{
-};
-
 struct ReturnDeadCPOW
 {
 };
 
 struct ReturnException
 {
     JSVariant exn;
 };
@@ -111,17 +107,16 @@ struct ReturnException
 struct ReturnObjectOpResult
 {
     uint32_t code;
 };
 
 union ReturnStatus
 {
     ReturnSuccess;
-    ReturnStopIteration;
     ReturnDeadCPOW;
     ReturnException;
     ReturnObjectOpResult;
 };
 
 union JSParam
 {
     void_t;     /* value is strictly an xpc out param */
--- a/js/ipc/WrapperAnswer.cpp
+++ b/js/ipc/WrapperAnswer.cpp
@@ -57,21 +57,16 @@ WrapperAnswer::fail(AutoJSAPI& jsapi, Re
     JSContext* cx = jsapi.cx();
     RootedValue exn(cx);
     if (!jsapi.HasException())
         return true;
 
     if (!jsapi.StealException(&exn))
         return true;
 
-    if (JS_IsStopIteration(exn)) {
-        *rs = ReturnStatus(ReturnStopIteration());
-        return true;
-    }
-
     // If this fails, we still don't want to exit. Just return an invalid
     // exception.
     (void) toVariant(cx, exn, &rs->get_ReturnException().exn());
     return true;
 }
 
 bool
 WrapperAnswer::ok(ReturnStatus* rs)
--- a/js/ipc/WrapperOwner.cpp
+++ b/js/ipc/WrapperOwner.cpp
@@ -1071,19 +1071,16 @@ WrapperOwner::ipcfail(JSContext* cx)
 }
 
 bool
 WrapperOwner::ok(JSContext* cx, const ReturnStatus& status)
 {
     if (status.type() == ReturnStatus::TReturnSuccess)
         return true;
 
-    if (status.type() == ReturnStatus::TReturnStopIteration)
-        return JS_ThrowStopIteration(cx);
-
     if (status.type() == ReturnStatus::TReturnDeadCPOW) {
         JS_ReportErrorASCII(cx, "operation not possible on dead CPOW");
         return false;
     }
 
     RootedValue exn(cx);
     if (!fromVariant(cx, status.get_ReturnException().exn(), &exn))
         return false;
--- a/js/src/jit-test/tests/basic/bug547911-1.js
+++ b/js/src/jit-test/tests/basic/bug547911-1.js
@@ -1,9 +1,9 @@
 // |jit-test| need-for-each
 
 a = b = c = d = 0;
-this.__defineGetter__("e", function () { throw StopIteration; })
+this.__defineGetter__("e", function () { throw Math; })
 try {
     for each(f in this) {}
 } catch (exc) {
-    assertEq(exc, StopIteration);
+    assertEq(exc, Math);
 }
--- a/js/src/jit-test/tests/basic/bug547911-2.js
+++ b/js/src/jit-test/tests/basic/bug547911-2.js
@@ -1,9 +1,9 @@
 // |jit-test| need-for-each
 
-var obj = {a: 0, b: 0, c: 0, d: 0, get e() { throw StopIteration; }};
+var obj = {a: 0, b: 0, c: 0, d: 0, get e() { throw Math; }};
 try {
     for each (x in obj) {}
     FAIL;
 } catch (exc) {
-    assertEq(exc, StopIteration);
+    assertEq(exc, Math);
 }
--- a/js/src/jit-test/tests/basic/testDeepBailFromHasInstance.js
+++ b/js/src/jit-test/tests/basic/testDeepBailFromHasInstance.js
@@ -1,9 +1,9 @@
-var arr = [StopIteration, StopIteration, StopIteration, StopIteration, {}];
+var arr = [Math, Math, Math, Math, {}];
 var obj = {};
 var x;
 var result = 'no error';
 try {
     for (var i = 0; i < arr.length; i++)
         x = (obj instanceof arr[i]);  // last iteration throws, triggering deep bail
 } catch (exc) {
     result = exc.constructor.name;
--- a/js/src/jit-test/tests/collections/Map-forEach.js
+++ b/js/src/jit-test/tests/collections/Map-forEach.js
@@ -44,16 +44,15 @@ assertThrowsInstanceOf(function() {
     Map.prototype.forEach.call(s, callback);
 }, TypeError, "Map.prototype.forEach should raise TypeError if not used on a Map");
 
 var fn = 2;
 assertThrowsInstanceOf(function() {
     initialMap.forEach(fn);
 }, TypeError, "Map.prototype.forEach should raise TypeError if callback is not a function");
 
-// testing that Map#forEach uses internal next() function and does not stop when
-// StopIteration exception is thrown
+// testing that Map#forEach uses internal next() function.
 
 var m = new Map([["one", 1]]);
 Object.getPrototypeOf(m[Symbol.iterator]()).next = function () { throw "FAIL"; };
-assertThrowsInstanceOf(function () {
-  m.forEach(function () { throw StopIteration; });
-}, StopIteration, "Map.prototype.forEach should use intrinsic next method.");
+assertThrowsValue(function () {
+  m.forEach(function () { throw Math; });
+}, Math, "Map.prototype.forEach should use intrinsic next method.");
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -77,17 +77,16 @@
 #include "vm/ErrorObject.h"
 #include "vm/HelperThreads.h"
 #include "vm/Interpreter.h"
 #include "vm/RegExpStatics.h"
 #include "vm/Runtime.h"
 #include "vm/SavedStacks.h"
 #include "vm/SelfHosting.h"
 #include "vm/Shape.h"
-#include "vm/StopIterationObject.h"
 #include "vm/String.h"
 #include "vm/StringBuffer.h"
 #include "vm/Symbol.h"
 #include "vm/WrapperObject.h"
 #include "vm/Xdr.h"
 #include "wasm/AsmJS.h"
 #include "wasm/WasmModule.h"
 
@@ -7117,29 +7116,16 @@ JSErrorNotes::begin()
 }
 
 JS_PUBLIC_API(JSErrorNotes::iterator)
 JSErrorNotes::end()
 {
     return iterator(notes_.end());
 }
 
-JS_PUBLIC_API(bool)
-JS_ThrowStopIteration(JSContext* cx)
-{
-    AssertHeapIsIdle();
-    return ThrowStopIteration(cx);
-}
-
-JS_PUBLIC_API(bool)
-JS_IsStopIteration(const Value& v)
-{
-    return v.isObject() && v.toObject().is<StopIterationObject>();
-}
-
 extern MOZ_NEVER_INLINE JS_PUBLIC_API(void)
 JS_AbortIfWrongThread(JSContext* cx)
 {
     if (!CurrentThreadCanAccessRuntime(cx->runtime()))
         MOZ_CRASH();
     if (TlsContext.get() != cx)
         MOZ_CRASH();
 }
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -6195,25 +6195,16 @@ JS_ErrorFromException(JSContext* cx, JS:
  * cross-compartment wrapper for one), return the stack for that exception, if
  * any.  Will return null if the given object is not an exception object
  * (including if it's null or a security wrapper that can't be unwrapped) or if
  * the exception has no stack.
  */
 extern JS_PUBLIC_API(JSObject*)
 ExceptionStackOrNull(JS::HandleObject obj);
 
-/*
- * Throws a StopIteration exception on cx.
- */
-extern JS_PUBLIC_API(bool)
-JS_ThrowStopIteration(JSContext* cx);
-
-extern JS_PUBLIC_API(bool)
-JS_IsStopIteration(const JS::Value& v);
-
 /**
  * A JS context always has an "owner thread". The owner thread is set when the
  * context is created (to the current thread) and practically all entry points
  * into the JS engine check that a context (or anything contained in the
  * context: runtime, compartment, object, etc) is only touched by its owner
  * thread. Embeddings may check this invariant outside the JS engine by calling
  * JS_AbortIfWrongThread (which will abort if not on the owner thread, even for
  * non-debug builds).
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -19,17 +19,16 @@
 #include "gc/Policy.h"
 #include "jit/JitCompartment.h"
 #include "jit/JitOptions.h"
 #include "js/Date.h"
 #include "js/Proxy.h"
 #include "js/RootingAPI.h"
 #include "proxy/DeadObjectProxy.h"
 #include "vm/Debugger.h"
-#include "vm/StopIterationObject.h"
 #include "vm/WrapperObject.h"
 
 #include "jsatominlines.h"
 #include "jsfuninlines.h"
 #include "jsgcinlines.h"
 #include "jsobjinlines.h"
 #include "jsscriptinlines.h"
 
@@ -390,27 +389,16 @@ JSCompartment::getNonWrapperObjectForCur
     // particular wrapper.
     RootedObject objectPassedToWrap(cx, obj);
     obj.set(UncheckedUnwrap(obj, /* stopAtWindowProxy = */ true));
     if (obj->compartment() == this) {
         MOZ_ASSERT(!IsWindow(obj));
         return true;
     }
 
-    // Translate StopIteration singleton.
-    if (obj->is<StopIterationObject>()) {
-        // StopIteration isn't a constructor, but it's stored in GlobalObject
-        // as one, out of laziness. Hence the GetBuiltinConstructor call here.
-        RootedObject stopIteration(cx);
-        if (!GetBuiltinConstructor(cx, JSProto_StopIteration, &stopIteration))
-            return false;
-        obj.set(stopIteration);
-        return true;
-    }
-
     // Invoke the prewrap callback. The prewrap callback is responsible for
     // doing similar reification as above, but can account for any additional
     // embedder requirements.
     //
     // We're a bit worried about infinite recursion here, so we do a check -
     // see bug 809295.
     auto preWrap = cx->runtime()->wrapObjectCallbacks->preWrap;
     if (!CheckSystemRecursionLimit(cx))
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -26,17 +26,16 @@
 
 #include "ds/Sort.h"
 #include "gc/Marking.h"
 #include "js/Proxy.h"
 #include "vm/GeneratorObject.h"
 #include "vm/GlobalObject.h"
 #include "vm/Interpreter.h"
 #include "vm/Shape.h"
-#include "vm/StopIterationObject.h"
 #include "vm/TypedArrayObject.h"
 
 #include "jsscriptinlines.h"
 
 #include "vm/NativeObject-inl.h"
 #include "vm/ReceiverGuard-inl.h"
 #include "vm/Stack-inl.h"
 #include "vm/String-inl.h"
@@ -532,18 +531,16 @@ Snapshot(JSContext* cx, HandleObject pob
 JS_FRIEND_API(bool)
 js::GetPropertyKeys(JSContext* cx, HandleObject obj, unsigned flags, AutoIdVector* props)
 {
     return Snapshot(cx, obj,
                     flags & (JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS | JSITER_SYMBOLSONLY),
                     props);
 }
 
-static bool property_iterator_next(JSContext* cx, unsigned argc, Value* vp);
-
 static inline PropertyIteratorObject*
 NewPropertyIteratorObject(JSContext* cx, unsigned flags)
 {
     if (flags & JSITER_ENUMERATE) {
         RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &PropertyIteratorObject::class_,
                                                                  TaggedProto(nullptr)));
         if (!group)
             return nullptr;
@@ -564,36 +561,17 @@ NewPropertyIteratorObject(JSContext* cx,
         // CodeGenerator::visitIteratorStartO assumes the iterator object is not
         // inside the nursery when deciding whether a barrier is necessary.
         MOZ_ASSERT(!js::gc::IsInsideNursery(res));
 
         MOZ_ASSERT(res->numFixedSlots() == JSObject::ITER_CLASS_NFIXED_SLOTS);
         return res;
     }
 
-    Rooted<PropertyIteratorObject*> res(cx, NewBuiltinClassInstance<PropertyIteratorObject>(cx));
-    if (!res)
-        return nullptr;
-
-    if (flags == 0) {
-        // Redefine next as an own property. This ensure that deleting the
-        // next method on the prototype doesn't break cross-global for .. in.
-        // We don't have to do this for JSITER_ENUMERATE because that object always
-        // takes an optimized path.
-        RootedFunction next(cx, NewNativeFunction(cx, property_iterator_next, 0,
-                                                  HandlePropertyName(cx->names().next)));
-        if (!next)
-            return nullptr;
-
-        RootedValue value(cx, ObjectValue(*next));
-        if (!DefineDataProperty(cx, res, cx->names().next, value))
-            return nullptr;
-    }
-
-    return res;
+    return NewBuiltinClassInstance<PropertyIteratorObject>(cx);
 }
 
 NativeIterator*
 NativeIterator::allocateIterator(JSContext* cx, uint32_t numGuards, uint32_t plength)
 {
     JS_STATIC_ASSERT(sizeof(ReceiverGuard) == 2 * sizeof(void*));
 
     size_t extraLength = plength + numGuards * 2;
@@ -1050,38 +1028,23 @@ JSCompartment::getOrCreateIterResultTemp
     MOZ_ASSERT(shape->slot() == JSCompartment::IterResultObjectDoneSlot &&
                shape->propidRef() == NameToId(cx->names().done));
 
     iterResultTemplate_.set(templateObject);
 
     return iterResultTemplate_;
 }
 
-bool
-js::ThrowStopIteration(JSContext* cx)
-{
-    MOZ_ASSERT(!JS_IsExceptionPending(cx));
-
-    // StopIteration isn't a constructor, but it's stored in GlobalObject
-    // as one, out of laziness. Hence the GetBuiltinConstructor call here.
-    RootedObject ctor(cx);
-    if (GetBuiltinConstructor(cx, JSProto_StopIteration, &ctor))
-        cx->setPendingException(ObjectValue(*ctor));
-    return false;
-}
-
 /*** Iterator objects ****************************************************************************/
 
 MOZ_ALWAYS_INLINE bool
-NativeIteratorNext(JSContext* cx, NativeIterator* ni, MutableHandleValue rval, bool* done)
+NativeIteratorNext(JSContext* cx, NativeIterator* ni, MutableHandleValue rval)
 {
-    *done = false;
-
     if (ni->props_cursor >= ni->props_end) {
-        *done = true;
+        rval.setMagic(JS_NO_ITER_VALUE);
         return true;
     }
 
     if (MOZ_LIKELY(ni->isKeyIter())) {
         rval.setString(*ni->current());
         ni->incCursor();
         return true;
     }
@@ -1100,46 +1063,16 @@ NativeIteratorNext(JSContext* cx, Native
 }
 
 bool
 js::IsPropertyIterator(HandleValue v)
 {
     return v.isObject() && v.toObject().is<PropertyIteratorObject>();
 }
 
-MOZ_ALWAYS_INLINE bool
-property_iterator_next_impl(JSContext* cx, const CallArgs& args)
-{
-    MOZ_ASSERT(IsPropertyIterator(args.thisv()));
-
-    RootedObject thisObj(cx, &args.thisv().toObject());
-
-    NativeIterator* ni = thisObj.as<PropertyIteratorObject>()->getNativeIterator();
-    RootedValue value(cx);
-    bool done;
-    if (!NativeIteratorNext(cx, ni, &value, &done))
-         return false;
-
-    // Use old iterator protocol for compatibility reasons.
-    if (done) {
-        ThrowStopIteration(cx);
-        return false;
-    }
-
-    args.rval().set(value);
-    return true;
-}
-
-static bool
-property_iterator_next(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    return CallNonGenericMethod<IsPropertyIterator, property_iterator_next_impl>(cx, args);
-}
-
 size_t
 PropertyIteratorObject::sizeOfMisc(mozilla::MallocSizeOf mallocSizeOf) const
 {
     return mallocSizeOf(getPrivate());
 }
 
 void
 PropertyIteratorObject::trace(JSTracer* trc, JSObject* obj)
@@ -1484,82 +1417,42 @@ js::SuppressDeletedElement(JSContext* cx
         return false;
     return SuppressDeletedPropertyHelper(cx, obj, SingleStringPredicate(str));
 }
 
 bool
 js::IteratorMore(JSContext* cx, HandleObject iterobj, MutableHandleValue rval)
 {
     // Fast path for native iterators.
-    if (iterobj->is<PropertyIteratorObject>()) {
+    if (MOZ_LIKELY(iterobj->is<PropertyIteratorObject>())) {
         NativeIterator* ni = iterobj->as<PropertyIteratorObject>().getNativeIterator();
-        bool done;
-        if (!NativeIteratorNext(cx, ni, rval, &done))
-            return false;
-
-        if (done)
-            rval.setMagic(JS_NO_ITER_VALUE);
-        return true;
+        return NativeIteratorNext(cx, ni, rval);
     }
 
-    // We're reentering below and can call anything.
-    if (!CheckRecursionLimit(cx))
+    if (JS_IsDeadWrapper(iterobj)) {
+        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
         return false;
+    }
 
-    // Call the iterator object's .next method.
-    if (!GetProperty(cx, iterobj, iterobj, cx->names().next, rval))
+    MOZ_ASSERT(IsWrapper(iterobj));
+
+    RootedObject obj(cx, CheckedUnwrap(iterobj));
+    if (!obj)
         return false;
 
-    // Call the .next method.  Fall through to the error-handling cases in the
-    // unlikely event that either one of the fallible operations performed
-    // during the call process fails.
-    FixedInvokeArgs<0> args(cx);
-    RootedValue iterval(cx, ObjectValue(*iterobj));
-    if (!js::Call(cx, rval, iterval, args, rval)) {
-        // Check for StopIteration.
-        if (!cx->isExceptionPending())
+    MOZ_RELEASE_ASSERT(obj->is<PropertyIteratorObject>());
+    {
+        AutoCompartment ac(cx, obj);
+        NativeIterator* ni = obj->as<PropertyIteratorObject>().getNativeIterator();
+        if (!NativeIteratorNext(cx, ni, rval))
             return false;
-        RootedValue exception(cx);
-        if (!cx->getPendingException(&exception))
-            return false;
-        if (!JS_IsStopIteration(exception))
-            return false;
-
-        cx->clearPendingException();
-        rval.setMagic(JS_NO_ITER_VALUE);
     }
-
-    return true;
+    return cx->compartment()->wrap(cx, rval);
 }
 
-static bool
-stopiter_hasInstance(JSContext* cx, HandleObject obj, MutableHandleValue v, bool* bp)
-{
-    *bp = JS_IsStopIteration(v);
-    return true;
-}
-
-static const ClassOps StopIterationObjectClassOps = {
-    nullptr, /* addProperty */
-    nullptr, /* delProperty */
-    nullptr, /* enumerate */
-    nullptr, /* enumerate */
-    nullptr, /* resolve */
-    nullptr, /* mayResolve */
-    nullptr, /* finalize */
-    nullptr, /* call */
-    stopiter_hasInstance
-};
-
-const Class StopIterationObject::class_ = {
-    "StopIteration",
-    JSCLASS_HAS_CACHED_PROTO(JSProto_StopIteration),
-    &StopIterationObjectClassOps
-};
-
 static const JSFunctionSpec iterator_proto_methods[] = {
     JS_SELF_HOSTED_SYM_FN(iterator, "IteratorIdentity", 0, 0),
     JS_FS_END
 };
 
 /* static */ bool
 GlobalObject::initIteratorProto(JSContext* cx, Handle<GlobalObject*> global)
 {
@@ -1616,28 +1509,8 @@ GlobalObject::initStringIteratorProto(JS
         !DefineToStringTag(cx, proto, cx->names().StringIterator))
     {
         return false;
     }
 
     global->setReservedSlot(STRING_ITERATOR_PROTO, ObjectValue(*proto));
     return true;
 }
-
-JSObject*
-js::InitStopIterationClass(JSContext* cx, HandleObject obj)
-{
-    Handle<GlobalObject*> global = obj.as<GlobalObject>();
-    if (!global->getPrototype(JSProto_StopIteration).isObject()) {
-        RootedObject proto(cx, GlobalObject::createBlankPrototype(cx, global,
-                                                                  &StopIterationObject::class_));
-        if (!proto || !FreezeObject(cx, proto))
-            return nullptr;
-
-        // This should use a non-JSProtoKey'd slot, but this is easier for now.
-        if (!GlobalObject::initBuiltinConstructor(cx, global, JSProto_StopIteration, proto, proto))
-            return nullptr;
-
-        global->setConstructor(JSProto_StopIteration, ObjectValue(*proto));
-    }
-
-    return &global->getPrototype(JSProto_StopIteration).toObject();
-}
--- a/js/src/jsiter.h
+++ b/js/src/jsiter.h
@@ -199,29 +199,23 @@ SuppressDeletedElement(JSContext* cx, Ha
 
 /*
  * IteratorMore() returns the next iteration value. If no value is available,
  * MagicValue(JS_NO_ITER_VALUE) is returned.
  */
 extern bool
 IteratorMore(JSContext* cx, HandleObject iterobj, MutableHandleValue rval);
 
-extern bool
-ThrowStopIteration(JSContext* cx);
-
 /*
  * Create an object of the form { value: VALUE, done: DONE }.
  * ES 2017 draft 7.4.7.
  */
 extern JSObject*
 CreateIterResultObject(JSContext* cx, HandleValue value, bool done);
 
 bool
 IsPropertyIterator(HandleValue v);
 
-extern JSObject*
-InitStopIterationClass(JSContext* cx, HandleObject obj);
-
 enum class IteratorKind { Sync, Async };
 
 } /* namespace js */
 
 #endif /* jsiter_h */
--- a/js/src/jsprototypes.h
+++ b/js/src/jsprototypes.h
@@ -80,17 +80,16 @@
     real(SyntaxError,           InitViaClassSpec,       ERROR_CLASP(JSEXN_SYNTAXERR)) \
     real(TypeError,             InitViaClassSpec,       ERROR_CLASP(JSEXN_TYPEERR)) \
     real(URIError,              InitViaClassSpec,       ERROR_CLASP(JSEXN_URIERR)) \
     real(DebuggeeWouldRun,      InitViaClassSpec,       ERROR_CLASP(JSEXN_DEBUGGEEWOULDRUN)) \
     real(CompileError,          InitViaClassSpec,       ERROR_CLASP(JSEXN_WASMCOMPILEERROR)) \
     real(LinkError,             InitViaClassSpec,       ERROR_CLASP(JSEXN_WASMLINKERROR)) \
     real(RuntimeError,          InitViaClassSpec,       ERROR_CLASP(JSEXN_WASMRUNTIMEERROR)) \
     imaginary(Iterator,         dummy,                  dummy) \
-    real(StopIteration,         InitStopIterationClass, OCLASP(StopIteration)) \
     real(ArrayBuffer,           InitViaClassSpec,       OCLASP(ArrayBuffer)) \
     real(Int8Array,             InitViaClassSpec,       TYPED_ARRAY_CLASP(Int8)) \
     real(Uint8Array,            InitViaClassSpec,       TYPED_ARRAY_CLASP(Uint8)) \
     real(Int16Array,            InitViaClassSpec,       TYPED_ARRAY_CLASP(Int16)) \
     real(Uint16Array,           InitViaClassSpec,       TYPED_ARRAY_CLASP(Uint16)) \
     real(Int32Array,            InitViaClassSpec,       TYPED_ARRAY_CLASP(Int32)) \
     real(Uint32Array,           InitViaClassSpec,       TYPED_ARRAY_CLASP(Uint32)) \
     real(Float32Array,          InitViaClassSpec,       TYPED_ARRAY_CLASP(Float32)) \
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -32,17 +32,16 @@
 #include "builtin/WeakMapObject.h"
 #include "builtin/WeakSetObject.h"
 #include "vm/Debugger.h"
 #include "vm/EnvironmentObject.h"
 #include "vm/HelperThreads.h"
 #include "vm/PIC.h"
 #include "vm/RegExpStatics.h"
 #include "vm/RegExpStaticsObject.h"
-#include "vm/StopIterationObject.h"
 #include "wasm/WasmJS.h"
 
 #include "jscompartmentinlines.h"
 #include "jsobjinlines.h"
 #include "jsscriptinlines.h"
 
 #include "vm/NativeObject-inl.h"
 
deleted file mode 100644
--- a/js/src/vm/StopIterationObject.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sts=4 et sw=4 tw=99:
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef vm_StopIterationObject_h
-#define vm_StopIterationObject_h
-
-#include "jsobj.h"
-
-namespace js {
-
-class StopIterationObject : public JSObject
-{
-  public:
-    static const Class class_;
-};
-
-} // namespace js
-
-#endif /* vm_StopIterationObject_h */
--- a/toolkit/components/promiseworker/PromiseWorker.jsm
+++ b/toolkit/components/promiseworker/PromiseWorker.jsm
@@ -83,19 +83,16 @@ const EXCEPTION_CONSTRUCTORS = {
     result.stack = error.stack;
     return result;
   },
   URIError(error) {
     let result = new URIError(error.message, error.fileName, error.lineNumber);
     result.stack = error.stack;
     return result;
   },
-  StopIteration() {
-    return StopIteration;
-  }
 };
 
 /**
  * An object responsible for dispatching messages to a chrome worker
  * and routing the responses.
  *
  * Instances of this constructor who need logging may provide a method
  * `log: function(...args) { ... }` in charge of printing out (or
@@ -119,17 +116,17 @@ this.BasePromiseWorker = function(url) {
    * A set of methods, with the following
    *
    * ConstructorName: function({message, fileName, lineNumber}) {
    *   // Construct a new instance of ConstructorName based on
    *   // `message`, `fileName`, `lineNumber`
    * }
    *
    * By default, this covers EvalError, InternalError, RangeError,
-   * ReferenceError, SyntaxError, TypeError, URIError, StopIteration.
+   * ReferenceError, SyntaxError, TypeError, URIError.
    */
   this.ExceptionHandlers = Object.create(EXCEPTION_CONSTRUCTORS);
 
   /**
    * The queue of deferred, waiting for the completion of their
    * respective job by the worker.
    *
    * Each item in the list may contain an additional field |closure|,
--- a/toolkit/components/promiseworker/worker/PromiseWorker.js
+++ b/toolkit/components/promiseworker/worker/PromiseWorker.js
@@ -164,24 +164,16 @@ AbstractWorker.prototype = {
       let error = {
         exn: exn.constructor.name,
         message: exn.message,
         fileName: exn.moduleName || exn.fileName,
         lineNumber: exn.lineNumber,
         stack: exn.moduleStack
       };
       this.postMessage({fail: error, id, durationMs});
-    } else if (exn == StopIteration) {
-      // StopIteration is a well-known singleton, and requires a
-      // slightly different treatment.
-      this.log("Sending back StopIteration, id is", id);
-      let error = {
-        exn: "StopIteration"
-      };
-      this.postMessage({fail: error, id, durationMs});
     } else if ("toMsg" in exn) {
       // Extension mechanism for exception [de]serialization. We
       // assume that any exception with a method `toMsg()` knows how
       // to serialize itself. The other side is expected to have
       // registered a deserializer using the `ExceptionHandlers`
       // object.
       this.log("Sending back an error that knows how to serialize itself", exn, "id is", id);
       let msg = exn.toMsg();