Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  nsCCUncollectableMarker.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 "nsCCUncollectableMarker.h"
#include "nsIObserverService.h"
#include "nsIDocShell.h"
#include "nsServiceManagerUtils.h"
#include "nsIDocumentViewer.h"
#include "mozilla/dom/Document.h"
#include "InProcessBrowserChildMessageManager.h"
#include "nsIWindowMediator.h"
#include "nsPIDOMWindow.h"
#include "nsIWebNavigation.h"
#include "nsISHistory.h"
#include "nsISHEntry.h"
#include "nsIWindowWatcher.h"
#include "mozilla/Services.h"
#include "nsIAppWindow.h"
#include "nsIAppShellService.h"
#include "nsAppShellCID.h"
#include "nsContentUtils.h"
#include "nsGlobalWindowInner.h"
#include "nsGlobalWindowOuter.h"
#include "nsJSEnvironment.h"
#include "nsFrameLoader.h"
#include "mozilla/CycleCollectedJSContext.h"
#include "mozilla/CycleCollectedJSRuntime.h"
#include "mozilla/EventListenerManager.h"
#include "mozilla/dom/ChromeMessageBroadcaster.h"
#include "mozilla/dom/ContentFrameMessageManager.h"
#include "mozilla/dom/ContentProcessMessageManager.h"
#include "mozilla/dom/CustomElementRegistry.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/ParentProcessMessageManager.h"
#include "mozilla/dom/BrowserChild.h"
#include "mozilla/dom/TimeoutManager.h"
#include "xpcpublic.h"
#include "nsObserverService.h"
#include "nsFocusManager.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsIXULRuntime.h"

using namespace mozilla;
using namespace mozilla::dom;

static bool sInited = 0;
// The initial value of sGeneration should not be the same as the
// value it is given at xpcom-shutdown, because this will make any GCs
// before we first CC benignly violate the black-gray invariant, due
// to dom::TraceBlackJS().
uint32_t nsCCUncollectableMarker::sGeneration = 1;
#include "nsXULPrototypeCache.h"

NS_IMPL_ISUPPORTS(nsCCUncollectableMarker, nsIObserver)

/* static */
nsresult nsCCUncollectableMarker::Init() {
  if (sInited) {
    return NS_OK;
  }

  nsCOMPtr<nsIObserver> marker = new nsCCUncollectableMarker;

  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
  if (!obs) return NS_ERROR_FAILURE;

  nsresult rv;

  // This makes the observer service hold an owning reference to the marker
  rv = obs->AddObserver(marker, "xpcom-shutdown"false);
  NS_ENSURE_SUCCESS(rv, rv);

  rv = obs->AddObserver(marker, "cycle-collector-begin"false);
  NS_ENSURE_SUCCESS(rv, rv);
  rv = obs->AddObserver(marker, "cycle-collector-forget-skippable"false);
  NS_ENSURE_SUCCESS(rv, rv);

  sInited = true;

  return NS_OK;
}

static void MarkChildMessageManagers(MessageBroadcaster* aMM) {
  aMM->MarkForCC();

  uint32_t browserChildCount = aMM->ChildCount();
  for (uint32_t j = 0; j < browserChildCount; ++j) {
    RefPtr<MessageListenerManager> childMM = aMM->GetChildAt(j);
    if (!childMM) {
      continue;
    }

    RefPtr<MessageBroadcaster> strongNonLeafMM =
        MessageBroadcaster::From(childMM);
    MessageBroadcaster* nonLeafMM = strongNonLeafMM;

    MessageListenerManager* tabMM = childMM;

    strongNonLeafMM = nullptr;
    childMM = nullptr;

    if (nonLeafMM) {
      MarkChildMessageManagers(nonLeafMM);
      continue;
    }

    tabMM->MarkForCC();

    // XXX hack warning, but works, since we know that
    //    callback is frameloader.
    mozilla::dom::ipc::MessageManagerCallback* cb = tabMM->GetCallback();
    if (cb) {
      nsFrameLoader* fl = static_cast<nsFrameLoader*>(cb);
      InProcessBrowserChildMessageManager* et =
          fl->GetBrowserChildMessageManager();
      if (!et) {
        continue;
      }
      et->MarkForCC();
      EventListenerManager* elm = et->GetExistingListenerManager();
      if (elm) {
        elm->MarkForCC();
      }
    }
  }
}

static void MarkMessageManagers() {
  if (nsFrameMessageManager::GetChildProcessManager()) {
    // ContentProcessMessageManager's MarkForCC also marks ChildProcessManager.
    ContentProcessMessageManager* pg = ContentProcessMessageManager::Get();
    if (pg) {
      pg->MarkForCC();
    }
  }

  // The global message manager only exists in the root process.
  if (!XRE_IsParentProcess()) {
    return;
  }
  RefPtr<ChromeMessageBroadcaster> strongGlobalMM =
      nsFrameMessageManager::GetGlobalMessageManager();
  if (!strongGlobalMM) {
    return;
  }
  ChromeMessageBroadcaster* globalMM = strongGlobalMM;
  strongGlobalMM = nullptr;
  MarkChildMessageManagers(globalMM);

  if (nsFrameMessageManager::sParentProcessManager) {
    nsFrameMessageManager::sParentProcessManager->MarkForCC();
    uint32_t childCount =
        nsFrameMessageManager::sParentProcessManager->ChildCount();
    for (uint32_t i = 0; i < childCount; ++i) {
      RefPtr<MessageListenerManager> childMM =
          nsFrameMessageManager::sParentProcessManager->GetChildAt(i);
      if (!childMM) {
        continue;
      }
      MessageListenerManager* child = childMM;
      childMM = nullptr;
      child->MarkForCC();
    }
  }
  if (nsFrameMessageManager::sSameProcessParentManager) {
    nsFrameMessageManager::sSameProcessParentManager->MarkForCC();
  }
}

void MarkDocumentViewer(nsIDocumentViewer* aViewer, bool aCleanupJS) {
  if (!aViewer) {
    return;
  }

  Document* doc = aViewer->GetDocument();
  if (doc &&
      doc->GetMarkedCCGeneration() != nsCCUncollectableMarker::sGeneration) {
    doc->MarkUncollectableForCCGeneration(nsCCUncollectableMarker::sGeneration);
    if (aCleanupJS) {
      EventListenerManager* elm = doc->GetExistingListenerManager();
      if (elm) {
        elm->MarkForCC();
      }
      RefPtr<nsGlobalWindowInner> win =
          nsGlobalWindowInner::Cast(doc->GetInnerWindow());
      if (win) {
        elm = win->GetExistingListenerManager();
        if (elm) {
          elm->MarkForCC();
        }
        win->GetTimeoutManager()->UnmarkGrayTimers();
      }
    }
  }
  if (doc) {
    if (nsPIDOMWindowInner* inner = doc->GetInnerWindow()) {
      inner->MarkUncollectableForCCGeneration(
          nsCCUncollectableMarker::sGeneration);
    }
    if (nsPIDOMWindowOuter* outer = doc->GetWindow()) {
      outer->MarkUncollectableForCCGeneration(
          nsCCUncollectableMarker::sGeneration);
    }
  }
}

void MarkDocShell(nsIDocShellTreeItem* aNode, bool aCleanupJS);

void MarkSHEntry(nsISHEntry* aSHEntry, bool aCleanupJS) {
  if (!aSHEntry) {
    return;
  }

  nsCOMPtr<nsIDocumentViewer> viewer;
  aSHEntry->GetDocumentViewer(getter_AddRefs(viewer));
  MarkDocumentViewer(viewer, aCleanupJS);

  nsCOMPtr<nsIDocShellTreeItem> child;
  int32_t i = 0;
  while (NS_SUCCEEDED(aSHEntry->ChildShellAt(i++, getter_AddRefs(child))) &&
         child) {
    MarkDocShell(child, aCleanupJS);
  }

  int32_t count;
  aSHEntry->GetChildCount(&count);
  for (i = 0; i < count; ++i) {
    nsCOMPtr<nsISHEntry> childEntry;
    aSHEntry->GetChildAt(i, getter_AddRefs(childEntry));
    MarkSHEntry(childEntry, aCleanupJS);
  }
}

void MarkDocShell(nsIDocShellTreeItem* aNode, bool aCleanupJS) {
  nsCOMPtr<nsIDocShell> shell = do_QueryInterface(aNode);
  if (!shell) {
    return;
  }

  nsCOMPtr<nsIDocumentViewer> viewer;
  shell->GetDocViewer(getter_AddRefs(viewer));
  MarkDocumentViewer(viewer, aCleanupJS);

  nsCOMPtr<nsIWebNavigation> webNav = do_QueryInterface(shell);
  RefPtr<ChildSHistory> history = webNav->GetSessionHistory();
  IgnoredErrorResult ignore;
  nsISHistory* legacyHistory =
      history ? history->GetLegacySHistory(ignore) : nullptr;
  if (legacyHistory) {
    MOZ_DIAGNOSTIC_ASSERT(!mozilla::SessionHistoryInParent());
    int32_t historyCount = history->Count();
    for (int32_t i = 0; i < historyCount; ++i) {
      nsCOMPtr<nsISHEntry> shEntry;
      legacyHistory->GetEntryAtIndex(i, getter_AddRefs(shEntry));

      MarkSHEntry(shEntry, aCleanupJS);
    }
  }

  int32_t i, childCount;
  aNode->GetInProcessChildCount(&childCount);
  for (i = 0; i < childCount; ++i) {
    nsCOMPtr<nsIDocShellTreeItem> child;
    aNode->GetInProcessChildAt(i, getter_AddRefs(child));
    MarkDocShell(child, aCleanupJS);
  }
}

void MarkWindowList(nsISimpleEnumerator* aWindowList, bool aCleanupJS) {
  nsCOMPtr<nsISupports> iter;
  while (NS_SUCCEEDED(aWindowList->GetNext(getter_AddRefs(iter))) && iter) {
    if (nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryInterface(iter)) {
      nsCOMPtr<nsIDocShell> rootDocShell = window->GetDocShell();

      MarkDocShell(rootDocShell, aCleanupJS);

      RefPtr<BrowserChild> browserChild = BrowserChild::GetFrom(rootDocShell);
      if (browserChild) {
        RefPtr<BrowserChildMessageManager> mm =
            browserChild->GetMessageManager();
        if (mm) {
          // MarkForCC ends up calling UnmarkGray on message listeners, which
          // TraceBlackJS can't do yet.
          mm->MarkForCC();
        }
      }
    }
  }
}

nsresult nsCCUncollectableMarker::Observe(nsISupports* aSubject,
                                          const char* aTopic,
                                          const char16_t* aData) {
  if (!strcmp(aTopic, "xpcom-shutdown")) {
    Element::ClearContentUnbinder();

    nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
    if (!obs) return NS_ERROR_FAILURE;

    // No need for kungFuDeathGrip here, yay observerservice!
    obs->RemoveObserver(this"xpcom-shutdown");
    obs->RemoveObserver(this"cycle-collector-begin");
    obs->RemoveObserver(this"cycle-collector-forget-skippable");

    sGeneration = 0;

    return NS_OK;
  }

  NS_ASSERTION(!strcmp(aTopic, "cycle-collector-begin") ||
                   !strcmp(aTopic, "cycle-collector-forget-skippable"),
               "wrong topic");

  // JS cleanup can be slow. Do it only if this is the first forget-skippable
  // after a GC.
  const bool cleanupJS = nsJSContext::HasHadCleanupSinceLastGC() &&
                         !strcmp(aTopic, "cycle-collector-forget-skippable");

  const bool prepareForCC = !strcmp(aTopic, "cycle-collector-begin");
  if (prepareForCC) {
    Element::ClearContentUnbinder();
  }

  // Increase generation to effectively unmark all current objects
  if (!++sGeneration) {
    ++sGeneration;
  }

  nsFocusManager::MarkUncollectableForCCGeneration(sGeneration);

  nsresult rv;

  // Iterate all toplevel windows
  nsCOMPtr<nsISimpleEnumerator> windowList;
  nsCOMPtr<nsIWindowMediator> med = do_GetService(NS_WINDOWMEDIATOR_CONTRACTID);
  if (med) {
    rv = med->GetEnumerator(nullptr, getter_AddRefs(windowList));
    NS_ENSURE_SUCCESS(rv, rv);

    MarkWindowList(windowList, cleanupJS);
  }

  nsCOMPtr<nsIWindowWatcher> ww = do_GetService(NS_WINDOWWATCHER_CONTRACTID);
  if (ww) {
    rv = ww->GetWindowEnumerator(getter_AddRefs(windowList));
    NS_ENSURE_SUCCESS(rv, rv);

    MarkWindowList(windowList, cleanupJS);
  }

  nsCOMPtr<nsIAppShellService> appShell =
      do_GetService(NS_APPSHELLSERVICE_CONTRACTID);
  if (appShell) {
    bool hasHiddenWindow = false;
    appShell->GetHasHiddenWindow(&hasHiddenWindow);
    if (hasHiddenWindow) {
      nsCOMPtr<nsIAppWindow> hw;
      appShell->GetHiddenWindow(getter_AddRefs(hw));
      nsCOMPtr<nsIDocShell> shell;
      hw->GetDocShell(getter_AddRefs(shell));
      MarkDocShell(shell, cleanupJS);
    }
  }

  nsXULPrototypeCache* xulCache = nsXULPrototypeCache::GetInstance();
  if (xulCache) {
    xulCache->MarkInCCGeneration(sGeneration);
  }

  enum ForgetSkippableCleanupState {
    eInitial = 0,
    eUnmarkJSEventListeners = 1,
    eUnmarkMessageManagers = 2,
    eUnmarkStrongObservers = 3,
    eUnmarkJSHolders = 4,
    eDone = 5
  };

  static_assert(eDone == kMajorForgetSkippableCalls,
                "There must be one forgetSkippable call per cleanup state.");

  static uint32_t sFSState = eDone;
  if (prepareForCC) {
    sFSState = eDone;
    return NS_OK;
  }

  if (cleanupJS) {
    // After a GC we start clean up phases from the beginning,
    // but we don't want to do the additional clean up phases here
    // since we have done already plenty of gray unmarking while going through
    // frame message managers and docshells.
    sFSState = eInitial;
    return NS_OK;
  } else {
    ++sFSState;
  }

  switch (sFSState) {
    case eUnmarkJSEventListeners: {
      nsContentUtils::UnmarkGrayJSListenersInCCGenerationDocuments();
      break;
    }
    case eUnmarkMessageManagers: {
      MarkMessageManagers();
      break;
    }
    case eUnmarkStrongObservers: {
      nsCOMPtr<nsIObserverService> obs =
          mozilla::services::GetObserverService();
      static_cast<nsObserverService*>(obs.get())->UnmarkGrayStrongObservers();
      break;
    }
    case eUnmarkJSHolders: {
      xpc_UnmarkSkippableJSHolders();
      break;
    }
    default: {
      break;
    }
  }

  return NS_OK;
}

void mozilla::dom::TraceBlackJS(JSTracer* aTrc) {
  if (!nsCCUncollectableMarker::sGeneration) {
    return;
  }

  if (ContentProcessMessageManager::WasCreated() &&
      nsFrameMessageManager::GetChildProcessManager()) {
    auto* pg = ContentProcessMessageManager::Get();
    if (pg) {
      mozilla::TraceScriptHolder(ToSupports(pg), aTrc);
    }
  }

  // Mark globals of active windows black.
  nsGlobalWindowOuter::OuterWindowByIdTable* windowsById =
      nsGlobalWindowOuter::GetWindowsTable();
  if (windowsById) {
    for (nsGlobalWindowOuter* window : windowsById->Values()) {
      if (!window->IsCleanedUp()) {
        nsGlobalWindowInner* inner = nullptr;
        for (PRCList* win = PR_LIST_HEAD(window); win != window;
             win = PR_NEXT_LINK(inner)) {
          inner = static_cast<nsGlobalWindowInner*>(win);
          if (inner->IsCurrentInnerWindow() ||
              (inner->GetExtantDoc() &&
               inner->GetExtantDoc()->GetBFCacheEntry())) {
            inner->TraceGlobalJSObject(aTrc);
            EventListenerManager* elm = inner->GetExistingListenerManager();
            if (elm) {
              elm->TraceListeners(aTrc);
            }
            CustomElementRegistry* cer = inner->GetExistingCustomElements();
            if (cer) {
              cer->TraceDefinitions(aTrc);
            }
          }
        }

        if (window->IsRootOuterWindow()) {
          // In child process trace all the BrowserChildMessageManagers.
          // Since there is one root outer window per
          // BrowserChildMessageManager, we need to look for only those windows,
          // not all.
          nsIDocShell* ds = window->GetDocShell();
          if (ds) {
            nsCOMPtr<nsIBrowserChild> browserChild = ds->GetBrowserChild();
            if (browserChild) {
              RefPtr<ContentFrameMessageManager> mm;
              browserChild->GetMessageManager(getter_AddRefs(mm));
              if (mm) {
                nsCOMPtr<nsISupports> browserChildAsSupports =
                    do_QueryInterface(browserChild);
                mozilla::TraceScriptHolder(browserChildAsSupports, aTrc);
                EventListenerManager* elm = mm->GetExistingListenerManager();
                if (elm) {
                  elm->TraceListeners(aTrc);
                }
                // As of now there isn't an easy way to trace message listeners.
              }
            }
          }
        }
      }
    }
  }
}

Messung V0.5
C=95 H=97 G=95

¤ Dauer der Verarbeitung: 0.17 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge