Backed out 2 changesets (bug 1377060) for build bustage a=backout
authorWes Kocher <wkocher@mozilla.com>
Mon, 03 Jul 2017 11:44:58 -0700
changeset 367190 368fe03dbe01fdd2470fa907ffe909b73fae1a4c
parent 367189 216b686cdbaa5cf9f0d355042d388c5a71a83b70
child 367191 47fc833e0893c5777641a72782ee05ac16a18031
push id32125
push usercbook@mozilla.com
push dateTue, 04 Jul 2017 08:48:50 +0000
treeherdermozilla-central@fef489e8c2a1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbackout
bugs1377060
milestone56.0a1
backs outc8f818803df73e9c13820c1c81ef0c5b6154f34b
bf11ec80b0fbacff87d0fe9f654edf66a003edfc
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
Backed out 2 changesets (bug 1377060) for build bustage a=backout Backed out changeset c8f818803df7 (bug 1377060) Backed out changeset bf11ec80b0fb (bug 1377060) MozReview-Commit-ID: Hp1PtpWYOWV
gfx/layers/PaintThread.cpp
gfx/layers/PaintThread.h
gfx/layers/client/ClientLayerManager.cpp
gfx/layers/ipc/CompositorBridgeChild.cpp
gfx/layers/ipc/CompositorBridgeChild.h
gfx/layers/ipc/ShadowLayers.cpp
gfx/thebes/gfxPrefs.h
xpcom/base/StaticPtr.h
--- a/gfx/layers/PaintThread.cpp
+++ b/gfx/layers/PaintThread.cpp
@@ -1,64 +1,58 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 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/. */
 
 #include "PaintThread.h"
 
-#include "base/task.h"
-#include "mozilla/layers/CompositorBridgeChild.h"
 #include "mozilla/gfx/2D.h"
-#include "mozilla/Preferences.h"
 #include "mozilla/SyncRunnable.h"
 
 namespace mozilla {
 namespace layers {
 
 using namespace gfx;
 
 StaticAutoPtr<PaintThread> PaintThread::sSingleton;
-StaticRefPtr<nsIThread> PaintThread::sThread;
-PlatformThreadId PaintThread::sThreadId;
 
 void
 PaintThread::Release()
 {
 }
 
 void
 PaintThread::AddRef()
 {
 }
 
 void
 PaintThread::InitOnPaintThread()
 {
   MOZ_ASSERT(!NS_IsMainThread());
-  sThreadId = PlatformThread::CurrentId();
+  mThreadId = PlatformThread::CurrentId();
 }
 
 bool
 PaintThread::Init()
 {
   MOZ_ASSERT(NS_IsMainThread());
+  nsresult rv = NS_NewNamedThread("PaintThread", getter_AddRefs(mThread));
 
-  RefPtr<nsIThread> thread;
-  nsresult rv = NS_NewNamedThread("PaintThread", getter_AddRefs(thread));
   if (NS_FAILED(rv)) {
     return false;
   }
-  sThread = thread;
 
   nsCOMPtr<nsIRunnable> paintInitTask =
     NewRunnableMethod("PaintThread::InitOnPaintThread",
                       this, &PaintThread::InitOnPaintThread);
-  SyncRunnable::DispatchToThread(sThread, paintInitTask);
+
+  SyncRunnable::DispatchToThread(PaintThread::sSingleton->mThread, paintInitTask);
   return true;
 }
 
 /* static */ void
 PaintThread::Start()
 {
   PaintThread::sSingleton = new PaintThread();
 
@@ -70,89 +64,55 @@ PaintThread::Start()
 
 /* static */ PaintThread*
 PaintThread::Get()
 {
   MOZ_ASSERT(NS_IsMainThread());
   return PaintThread::sSingleton.get();
 }
 
-void
-DestroyPaintThread(UniquePtr<PaintThread>&& pt)
-{
-  MOZ_ASSERT(PaintThread::IsOnPaintThread());
-  pt->ShutdownOnPaintThread();
-}
-
 /* static */ void
 PaintThread::Shutdown()
 {
-  MOZ_ASSERT(NS_IsMainThread());
-
-  UniquePtr<PaintThread> pt(sSingleton.forget());
-  if (!pt) {
+  if (!PaintThread::sSingleton) {
     return;
   }
 
-  sThread->Dispatch(NewRunnableFunction(DestroyPaintThread, Move(pt)));
-  sThread->Shutdown();
-  sThread = nullptr;
+  PaintThread::sSingleton->ShutdownImpl();
+  PaintThread::sSingleton = nullptr;
 }
 
 void
-PaintThread::ShutdownOnPaintThread()
+PaintThread::ShutdownImpl()
 {
-  MOZ_ASSERT(IsOnPaintThread());
-}
-
-/* static */ bool
-PaintThread::IsOnPaintThread()
-{
-  return sThreadId == PlatformThread::CurrentId();
+  MOZ_ASSERT(NS_IsMainThread());
+  PaintThread::sSingleton->mThread->AsyncShutdown();
 }
 
-void
-PaintThread::PaintContentsAsync(CompositorBridgeChild* aBridge,
-                                gfx::DrawTargetCapture* aCapture,
-                                gfx::DrawTarget* aTarget)
+bool
+PaintThread::IsOnPaintThread()
 {
-  MOZ_ASSERT(IsOnPaintThread());
-
-  // Draw all the things into the actual dest target.
-  aTarget->DrawCapturedDT(aCapture, Matrix());
-
-  if (aBridge) {
-    aBridge->NotifyFinishedAsyncPaint();
-  }
+  MOZ_ASSERT(mThread);
+  return PlatformThread::CurrentId() == mThreadId;
 }
 
 void
 PaintThread::PaintContents(DrawTargetCapture* aCapture,
                            DrawTarget* aTarget)
 {
-  MOZ_ASSERT(NS_IsMainThread());
+  if (!IsOnPaintThread()) {
+    MOZ_ASSERT(NS_IsMainThread());
+    nsCOMPtr<nsIRunnable> paintTask =
+      NewRunnableMethod<DrawTargetCapture*, DrawTarget*>("PaintThread::PaintContents",
+                                                         this,
+                                                         &PaintThread::PaintContents,
+                                                         aCapture, aTarget);
 
-  // If painting asynchronously, we need to acquire the compositor bridge which
-  // owns the underlying MessageChannel. Otherwise we leave it null and use
-  // synchronous dispatch.
-  RefPtr<CompositorBridgeChild> cbc;
-  if (!gfxPrefs::LayersOMTPForceSync()) {
-    cbc = CompositorBridgeChild::Get();
-    cbc->NotifyBeginAsyncPaint();
+    SyncRunnable::DispatchToThread(mThread, paintTask);
+    return;
   }
-  RefPtr<DrawTargetCapture> capture(aCapture);
-  RefPtr<DrawTarget> target(aTarget);
 
-  RefPtr<Runnable> task = NS_NewRunnableFunction("PaintThread::PaintContents",
-    [=, this]() -> void
-  {
-    PaintContentsAsync(cbc, capture, target);
-  });
-
-  if (cbc) {
-    sThread->Dispatch(task.forget());
-  } else {
-    SyncRunnable::DispatchToThread(sThread, task);
-  }
+  // Draw all the things into the actual dest target.
+  aTarget->DrawCapturedDT(aCapture, Matrix());
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/PaintThread.h
+++ b/gfx/layers/PaintThread.h
@@ -4,59 +4,48 @@
  * 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 MOZILLA_LAYERS_PAINTTHREAD_H
 #define MOZILLA_LAYERS_PAINTTHREAD_H
 
 #include "base/platform_thread.h"
 #include "mozilla/StaticPtr.h"
-#include "mozilla/UniquePtr.h"
 #include "nsThreadUtils.h"
 
 namespace mozilla {
 namespace gfx {
 class DrawTarget;
 class DrawTargetCapture;
 };
 
 namespace layers {
 
-class CompositorBridgeChild;
-
 class PaintThread final
 {
-  friend void DestroyPaintThread(UniquePtr<PaintThread>&& aPaintThread);
-
 public:
   static void Start();
   static void Shutdown();
   static PaintThread* Get();
   void PaintContents(gfx::DrawTargetCapture* aCapture,
                      gfx::DrawTarget* aTarget);
-
   // Sync Runnables need threads to be ref counted,
   // But this thread lives through the whole process.
   // We're only temporarily using sync runnables so
   // Override release/addref but don't do anything.
   void Release();
   void AddRef();
 
-  // Helper for asserts.
-  static bool IsOnPaintThread();
-
 private:
+  bool IsOnPaintThread();
   bool Init();
-  void ShutdownOnPaintThread();
+  void ShutdownImpl();
   void InitOnPaintThread();
-  void PaintContentsAsync(CompositorBridgeChild* aBridge,
-                          gfx::DrawTargetCapture* aCapture,
-                          gfx::DrawTarget* aTarget);
 
   static StaticAutoPtr<PaintThread> sSingleton;
-  static StaticRefPtr<nsIThread> sThread;
-  static PlatformThreadId sThreadId;
+  RefPtr<nsIThread> mThread;
+  PlatformThreadId mThreadId;
 };
 
 } // namespace layers
 } // namespace mozilla
 
-#endif
+#endif
\ No newline at end of file
--- a/gfx/layers/client/ClientLayerManager.cpp
+++ b/gfx/layers/client/ClientLayerManager.cpp
@@ -221,19 +221,16 @@ ClientLayerManager::CreateReadbackLayer(
 {
   RefPtr<ReadbackLayer> layer = new ClientReadbackLayer(this);
   return layer.forget();
 }
 
 bool
 ClientLayerManager::BeginTransactionWithTarget(gfxContext* aTarget)
 {
-  // Wait for any previous async paints to complete before starting to paint again.
-  GetCompositorBridgeChild()->FlushAsyncPaints();
-
   MOZ_ASSERT(mForwarder, "ClientLayerManager::BeginTransaction without forwarder");
   if (!mForwarder->IPCOpen()) {
     gfxCriticalNote << "ClientLayerManager::BeginTransaction with IPC channel down. GPU process may have died.";
     return false;
   }
 
   if (XRE_IsContentProcess() &&
       mForwarder->DeviceCanReset() &&
--- a/gfx/layers/ipc/CompositorBridgeChild.cpp
+++ b/gfx/layers/ipc/CompositorBridgeChild.cpp
@@ -14,17 +14,16 @@
 #include "gfxPrefs.h"
 #include "mozilla/dom/TabGroup.h"
 #include "mozilla/layers/CompositorManagerChild.h"
 #include "mozilla/layers/ImageBridgeChild.h"
 #include "mozilla/layers/APZChild.h"
 #include "mozilla/layers/IAPZCTreeManager.h"
 #include "mozilla/layers/APZCTreeManagerChild.h"
 #include "mozilla/layers/LayerTransactionChild.h"
-#include "mozilla/layers/PaintThread.h"
 #include "mozilla/layers/PLayerTransactionChild.h"
 #include "mozilla/layers/PTextureChild.h"
 #include "mozilla/layers/TextureClient.h"// for TextureClient
 #include "mozilla/layers/TextureClientPool.h"// for TextureClientPool
 #include "mozilla/layers/WebRenderBridgeChild.h"
 #include "mozilla/gfx/gfxVars.h"
 #include "mozilla/gfx/GPUProcessManager.h"
 #include "mozilla/gfx/Logging.h"
@@ -85,19 +84,16 @@ CompositorBridgeChild::CompositorBridgeC
   , mResourceId(0)
   , mCanSend(false)
   , mActorDestroyed(false)
   , mFwdTransactionId(0)
   , mDeviceResetSequenceNumber(0)
   , mMessageLoop(MessageLoop::current())
   , mProcessToken(0)
   , mSectionAllocator(nullptr)
-  , mPaintLock("CompositorBridgeChild.mPaintLock")
-  , mOutstandingAsyncPaints(0)
-  , mIsWaitingForPaint(false)
 {
   MOZ_ASSERT(NS_IsMainThread());
 }
 
 CompositorBridgeChild::~CompositorBridgeChild()
 {
   if (mCanSend) {
     gfxCriticalError() << "CompositorBridgeChild was not deinitialized";
@@ -541,30 +537,18 @@ void
 CompositorBridgeChild::ActorDestroy(ActorDestroyReason aWhy)
 {
   if (aWhy == AbnormalShutdown) {
     // If the parent side runs into a problem then the actor will be destroyed.
     // There is nothing we can do in the child side, here sets mCanSend as false.
     gfxCriticalNote << "Receive IPC close with reason=AbnormalShutdown";
   }
 
-  {
-    // We take the lock to update these fields, since they are read from the
-    // paint thread. We don't need the lock to init them, since that happens
-    // on the main thread before the paint thread can ever grab a reference
-    // to the CompositorBridge object.
-    //
-    // Note that it is useful to take this lock for one other reason: It also
-    // tells us whether GetIPCChannel is safe to call. If we access the IPC
-    // channel within this lock, when mCanSend is true, then we know it has not
-    // been zapped by IPDL.
-    MonitorAutoLock lock(mPaintLock);
-    mCanSend = false;
-    mActorDestroyed = true;
-  }
+  mCanSend = false;
+  mActorDestroyed = true;
 
   if (mProcessToken && XRE_IsParentProcess()) {
     GPUProcessManager::Get()->NotifyRemoteActorDestroyed(mProcessToken);
   }
 }
 
 mozilla::ipc::IPCResult
 CompositorBridgeChild::RecvSharedCompositorFrameMetrics(
@@ -1125,91 +1109,11 @@ CompositorBridgeChild::GetNextExternalIm
 }
 
 wr::PipelineId
 CompositorBridgeChild::GetNextPipelineId()
 {
   return wr::AsPipelineId(GetNextResourceId());
 }
 
-void
-CompositorBridgeChild::NotifyBeginAsyncPaint()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  MonitorAutoLock lock(mPaintLock);
-
-  // We must not be waiting for paints to complete yet. This would imply we
-  // started a new paint without waiting for a previous one, which could lead to
-  // incorrect rendering or IPDL deadlocks.
-  MOZ_ASSERT(!mIsWaitingForPaint);
-
-  mOutstandingAsyncPaints++;
-}
-
-void
-CompositorBridgeChild::NotifyFinishedAsyncPaint()
-{
-  MOZ_ASSERT(PaintThread::IsOnPaintThread());
-
-  MonitorAutoLock lock(mPaintLock);
-
-  mOutstandingAsyncPaints--;
-
-  // It's possible that we painted so fast that the main thread never reached
-  // the code that starts delaying messages. If so, mIsWaitingForPaint will be
-  // false, and we can safely return.
-  if (mIsWaitingForPaint && mOutstandingAsyncPaints == 0) {
-    ResumeIPCAfterAsyncPaint();
-
-    // Notify the main thread in case it's blocking. We do this unconditionally
-    // to avoid deadlocking.
-    lock.Notify();
-  }
-}
-
-void
-CompositorBridgeChild::PostponeMessagesIfAsyncPainting()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  MonitorAutoLock lock(mPaintLock);
-
-  MOZ_ASSERT(!mIsWaitingForPaint);
-
-  if (mOutstandingAsyncPaints > 0) {
-    mIsWaitingForPaint = true;
-    GetIPCChannel()->BeginPostponingSends();
-  }
-}
-
-void
-CompositorBridgeChild::ResumeIPCAfterAsyncPaint()
-{
-  // Note: the caller is responsible for holding the lock.
-  mPaintLock.AssertCurrentThreadOwns();
-  MOZ_ASSERT(PaintThread::IsOnPaintThread());
-  MOZ_ASSERT(mOutstandingAsyncPaints == 0);
-  MOZ_ASSERT(mIsWaitingForPaint);
-
-  mIsWaitingForPaint = false;
-
-  // It's also possible that the channel has shut down already.
-  if (!mCanSend || mActorDestroyed) {
-    return;
-  }
-
-  GetIPCChannel()->StopPostponingSends();
-}
-
-void
-CompositorBridgeChild::FlushAsyncPaints()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  MonitorAutoLock lock(mPaintLock);
-  while (mIsWaitingForPaint) {
-    lock.Wait();
-  }
-}
-
 } // namespace layers
 } // namespace mozilla
+
--- a/gfx/layers/ipc/CompositorBridgeChild.h
+++ b/gfx/layers/ipc/CompositorBridgeChild.h
@@ -5,17 +5,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_layers_CompositorBridgeChild_h
 #define mozilla_layers_CompositorBridgeChild_h
 
 #include "base/basictypes.h"            // for DISALLOW_EVIL_CONSTRUCTORS
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT_HELPER2
 #include "mozilla/Attributes.h"         // for override
-#include "mozilla/Monitor.h"
 #include "mozilla/ipc/ProtocolUtils.h"
 #include "mozilla/layers/PCompositorBridgeChild.h"
 #include "mozilla/layers/TextureForwarder.h" // for TextureForwarder
 #include "mozilla/webrender/WebRenderTypes.h"
 #include "nsClassHashtable.h"           // for nsClassHashtable
 #include "nsRefPtrHashtable.h"
 #include "nsCOMPtr.h"                   // for nsCOMPtr
 #include "nsHashKeys.h"                 // for nsUint64HashKey
@@ -216,43 +215,20 @@ public:
   uint64_t DeviceResetSequenceNumber() const {
     return mDeviceResetSequenceNumber;
   }
 
   wr::MaybeExternalImageId GetNextExternalImageId() override;
 
   wr::PipelineId GetNextPipelineId();
 
-  // Must only be called from the main thread. Notifies the CompositorBridge
-  // that the paint thread is going to begin painting asynchronously.
-  void NotifyBeginAsyncPaint();
-
-  // Must only be called from the paint thread. Notifies the CompositorBridge
-  // that the paint thread has finished an asynchronous paint request.
-  void NotifyFinishedAsyncPaint();
-
-  // Must only be called from the main thread. Notifies the CompoistorBridge
-  // that a transaction is about to be sent, and if the paint thread is
-  // currently painting, to begin delaying IPC messages.
-  void PostponeMessagesIfAsyncPainting();
-
-  // Must only be called from the main thread. Ensures that any paints from
-  // previous frames have been flushed. The main thread blocks until the
-  // operation completes.
-  void FlushAsyncPaints();
-
 private:
   // Private destructor, to discourage deletion outside of Release():
   virtual ~CompositorBridgeChild();
 
-  // Must only be called from the paint thread. If the main thread is delaying
-  // IPC messages, this forwards all such delayed IPC messages to the I/O thread
-  // and resumes IPC.
-  void ResumeIPCAfterAsyncPaint();
-
   void AfterDestroy();
 
   virtual PLayerTransactionChild*
     AllocPLayerTransactionChild(const nsTArray<LayersBackend>& aBackendHints,
                                 const uint64_t& aId) override;
 
   virtual bool DeallocPLayerTransactionChild(PLayerTransactionChild *aChild) override;
 
@@ -347,28 +323,14 @@ private:
 
   MessageLoop* mMessageLoop;
 
   AutoTArray<RefPtr<TextureClientPool>,2> mTexturePools;
 
   uint64_t mProcessToken;
 
   FixedSizeSmallShmemSectionAllocator* mSectionAllocator;
-
-  // Off-Main-Thread Painting state. This covers access to the OMTP-related
-  // state below.
-  Monitor mPaintLock;
-
-  // Contains the number of outstanding asynchronous paints tied to a
-  // PLayerTransaction on this bridge. This is R/W on both the main and paint
-  // threads, and must be accessed within the paint lock.
-  size_t mOutstandingAsyncPaints;
-
-  // True if this CompositorBridge is currently delaying its messages until the
-  // paint thread completes. This is R/W on both the main and paint threads, and
-  // must be accessed within the paint lock.
-  bool mIsWaitingForPaint;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif // mozilla_layers_CompositorBrigedChild_h
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -759,20 +759,16 @@ ShadowLayerForwarder::EndTransaction(con
     if (locks.Length()) {
       if (!mShadowManager->SendInitReadLocks(locks)) {
         MOZ_LAYERS_LOG(("[LayersForwarder] WARNING: sending read locks failed!"));
         return false;
       }
     }
   }
 
-  // We delay at the last possible minute, to give the paint thread a chance to
-  // finish. If it does we don't have to delay messages at all.
-  GetCompositorBridgeChild()->PostponeMessagesIfAsyncPainting();
-
   MOZ_LAYERS_LOG(("[LayersForwarder] sending transaction..."));
   RenderTraceScope rendertrace3("Forward Transaction", "000093");
   if (!mShadowManager->SendUpdate(info)) {
     MOZ_LAYERS_LOG(("[LayersForwarder] WARNING: sending transaction failed!"));
     return false;
   }
 
   if (startTime) {
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -580,17 +580,16 @@ private:
   DECL_GFX_PREF(Once, "layers.mlgpu.enable-clear-view",        AdvancedLayersEnableClearView, bool, true);
   DECL_GFX_PREF(Once, "layers.mlgpu.enable-cpu-occlusion",     AdvancedLayersEnableCPUOcclusion, bool, true);
   DECL_GFX_PREF(Once, "layers.mlgpu.enable-depth-buffer",      AdvancedLayersEnableDepthBuffer, bool, false);
   DECL_GFX_PREF(Live, "layers.mlgpu.enable-invalidation",      AdvancedLayersUseInvalidation, bool, true);
   DECL_GFX_PREF(Once, "layers.mlgpu.enable-on-windows7",       AdvancedLayersEnableOnWindows7, bool, false);
   DECL_GFX_PREF(Once, "layers.mlgpu.enable-container-resizing", AdvancedLayersEnableContainerResizing, bool, true);
   DECL_GFX_PREF(Once, "layers.offmainthreadcomposition.force-disabled", LayersOffMainThreadCompositionForceDisabled, bool, false);
   DECL_GFX_PREF(Live, "layers.offmainthreadcomposition.frame-rate", LayersCompositionFrameRate, int32_t,-1);
-  DECL_GFX_PREF(Live, "layers.omtp.force-sync",                LayersOMTPForceSync, bool, true);
   DECL_GFX_PREF(Live, "layers.orientation.sync.timeout",       OrientationSyncMillis, uint32_t, (uint32_t)0);
   DECL_GFX_PREF(Once, "layers.prefer-opengl",                  LayersPreferOpenGL, bool, false);
   DECL_GFX_PREF(Live, "layers.progressive-paint",              ProgressivePaint, bool, false);
   DECL_GFX_PREF(Live, "layers.shared-buffer-provider.enabled", PersistentBufferProviderSharedEnabled, bool, false);
   DECL_GFX_PREF(Live, "layers.single-tile.enabled",            LayersSingleTileEnabled, bool, true);
   DECL_GFX_PREF(Once, "layers.stereo-video.enabled",           StereoVideoEnabled, bool, false);
   DECL_GFX_PREF(Live, "layers.force-synchronous-resize",       LayersForceSynchronousResize, bool, false);
 
--- a/xpcom/base/StaticPtr.h
+++ b/xpcom/base/StaticPtr.h
@@ -62,23 +62,16 @@ public:
   T* operator->() const
   {
     MOZ_ASSERT(mRawPtr);
     return get();
   }
 
   T& operator*() const { return *get(); }
 
-  T* forget()
-  {
-    T* temp = mRawPtr;
-    mRawPtr = nullptr;
-    return temp;
-  }
-
 private:
   // Disallow copy constructor, but only in debug mode.  We only define
   // a default constructor in debug mode (see above); if we declared
   // this constructor always, the compiler wouldn't generate a trivial
   // default constructor for us in non-debug mode.
 #ifdef DEBUG
   StaticAutoPtr(StaticAutoPtr<T>& aOther);
 #endif