Merge mozilla-central to autoland
authorDorel Luca <dluca@mozilla.com>
Mon, 03 Sep 2018 00:34:09 +0300
changeset 489568 ce85e9d3f366766c061cf893fda5c9689bf05b0c
parent 489555 24d55d7791012c595503c2da02365a511c9cdb9b (current diff)
parent 489567 634b562ae2c3af1c07e12cca895796cc501f343d (diff)
child 489569 5b5d256c99f92667ebf91a02dbde8e82d429d400
push id9738
push useraciure@mozilla.com
push dateMon, 03 Sep 2018 16:13:51 +0000
treeherdermozilla-beta@f5841408a66c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone63.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
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