Bug 861449 - Incremental css::Rule destroyer. r=dbaron

Destroying large arrays of css::Rules during page teardown can take
multiple milliseconds in incremental CC. To reduce CC pauses, this
patch introduces a new class nsIncrementalClearCOMRuleArray that uses
the deferred finalizer to incrementally destroy these rule arrays.
This commit is contained in:
Andrew McCreight 2015-06-15 12:34:23 -07:00
Родитель 350215c93f
Коммит a886770a11
5 изменённых файлов: 116 добавлений и 6 удалений

Просмотреть файл

@ -10,6 +10,7 @@
#define mozilla_CSSStyleSheet_h
#include "mozilla/Attributes.h"
#include "mozilla/IncrementalClearCOMRuleArray.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/dom/Element.h"
@ -19,7 +20,6 @@
#include "nsIStyleSheet.h"
#include "nsIDOMCSSStyleSheet.h"
#include "nsICSSLoaderObserver.h"
#include "nsCOMArray.h"
#include "nsTArrayForwardDeclare.h"
#include "nsString.h"
#include "mozilla/CORSMode.h"
@ -84,7 +84,7 @@ private:
nsCOMPtr<nsIURI> mOriginalSheetURI; // for GetHref. Can be null.
nsCOMPtr<nsIURI> mBaseURI; // for resolving relative URIs
nsCOMPtr<nsIPrincipal> mPrincipal;
nsCOMArray<css::Rule> mOrderedRules;
IncrementalClearCOMRuleArray mOrderedRules;
nsAutoPtr<nsXMLNameSpaceMap> mNameSpaceMap;
// Linked list of child sheets. This is al fundamentally broken, because
// each of the child sheets has a unique parent... We can only hope (and

Просмотреть файл

@ -12,9 +12,9 @@
#define mozilla_css_GroupRule_h__
#include "mozilla/Attributes.h"
#include "mozilla/IncrementalClearCOMRuleArray.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/css/Rule.h"
#include "nsCOMArray.h"
#include "nsAutoPtr.h"
#include "nsCycleCollectionParticipant.h"
@ -57,7 +57,7 @@ public:
int32_t StyleRuleCount() const { return mRules.Count(); }
Rule* GetStyleRuleAt(int32_t aIndex) const;
typedef nsCOMArray<Rule>::nsCOMArrayEnumFunc RuleEnumFunc;
typedef IncrementalClearCOMRuleArray::nsCOMArrayEnumFunc RuleEnumFunc;
bool EnumerateRulesForwards(RuleEnumFunc aFunc, void * aData) const;
/*
@ -80,7 +80,7 @@ public:
CloneRuleInto(Rule* aRule, void* aArray)
{
nsRefPtr<Rule> clone = aRule->Clone();
static_cast<nsCOMArray<Rule>*>(aArray)->AppendObject(clone);
static_cast<IncrementalClearCOMRuleArray*>(aArray)->AppendObject(clone);
return true;
}
@ -95,7 +95,7 @@ protected:
uint32_t* _retval);
nsresult DeleteRule(uint32_t aIndex);
nsCOMArray<Rule> mRules;
IncrementalClearCOMRuleArray mRules;
nsRefPtr<GroupRuleRuleList> mRuleCollection; // lazily constructed
};

Просмотреть файл

@ -0,0 +1,80 @@
/* -*- 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 "mozilla/IncrementalClearCOMRuleArray.h"
#include "nsCycleCollector.h"
#include "mozilla/DeferredFinalize.h"
#include "nsTArray.h"
#include "nsCCUncollectableMarker.h"
using namespace mozilla;
typedef nsCOMArray<css::Rule> RuleArray;
typedef nsTArray<RuleArray> RuleArrayArray;
// These methods are based on those in DeferredFinalizerImpl.
static void*
AppendRulesArrayPointer(void* aData, void* aObject)
{
RuleArrayArray* rulesArray = static_cast<RuleArrayArray*>(aData);
RuleArray* oldRules = static_cast<RuleArray*>(aObject);
if (!rulesArray) {
rulesArray = new RuleArrayArray();
}
RuleArray* newRules = rulesArray->AppendElement();
newRules->SwapElements(*oldRules);
return rulesArray;
}
// Remove up to |aSliceBudget| css::Rules from the arrays, starting at
// the end of the last array.
static bool
DeferredFinalizeRulesArray(uint32_t aSliceBudget, void* aData)
{
MOZ_ASSERT(aSliceBudget > 0, "nonsensical/useless call with aSliceBudget == 0");
RuleArrayArray* rulesArray = static_cast<RuleArrayArray*>(aData);
size_t newOuterLen = rulesArray->Length();
while (aSliceBudget > 0 && newOuterLen > 0) {
RuleArray& lastArray = rulesArray->ElementAt(newOuterLen - 1);
uint32_t innerLen = lastArray.Length();
uint32_t currSlice = std::min(innerLen, aSliceBudget);
uint32_t newInnerLen = innerLen - currSlice;
lastArray.TruncateLength(newInnerLen);
aSliceBudget -= currSlice;
if (newInnerLen == 0) {
newOuterLen -= 1;
}
}
rulesArray->TruncateLength(newOuterLen);
if (newOuterLen == 0) {
delete rulesArray;
return true;
}
return false;
}
void
IncrementalClearCOMRuleArray::Clear()
{
// Destroy the array incrementally if it is long and we
// haven't started shutting down.
if (Length() > 10 && nsCCUncollectableMarker::sGeneration) {
DeferredFinalize(AppendRulesArrayPointer, DeferredFinalizeRulesArray, this);
} else {
nsCOMArray<css::Rule>::Clear();
}
MOZ_ASSERT(Length() == 0);
}

Просмотреть файл

@ -0,0 +1,28 @@
/* -*- 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/. */
#ifndef mozilla_IncrementalClearCOMRuleArray_h
#define mozilla_IncrementalClearCOMRuleArray_h
#include "nsCOMArray.h"
namespace mozilla {
namespace css {
class Rule;
} // namespace css
class IncrementalClearCOMRuleArray : public nsCOMArray<css::Rule>
{
public:
IncrementalClearCOMRuleArray() {}
~IncrementalClearCOMRuleArray() { Clear(); }
void Clear();
};
} // namespace mozilla
#endif /* !defined(mozilla_IncrementalClearCOMRuleArray_h) */

Просмотреть файл

@ -84,6 +84,7 @@ EXPORTS.mozilla += [
'CSSVariableDeclarations.h',
'CSSVariableResolver.h',
'CSSVariableValues.h',
'IncrementalClearCOMRuleArray.h',
'StyleAnimationValue.h',
]
@ -125,6 +126,7 @@ UNIFIED_SOURCES += [
'FontFace.cpp',
'FontFaceSetIterator.cpp',
'ImageLoader.cpp',
'IncrementalClearCOMRuleArray.cpp',
'Loader.cpp',
'MediaQueryList.cpp',
'nsAnimationManager.cpp',