Merge mozilla-central to autoland
authorDorel Luca <dluca@mozilla.com>
Mon, 03 Sep 2018 00:34:09 +0300
changeset 482762 ce85e9d3f366766c061cf893fda5c9689bf05b0c
parent 482761 24d55d7791012c595503c2da02365a511c9cdb9b (current diff)
parent 482752 634b562ae2c3af1c07e12cca895796cc501f343d (diff)
child 482763 5b5d256c99f92667ebf91a02dbde8e82d429d400
push id232
push userfmarier@mozilla.com
push dateWed, 05 Sep 2018 20:45:54 +0000
milestone63.0a1
Merge mozilla-central to autoland
--- a/dom/media/CubebUtils.cpp
+++ b/dom/media/CubebUtils.cpp
@@ -416,16 +416,20 @@ cubeb* GetCubebContextUnlocked()
 {
   sMutex.AssertCurrentThreadOwns();
   if (sCubebForceNullContext) {
     // Pref set such that we should return a null context
     MOZ_LOG(gCubebLog, LogLevel::Debug,
             ("%s: returning null context due to %s!", __func__, PREF_CUBEB_FORCE_NULL_CONTEXT));
     return nullptr;
   }
+  if (recordreplay::IsRecordingOrReplaying()) {
+    // Media is not supported when recording or replaying. See bug 1304146.
+    return nullptr;
+  }
   if (sCubebState != CubebState::Uninitialized) {
     // If we have already passed the initialization point (below), just return
     // the current context, which may be null (e.g., after error or shutdown.)
     return sCubebContext;
   }
 
   if (!sBrandName && NS_IsMainThread()) {
     InitBrandName();
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -337,17 +337,18 @@ CallOnSuccess(MediaManager::GetUserMedia
  * clears this on XPCOM_WILL_SHUTDOWN, before MediaManager enters shutdown.
  */
 class SourceListener : public SupportsWeakPtr<SourceListener> {
 public:
   typedef MozPromise<bool /* aIgnored */, Maybe<nsString>, true> ApplyConstraintsPromise;
   typedef MozPromise<bool /* aIgnored */, RefPtr<MediaMgrError>, true> InitPromise;
 
   MOZ_DECLARE_WEAKREFERENCE_TYPENAME(SourceListener)
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(SourceListener)
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION_AND_RECORDING(SourceListener,
+                                                                                   recordreplay::Behavior::Preserve)
 
   SourceListener();
 
   /**
    * Registers this source listener as belonging to the given window listener.
    */
   void Register(GetUserMediaWindowListener* aListener);
 
--- a/extensions/spellcheck/src/mozEnglishWordUtils.cpp
+++ b/extensions/spellcheck/src/mozEnglishWordUtils.cpp
@@ -62,17 +62,17 @@ mozEnglishWordUtils::FindNextWord(const 
       }
 
     // we could be trying to break down a url, we don't want to break a url into parts,
     // instead we want to find out if it really is a url and if so, skip it, advancing startWord
     // to a point after the url.
 
     // before we spend more time looking to see if the word is a url, look for a url identifer
     // and make sure that identifer isn't the last character in the word fragment.
-    if ( (*p == ':' || *p == '@' || *p == '.') &&  p < endbuf - 1) {
+    if ((p < endbuf - 1) && (*p == ':' || *p == '@' || *p == '.')) {
 
         // ok, we have a possible url...do more research to find out if we really have one
         // and determine the length of the url so we can skip over it.
 
         if (mURLDetector)
         {
           int32_t startPos = -1;
           int32_t endPos = -1;
--- a/gfx/layers/ipc/ThreadSafeRefcountingWithMainThreadDestruction.h
+++ b/gfx/layers/ipc/ThreadSafeRefcountingWithMainThreadDestruction.h
@@ -54,17 +54,17 @@ struct DeleteOnMainThreadTask : public R
     mToDelete->DeleteToBeCalledOnMainThread();
     return NS_OK;
   }
 };
 
 } // namespace layers
 } // namespace mozilla
 
-#define NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(_class) \
+#define NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION_AND_RECORDING(_class, _recording) \
 public:                                                                       \
   NS_METHOD_(MozExternalRefCountType) AddRef(void) {                          \
     MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class)                                \
     MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt");                      \
     nsrefcnt count = ++mRefCnt;                                               \
     NS_LOG_ADDREF(this, count, #_class, sizeof(*this));                       \
     return (nsrefcnt) count;                                                  \
   }                                                                           \
@@ -84,14 +84,18 @@ public:                                 
           new mozilla::layers::DeleteOnMainThreadTask<_class>(this));         \
       }                                                                       \
     } else {                                                                  \
       NS_LOG_RELEASE(this, count, #_class);                                   \
     }                                                                         \
     return count;                                                             \
   }                                                                           \
 protected:                                                                    \
-  ::mozilla::ThreadSafeAutoRefCnt mRefCnt;                                    \
+  ::mozilla::ThreadSafeAutoRefCntWithRecording<_recording> mRefCnt;           \
 private:                                                                      \
   ::mozilla::layers::HelperForMainThreadDestruction mHelperForMainThreadDestruction; \
 public:
 
+#define NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(_class) \
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION_AND_RECORDING \
+    (_class, recordreplay::Behavior::DontPreserve)
+
 #endif
--- a/ipc/glue/MessageChannel.cpp
+++ b/ipc/glue/MessageChannel.cpp
@@ -2096,16 +2096,25 @@ MessageChannel::MessageTask::Clear()
     mChannel->AssertWorkerThread();
 
     mChannel = nullptr;
 }
 
 NS_IMETHODIMP
 MessageChannel::MessageTask::GetPriority(uint32_t* aPriority)
 {
+  if (recordreplay::IsRecordingOrReplaying()) {
+    // Ignore message priorities in recording/replaying processes. Incoming
+    // messages were sorted in the middleman process according to their
+    // priority before being forwarded here, and reordering them again in this
+    // process can cause problems such as dispatching messages for an actor
+    // before the constructor for that actor.
+    *aPriority = PRIORITY_NORMAL;
+    return NS_OK;
+  }
   switch (mMessage.priority()) {
   case Message::NORMAL_PRIORITY:
     *aPriority = PRIORITY_NORMAL;
     break;
   case Message::INPUT_PRIORITY:
     *aPriority = PRIORITY_INPUT;
     break;
   case Message::HIGH_PRIORITY:
--- a/js/src/vm/HelperThreads.cpp
+++ b/js/src/vm/HelperThreads.cpp
@@ -2418,38 +2418,42 @@ HelperThread::threadLoop()
             oomUnsafe.crash("HelperThread cx.init()");
     }
     cx.setHelperThread(this);
     JS_SetNativeStackQuota(&cx, HELPER_STACK_QUOTA);
 
     while (!terminate) {
         MOZ_ASSERT(idle());
 
+        if (mozilla::recordreplay::IsRecordingOrReplaying()) {
+            // Unlock the helper thread state lock before potentially
+            // blocking while the main thread waits for all threads to
+            // become idle. Otherwise we would need to see if we need to
+            // block at every point where a helper thread acquires the
+            // helper thread state lock.
+            {
+                AutoUnlockHelperThreadState unlock(lock);
+                mozilla::recordreplay::MaybeWaitForCheckpointSave();
+            }
+            // Now that we are holding the helper thread state lock again,
+            // notify the record/replay system that we might block soon.
+            // The helper thread state lock may not be released until the
+            // block occurs.
+            mozilla::recordreplay::NotifyUnrecordedWait(WakeupAll);
+        }
+
         // The selectors may depend on the HelperThreadState not changing
         // between task selection and task execution, in particular, on new
         // tasks not being added (because of the lifo structure of the work
         // lists). Unlocking the HelperThreadState between task selection and
         // execution is not well-defined.
 
         const TaskSpec* task = findHighestPriorityTask(lock);
         if (!task) {
             AUTO_PROFILER_LABEL("HelperThread::threadLoop::wait", IDLE);
-            if (mozilla::recordreplay::IsRecordingOrReplaying()) {
-                // Unlock the helper thread state lock before potentially
-                // blocking while the main thread waits for all threads to
-                // become idle. Otherwise we would need to see if we need to
-                // block at every point where a helper thread acquires the
-                // helper thread state lock.
-                {
-                    AutoUnlockHelperThreadState unlock(lock);
-                    mozilla::recordreplay::MaybeWaitForCheckpointSave();
-                }
-                mozilla::recordreplay::NotifyUnrecordedWait(WakeupAll);
-            }
-
             HelperThreadState().wait(lock, GlobalHelperThreadState::PRODUCER);
             continue;
         }
 
         js::oom::SetThreadType(task->type);
         (this->*(task->handleWorkload))(lock);
         js::oom::SetThreadType(js::THREAD_TYPE_NONE);
     }
--- a/testing/mozharness/mozharness/base/python.py
+++ b/testing/mozharness/mozharness/base/python.py
@@ -344,19 +344,27 @@ class VirtualenvMixin(object):
         # Always use the virtualenv that is vendored since that is deterministic.
         # TODO Bug 1408051 - Use the copy of virtualenv under
         # third_party/python/virtualenv once everything is off buildbot
         virtualenv = [
             sys.executable,
             os.path.join(external_tools_path, 'virtualenv', 'virtualenv.py'),
         ]
         virtualenv_options = c.get('virtualenv_options', [])
-        # Don't create symlinks. If we don't do this, permissions issues may
-        # hinder virtualenv creation or operation.
-        virtualenv_options.append('--always-copy')
+        # Creating symlinks in the virtualenv may cause issues during
+        # virtualenv creation or operation on non-Redhat derived
+        # distros. On Redhat derived distros --always-copy causes
+        # imports to fail. See
+        # https://github.com/pypa/virtualenv/issues/565. Therefore
+        # only use --alway-copy when not using Redhat.
+        if self._is_redhat():
+            self.warning("creating virtualenv without --always-copy "
+                         "due to issues on Redhat derived distros")
+        else:
+            virtualenv_options.append('--always-copy')
 
         if os.path.exists(self.query_python_path()):
             self.info("Virtualenv %s appears to already exist; skipping virtualenv creation." % self.query_python_path())
         else:
             self.mkdir_p(dirs['abs_work_dir'])
             self.run_command(virtualenv + virtualenv_options + [venv_path],
                              cwd=dirs['abs_work_dir'],
                              error_list=VirtualenvErrorList,
--- a/testing/mozharness/mozharness/base/script.py
+++ b/testing/mozharness/mozharness/base/script.py
@@ -49,16 +49,17 @@ if os.name == 'nt':
 try:
     import simplejson as json
     assert json
 except ImportError:
     import json
 
 from io import BytesIO
 
+import mozinfo
 from mozprocess import ProcessHandler
 from mozharness.base.config import BaseConfig
 from mozharness.base.log import SimpleFileLogger, MultiFileLogger, \
     LogMixin, OutputParser, DEBUG, INFO, ERROR, FATAL
 
 
 class ContentLengthMismatch(Exception):
     pass
@@ -113,16 +114,27 @@ class PlatformMixin(object):
         Returns:
             bool: True if the current platform is a Linux distro, False otherwise
         """
         if platform.system() in ("Linux"):
             return True
         if sys.platform.startswith("linux"):
             return True
 
+    def _is_redhat(self):
+        """ check if the current operating system is a Redhat derived Linux distribution.
+
+        Returns:
+            bool: True if the current platform is a Redhat Linux distro, False otherwise
+        """
+        if not self._is_linux():
+            return False
+        re_redhat_distro = re.compile('Redhat|Fedora|CentOS|Oracle')
+        return re_redhat_distro.match(mozinfo.linux_distro) is not None
+
     def _is_64_bit(self):
         if self._is_darwin():
             # osx is a special snowflake and to ensure the arch, it is better to use the following
             return sys.maxsize > 2**32  # context: https://docs.python.org/2/library/platform.html
         else:
             # Using machine() gives you the architecture of the host rather
             # than the build type of the Python binary
             return '64' in platform.machine()
--- a/toolkit/components/finalizationwitness/FinalizationWitnessService.cpp
+++ b/toolkit/components/finalizationwitness/FinalizationWitnessService.cpp
@@ -97,20 +97,17 @@ ExtractFinalizationEvent(JSObject *objSe
  * Finalizer for instances of FinalizationWitness.
  *
  * Unless method Forget() has been called, the finalizer displays an error
  * message.
  */
 void Finalize(JSFreeOp *fop, JSObject *objSelf)
 {
   RefPtr<FinalizationEvent> event = ExtractFinalizationEvent(objSelf);
-
-  // Finalize witnesses are not notified when recording or replaying, as
-  // finalizations occur non-deterministically in the recording.
-  if (event == nullptr || gShuttingDown || recordreplay::IsRecordingOrReplaying()) {
+  if (event == nullptr || gShuttingDown) {
     // NB: event will be null if Forget() has been called
     return;
   }
 
   // Notify observers. Since we are executed during garbage-collection,
   // we need to dispatch the notification to the main thread.
   nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
   if (mainThread) {
@@ -198,16 +195,22 @@ NS_IMPL_ISUPPORTS(FinalizationWitnessSer
  * @constructor
  */
 NS_IMETHODIMP
 FinalizationWitnessService::Make(const char* aTopic,
                                  const char16_t* aValue,
                                  JSContext* aCx,
                                  JS::MutableHandle<JS::Value> aRetval)
 {
+  // Finalize witnesses are not created when recording or replaying, as
+  // finalizations occur non-deterministically in the recording.
+  if (recordreplay::IsRecordingOrReplaying()) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
   JS::Rooted<JSObject*> objResult(aCx, JS_NewObject(aCx, &sWitnessClass));
   if (!objResult) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
   if (!JS_DefineFunctions(aCx, objResult, sWitnessClassFunctions)) {
     return NS_ERROR_FAILURE;
   }
 
--- a/toolkit/recordreplay/ipc/ChildIPC.cpp
+++ b/toolkit/recordreplay/ipc/ChildIPC.cpp
@@ -404,16 +404,20 @@ static bool gPendingPaint;
 static void* gDrawTargetBuffer;
 static size_t gDrawTargetBufferSize;
 
 already_AddRefed<gfx::DrawTarget>
 DrawTargetForRemoteDrawing(LayoutDeviceIntSize aSize)
 {
   MOZ_RELEASE_ASSERT(!NS_IsMainThread());
 
+  if (aSize.IsEmpty()) {
+    return nullptr;
+  }
+
   gPaintMessage = Some(PaintMessage(aSize.width, aSize.height));
 
   gfx::IntSize size(aSize.width, aSize.height);
   size_t bufferSize = layers::ImageDataSerializer::ComputeRGBBufferSize(size, gSurfaceFormat);
   MOZ_RELEASE_ASSERT(bufferSize <= parent::GraphicsMemorySize);
 
   if (bufferSize != gDrawTargetBufferSize) {
     free(gDrawTargetBuffer);
--- a/xpcom/base/CycleCollectedJSRuntime.cpp
+++ b/xpcom/base/CycleCollectedJSRuntime.cpp
@@ -1450,16 +1450,23 @@ CycleCollectedJSRuntime::FinalizeDeferre
     mFinalizeRunnable->ReleaseNow(false);
     if (mFinalizeRunnable) {
       // If we re-entered ReleaseNow, we couldn't delete mFinalizeRunnable and
       // we need to just continue processing it.
       return;
     }
   }
 
+  // When recording or replaying, execute triggers that were activated recently
+  // by mozilla::DeferredFinalize. This will populate the deferred finalizer
+  // table with a consistent set of entries between the recording and replay.
+  if (recordreplay::IsRecordingOrReplaying()) {
+    recordreplay::ExecuteTriggers();
+  }
+
   if (mDeferredFinalizerTable.Count() == 0) {
     return;
   }
 
   mFinalizeRunnable = new IncrementalFinalizeRunnable(this,
                                                       mDeferredFinalizerTable);
 
   // Everything should be gone now.
--- a/xpcom/base/nsCycleCollector.cpp
+++ b/xpcom/base/nsCycleCollector.cpp
@@ -3958,22 +3958,16 @@ nsCycleCollector::BeginCollection(ccType
   FinishAnyIncrementalGCInProgress();
   timeLog.Checkpoint("Pre-FixGrayBits finish IGC");
 
   FixGrayBits(forceGC, timeLog);
   if (mCCJSRuntime) {
     mCCJSRuntime->CheckGrayBits();
   }
 
-  // If we are recording or replaying, force the release of any references
-  // from objects that have recently been finalized.
-  if (recordreplay::IsRecordingOrReplaying()) {
-    recordreplay::ExecuteTriggers();
-  }
-
   FreeSnowWhite(true);
   timeLog.Checkpoint("BeginCollection FreeSnowWhite");
 
   if (mLogger && NS_FAILED(mLogger->Begin())) {
     mLogger = nullptr;
   }
 
   // FreeSnowWhite could potentially have started an IGC, which we need
--- a/xpcom/io/nsPipe3.cpp
+++ b/xpcom/io/nsPipe3.cpp
@@ -278,17 +278,17 @@ public:
 
   MonitorAction OnOutputWritable(nsPipeEvents&);
   MonitorAction OnOutputException(nsresult, nsPipeEvents&);
 
 private:
   nsPipe*                         mPipe;
 
   // separate refcnt so that we know when to close the producer
-  mozilla::ThreadSafeAutoRefCnt   mWriterRefCnt;
+  ThreadSafeAutoRefCntWithRecording<recordreplay::Behavior::Preserve> mWriterRefCnt;
   int64_t                         mLogicalOffset;
   bool                            mBlocking;
 
   // these variables can only be accessed while inside the pipe's monitor
   bool                            mBlocked;
   bool                            mWritable;
   nsCOMPtr<nsIOutputStreamCallback> mCallback;
   uint32_t                        mCallbackFlags;
--- a/xpcom/threads/nsThread.cpp
+++ b/xpcom/threads/nsThread.cpp
@@ -1033,27 +1033,21 @@ nsThread::ProcessNextEvent(bool aMayWait
 {
   LOG(("THRD(%p) ProcessNextEvent [%u %u]\n", this, aMayWait,
        mNestedEventLoopDepth));
 
   if (NS_WARN_IF(PR_GetCurrentThread() != mThread)) {
     return NS_ERROR_NOT_SAME_THREAD;
   }
 
-  // When recording or replaying, execute triggers that were activated
-  // non-deterministically at some point since the last turn of the event loop.
-  if (recordreplay::IsRecordingOrReplaying()) {
-    recordreplay::ExecuteTriggers();
-
-    // Vsync observers are notified whenever processing events on the main
-    // thread. Waiting for explicit vsync messages from the UI process can
-    // result in paints happening at unexpected times when replaying/rewinding.
-    if (mIsMainThread == MAIN_THREAD) {
-      recordreplay::child::NotifyVsyncObserver();
-    }
+  // When recording or replaying, vsync observers are notified whenever
+  // processing events on the main thread. Waiting for explicit vsync messages
+  // from the UI process can result in paints happening at unexpected times.
+  if (recordreplay::IsRecordingOrReplaying() && mIsMainThread == MAIN_THREAD) {
+    recordreplay::child::NotifyVsyncObserver();
   }
 
   // The toplevel event loop normally blocks waiting for the next event, but
   // if we're trying to shut this thread down, we must exit the event loop when
   // the event queue is empty.
   // This only applys to the toplevel event loop! Nested event loops (e.g.
   // during sync dispatch) are waiting for some state change and must be able
   // to block even if something has requested shutdown of the thread. Otherwise