summaryrefslogtreecommitdiffstats
path: root/layout/style/IncrementalClearCOMRuleArray.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'layout/style/IncrementalClearCOMRuleArray.cpp')
-rw-r--r--layout/style/IncrementalClearCOMRuleArray.cpp81
1 files changed, 81 insertions, 0 deletions
diff --git a/layout/style/IncrementalClearCOMRuleArray.cpp b/layout/style/IncrementalClearCOMRuleArray.cpp
new file mode 100644
index 000000000..92cdced22
--- /dev/null
+++ b/layout/style/IncrementalClearCOMRuleArray.cpp
@@ -0,0 +1,81 @@
+/* -*- 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 <algorithm> // For std::min
+#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);
+}