Merge mozilla-central to autoland. a=merge on a CLOSED TREE
authorRazvan Maries <rmaries@mozilla.com>
Wed, 20 Mar 2019 00:07:50 +0200
changeset 465118 26fafa29a3eb557f9e41ecd9e6821052475055ce
parent 465117 91403c24fee3d5df8fa978710785807b409d7af8 (current diff)
parent 465070 d15d511d7fed036d69d37cecbacdea779a983a34 (diff)
child 465119 b29882123ec6753ce6292d1affec84669711d3bf
push id35732
push useropoprus@mozilla.com
push dateWed, 20 Mar 2019 10:52:37 +0000
treeherdermozilla-central@708979f9c3f3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone68.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=merge on a CLOSED TREE
--- a/dom/localstorage/ActorsParent.cpp
+++ b/dom/localstorage/ActorsParent.cpp
@@ -31,16 +31,17 @@
 #include "mozilla/dom/quota/QuotaManager.h"
 #include "mozilla/dom/quota/QuotaObject.h"
 #include "mozilla/dom/quota/UsageInfo.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/ipc/BackgroundParent.h"
 #include "mozilla/ipc/PBackgroundChild.h"
 #include "mozilla/ipc/PBackgroundParent.h"
 #include "mozilla/ipc/PBackgroundSharedTypes.h"
+#include "mozilla/Logging.h"
 #include "nsClassHashtable.h"
 #include "nsDataHashtable.h"
 #include "nsInterfaceHashtable.h"
 #include "nsIObjectInputStream.h"
 #include "nsIObjectOutputStream.h"
 #include "nsISimpleEnumerator.h"
 #include "nsNetUtil.h"
 #include "nsRefPtrHashtable.h"
@@ -2166,19 +2167,19 @@ class LSRequestBase : public DatastoreOp
  protected:
   // Common nsIRunnable implementation that subclasses may not override.
   NS_IMETHOD
   Run() final;
 
   // IPDL methods.
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
+  mozilla::ipc::IPCResult RecvCancel() override;
+
  private:
-  mozilla::ipc::IPCResult RecvCancel() final;
-
   mozilla::ipc::IPCResult RecvFinish() final;
 };
 
 class PrepareDatastoreOp : public LSRequestBase, public OpenDirectoryListener {
   class LoadDataOp;
 
   enum class NestedState {
     // The nesting has not yet taken place. Next step is
@@ -2338,16 +2339,18 @@ class PrepareDatastoreOp : public LSRequ
 
   void CleanupMetadata();
 
   NS_DECL_ISUPPORTS_INHERITED
 
   // IPDL overrides.
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
+  mozilla::ipc::IPCResult RecvCancel() final;
+
   // OpenDirectoryListener overrides.
   void DirectoryLockAcquired(DirectoryLock* aLock) override;
 
   void DirectoryLockFailed() override;
 };
 
 class PrepareDatastoreOp::LoadDataOp final
     : public ConnectionDatastoreOperationBase {
@@ -2734,16 +2737,18 @@ typedef nsDataHashtable<nsCStringHashKey
 // Can only be touched on the Quota Manager I/O thread.
 StaticAutoPtr<UsageHashtable> gUsages;
 
 StaticAutoPtr<ArchivedOriginHashtable> gArchivedOrigins;
 
 // Can only be touched on the Quota Manager I/O thread.
 bool gInitializedShadowStorage = false;
 
+LazyLogModule gLogger("LocalStorage");
+
 bool IsOnConnectionThread() {
   MOZ_ASSERT(gConnectionThread);
   return gConnectionThread->IsOnConnectionThread();
 }
 
 void AssertIsOnConnectionThread() {
   MOZ_ASSERT(gConnectionThread);
   gConnectionThread->AssertIsOnConnectionThread();
@@ -5716,16 +5721,62 @@ void LSRequestBase::ActorDestroy(ActorDe
   AssertIsOnOwningThread();
 
   NoteComplete();
 }
 
 mozilla::ipc::IPCResult LSRequestBase::RecvCancel() {
   AssertIsOnOwningThread();
 
+  if (MOZ_LOG_TEST(gLogger, LogLevel::Info)) {
+    MOZ_LOG(gLogger, LogLevel::Info, ("LSRequestBase::RecvCancel"));
+
+    nsCString state;
+
+    switch (mState) {
+      case State::Initial:
+        state.AssignLiteral("Initial");
+        break;
+
+      case State::Opening:
+        state.AssignLiteral("Opening");
+        break;
+
+      case State::Nesting:
+        state.AssignLiteral("Nesting");
+        break;
+
+      case State::SendingReadyMessage:
+        state.AssignLiteral("SendingReadyMessage");
+        break;
+
+      case State::WaitingForFinish:
+        state.AssignLiteral("WaitingForFinish");
+        break;
+
+      case State::SendingResults:
+        state.AssignLiteral("SendingResults");
+        break;
+
+      case State::Completed:
+        state.AssignLiteral("Completed");
+        break;
+
+      default:
+        MOZ_CRASH("Bad state!");
+    }
+
+    MOZ_LOG(gLogger, LogLevel::Info, ("  mState: %s", state.get()));
+  }
+
+  const char* crashOnCancel = PR_GetEnv("LSNG_CRASH_ON_CANCEL");
+  if (crashOnCancel) {
+    MOZ_CRASH("LSNG: Crash on cancel.");
+  }
+
   IProtocol* mgr = Manager();
   if (!PBackgroundLSRequestParent::Send__delete__(this, NS_ERROR_FAILURE)) {
     return IPC_FAIL_NO_REASON(mgr);
   }
 
   return IPC_OK();
 }
 
@@ -6675,16 +6726,75 @@ void PrepareDatastoreOp::ActorDestroy(Ac
 
   LSRequestBase::ActorDestroy(aWhy);
 
   if (mLoadDataOp) {
     mLoadDataOp->NoteComplete();
   }
 }
 
+mozilla::ipc::IPCResult PrepareDatastoreOp::RecvCancel() {
+  AssertIsOnOwningThread();
+
+  if (MOZ_LOG_TEST(gLogger, LogLevel::Info)) {
+    MOZ_LOG(gLogger, LogLevel::Info, ("PrepareDatastoreOp::RecvCancel"));
+
+    nsCString nestedState;
+
+    switch (mNestedState) {
+      case NestedState::BeforeNesting:
+        nestedState.AssignLiteral("BeforeNesting");
+        break;
+
+      case NestedState::CheckExistingOperations:
+        nestedState.AssignLiteral("CheckExistingOperations");
+        break;
+
+      case NestedState::CheckClosingDatastore:
+        nestedState.AssignLiteral("CheckClosingDatastore");
+        break;
+
+      case NestedState::PreparationPending:
+        nestedState.AssignLiteral("PreparationPending");
+        break;
+
+      case NestedState::QuotaManagerPending:
+        nestedState.AssignLiteral("QuotaManagerPending");
+        break;
+
+      case NestedState::DirectoryOpenPending:
+        nestedState.AssignLiteral("DirectoryOpenPending");
+        break;
+
+      case NestedState::DatabaseWorkOpen:
+        nestedState.AssignLiteral("DatabaseWorkOpen");
+        break;
+
+      case NestedState::BeginLoadData:
+        nestedState.AssignLiteral("BeginLoadData");
+        break;
+
+      case NestedState::DatabaseWorkLoadData:
+        nestedState.AssignLiteral("DatabaseWorkLoadData");
+        break;
+
+      case NestedState::AfterNesting:
+        nestedState.AssignLiteral("AfterNesting");
+        break;
+
+      default:
+        MOZ_CRASH("Bad state!");
+    }
+
+    MOZ_LOG(gLogger, LogLevel::Info, ("  mNestedState: %s", nestedState.get()));
+  }
+
+  return LSRequestBase::RecvCancel();
+}
+
 void PrepareDatastoreOp::DirectoryLockAcquired(DirectoryLock* aLock) {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mState == State::Nesting);
   MOZ_ASSERT(mNestedState == NestedState::DirectoryOpenPending);
   MOZ_ASSERT(!mDirectoryLock);
 
   if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread()) ||
       !MayProceed()) {
--- a/dom/localstorage/LSObject.cpp
+++ b/dom/localstorage/LSObject.cpp
@@ -13,16 +13,28 @@
 #include "mozilla/dom/quota/QuotaManager.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/ipc/BackgroundUtils.h"
 #include "mozilla/ipc/PBackgroundChild.h"
 #include "nsContentUtils.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsThread.h"
 
+/**
+ * Automatically cancel and abort synchronous LocalStorage requests (for example
+ * datastore preparation) if they take this long.  We've chosen a value that is
+ * long enough that it is unlikely for the problem to be falsely triggered by
+ * slow system I/O.  We've also chosen a value long enough so that automated
+ * tests should time out and fail if LocalStorage hangs.  Also, this value is
+ * long enough so that testers can notice the (content process) hang; we want to
+ * know about the hangs, not hide them.  On the other hand this value is less
+ * than 60 seconds which is used by nsTerminator to crash a hung main process.
+ */
+#define FAILSAFE_CANCEL_SYNC_OP_MS 50000
+
 namespace mozilla {
 namespace dom {
 
 namespace {
 
 class RequestHelper;
 
 StaticMutex gRequestHelperMutex;
@@ -132,27 +144,29 @@ class RequestHelper final : public Runna
   // __destroy__ method.
   LSRequestChild* mActor;
   const LSRequestParams mParams;
   LSRequestResponse mResponse;
   nsresult mResultCode;
   State mState;
   // Control flag for the nested event loop; once set to false, the loop ends.
   bool mWaiting;
+  bool mCancelled;
 
  public:
   RequestHelper(LSObject* aObject, const LSRequestParams& aParams)
       : Runnable("dom::RequestHelper"),
         mObject(aObject),
         mOwningEventTarget(GetCurrentThreadEventTarget()),
         mActor(nullptr),
         mParams(aParams),
         mResultCode(NS_OK),
         mState(State::Initial),
-        mWaiting(true) {}
+        mWaiting(true),
+        mCancelled(false) {}
 
   bool IsOnOwningThread() const {
     MOZ_ASSERT(mOwningEventTarget);
 
     bool current;
     return NS_SUCCEEDED(mOwningEventTarget->IsOnCurrentThread(&current)) &&
            current;
   }
@@ -1073,32 +1087,51 @@ nsresult RequestHelper::StartAndReturnRe
         gSyncLoopEventTarget = nullptr;
       });
 
       rv = domFileThread->Dispatch(this, NS_DISPATCH_NORMAL);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
 
+      nsCOMPtr<nsITimer> timer = NS_NewTimer();
+
+      MOZ_ALWAYS_SUCCEEDS(timer->SetTarget(mNestedEventTarget));
+
+      MOZ_ALWAYS_SUCCEEDS(timer->InitWithNamedFuncCallback(
+          [](nsITimer* aTimer, void* aClosure) {
+            auto helper = static_cast<RequestHelper*>(aClosure);
+
+            helper->mCancelled = true;
+          },
+          this, FAILSAFE_CANCEL_SYNC_OP_MS, nsITimer::TYPE_ONE_SHOT,
+          "RequestHelper::StartAndReturnResponse::SpinEventLoopTimer"));
+
       MOZ_ALWAYS_TRUE(SpinEventLoopUntil(
           [&]() {
+            if (mCancelled) {
+              return true;
+            }
+
             if (!mWaiting) {
               return true;
             }
 
             {
               StaticMutexAutoLock lock(gRequestHelperMutex);
               if (NS_WARN_IF(gPendingSyncMessage)) {
                 return true;
               }
             }
 
             return false;
           },
           thread));
+
+      MOZ_ALWAYS_SUCCEEDS(timer->Cancel());
     }
 
     // If mWaiting is still set to true, it means that the event loop spinning
     // was aborted and we need to cancel the request in the parent since we
     // don't care about the result anymore.
     // We can check mWaiting here because it's only ever touched on the main
     // thread.
     if (NS_WARN_IF(mWaiting)) {
--- a/js/src/gc/Policy.h
+++ b/js/src/gc/Policy.h
@@ -59,17 +59,17 @@ namespace JS {
 template <typename T>
 struct GCPolicy<T*> : public js::InternalGCPointerPolicy<T*> {};
 template <typename T>
 struct GCPolicy<T* const> : public js::InternalGCPointerPolicy<T* const> {};
 
 template <typename T>
 struct GCPolicy<js::HeapPtr<T>> {
   static void trace(JSTracer* trc, js::HeapPtr<T>* thingp, const char* name) {
-    js::TraceEdge(trc, thingp, name);
+    js::TraceNullableEdge(trc, thingp, name);
   }
   static bool needsSweep(js::HeapPtr<T>* thingp) {
     return js::gc::IsAboutToBeFinalized(thingp);
   }
 };
 
 template <typename T>
 struct GCPolicy<js::ReadBarriered<T>> {
--- a/js/src/jit/arm64/Architecture-arm64.h
+++ b/js/src/jit/arm64/Architecture-arm64.h
@@ -389,20 +389,22 @@ class FloatRegisters {
 // In bytes: slots needed for potential memory->memory move spills.
 //   +8 for cycles
 //   +8 for gpr spills
 //   +8 for double spills
 static const uint32_t ION_FRAME_SLACK_SIZE = 24;
 
 static const uint32_t ShadowStackSpace = 0;
 
-// TODO:
-// This constant needs to be updated to account for whatever near/far branching
-// strategy is used by ARM64.
-static const uint32_t JumpImmediateRange = UINT32_MAX;
+// When our only strategy for far jumps is to encode the offset directly, and
+// not insert any jump islands during assembly for even further jumps, then the
+// architecture restricts us to -2^27 .. 2^27-4, to fit into a signed 28-bit
+// value.  We further reduce this range to allow the far-jump inserting code to
+// have some breathing room.
+static const uint32_t JumpImmediateRange = ((1 << 27) - (20 * 1024 * 1024));
 
 static const uint32_t ABIStackAlignment = 16;
 static const uint32_t CodeAlignment = 16;
 static const bool StackKeptAligned = false;
 
 // Although sp is only usable if 16-byte alignment is kept,
 // the Pseudo-StackPointer enables use of 8-byte alignment.
 static const uint32_t StackAlignment = 8;