зеркало из https://github.com/mozilla/gecko-dev.git
Bug 847236 - Simplify the dead nsEventTargetChainItem objects cache (2nd attempt). r=smaug.
--HG-- extra : rebase_source : c46d667fbcc56bdc1826ea61bc62f656f79c3919
This commit is contained in:
Родитель
2620400c66
Коммит
7a41aa92ce
|
@ -24,7 +24,6 @@
|
||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
#include "nsReadableUtils.h"
|
#include "nsReadableUtils.h"
|
||||||
#include "nsAutoPtr.h"
|
#include "nsAutoPtr.h"
|
||||||
#include NEW_H
|
|
||||||
#include "prprf.h"
|
#include "prprf.h"
|
||||||
#include "nsIDocument.h"
|
#include "nsIDocument.h"
|
||||||
#include "nsGkAtoms.h"
|
#include "nsGkAtoms.h"
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
/* -*- 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
|
/* 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
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
@ -12,7 +13,6 @@
|
||||||
#include "nsError.h"
|
#include "nsError.h"
|
||||||
#include "nsMutationEvent.h"
|
#include "nsMutationEvent.h"
|
||||||
#include NEW_H
|
#include NEW_H
|
||||||
#include "nsFixedSizeAllocator.h"
|
|
||||||
#include "nsINode.h"
|
#include "nsINode.h"
|
||||||
#include "nsPIDOMWindow.h"
|
#include "nsPIDOMWindow.h"
|
||||||
#include "nsFrameLoader.h"
|
#include "nsFrameLoader.h"
|
||||||
|
@ -27,8 +27,6 @@ using namespace mozilla;
|
||||||
#define NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT (1 << 1)
|
#define NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT (1 << 1)
|
||||||
#define NS_TARGET_CHAIN_MAY_HAVE_MANAGER (1 << 2)
|
#define NS_TARGET_CHAIN_MAY_HAVE_MANAGER (1 << 2)
|
||||||
|
|
||||||
static nsEventTargetChainItem* gCachedETCI = nullptr;
|
|
||||||
|
|
||||||
// nsEventTargetChainItem represents a single item in the event target chain.
|
// nsEventTargetChainItem represents a single item in the event target chain.
|
||||||
class nsEventTargetChainItem
|
class nsEventTargetChainItem
|
||||||
{
|
{
|
||||||
|
@ -36,25 +34,32 @@ private:
|
||||||
nsEventTargetChainItem(nsIDOMEventTarget* aTarget,
|
nsEventTargetChainItem(nsIDOMEventTarget* aTarget,
|
||||||
nsEventTargetChainItem* aChild = nullptr);
|
nsEventTargetChainItem* aChild = nullptr);
|
||||||
|
|
||||||
|
// This is the ETCI recycle pool, which is used to avoid some malloc/free
|
||||||
|
// churn. It's implemented as a linked list.
|
||||||
|
static nsEventTargetChainItem* sEtciRecyclePool;
|
||||||
|
static uint32_t sNumRecycledEtcis;
|
||||||
|
static const uint32_t kMaxNumRecycledEtcis = 128;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static nsEventTargetChainItem* Create(nsFixedSizeAllocator* aAllocator,
|
static nsEventTargetChainItem* Create(nsIDOMEventTarget* aTarget,
|
||||||
nsIDOMEventTarget* aTarget,
|
|
||||||
nsEventTargetChainItem* aChild = nullptr)
|
nsEventTargetChainItem* aChild = nullptr)
|
||||||
{
|
{
|
||||||
|
// Allocate from the ETCI recycle pool if possible.
|
||||||
void* place = nullptr;
|
void* place = nullptr;
|
||||||
if (gCachedETCI) {
|
if (sNumRecycledEtcis > 0) {
|
||||||
place = gCachedETCI;
|
MOZ_ASSERT(sEtciRecyclePool);
|
||||||
gCachedETCI = gCachedETCI->mNext;
|
place = sEtciRecyclePool;
|
||||||
|
sEtciRecyclePool = sEtciRecyclePool->mNext;
|
||||||
|
--sNumRecycledEtcis;
|
||||||
} else {
|
} else {
|
||||||
place = aAllocator->Alloc(sizeof(nsEventTargetChainItem));
|
place = malloc(sizeof(nsEventTargetChainItem));
|
||||||
}
|
}
|
||||||
return place
|
return place
|
||||||
? ::new (place) nsEventTargetChainItem(aTarget, aChild)
|
? ::new (place) nsEventTargetChainItem(aTarget, aChild)
|
||||||
: nullptr;
|
: nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Destroy(nsFixedSizeAllocator* aAllocator,
|
static void Destroy(nsEventTargetChainItem* aItem)
|
||||||
nsEventTargetChainItem* aItem)
|
|
||||||
{
|
{
|
||||||
// ::Destroy deletes ancestor chain.
|
// ::Destroy deletes ancestor chain.
|
||||||
nsEventTargetChainItem* item = aItem;
|
nsEventTargetChainItem* item = aItem;
|
||||||
|
@ -62,16 +67,30 @@ public:
|
||||||
item->mChild->mParent = nullptr;
|
item->mChild->mParent = nullptr;
|
||||||
item->mChild = nullptr;
|
item->mChild = nullptr;
|
||||||
}
|
}
|
||||||
|
// Put destroyed ETCIs into the recycle pool if it's not already full.
|
||||||
while (item) {
|
while (item) {
|
||||||
nsEventTargetChainItem* parent = item->mParent;
|
nsEventTargetChainItem* parent = item->mParent;
|
||||||
item->~nsEventTargetChainItem();
|
item->~nsEventTargetChainItem();
|
||||||
item->mNext = gCachedETCI;
|
if (sNumRecycledEtcis < kMaxNumRecycledEtcis) {
|
||||||
gCachedETCI = item;
|
item->mNext = sEtciRecyclePool;
|
||||||
--sCurrentEtciCount;
|
sEtciRecyclePool = item;
|
||||||
|
++sNumRecycledEtcis;
|
||||||
|
} else {
|
||||||
|
free(item);
|
||||||
|
}
|
||||||
item = parent;
|
item = parent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ShutdownRecyclePool()
|
||||||
|
{
|
||||||
|
while (sEtciRecyclePool) {
|
||||||
|
nsEventTargetChainItem* tmp = sEtciRecyclePool;
|
||||||
|
sEtciRecyclePool = sEtciRecyclePool->mNext;
|
||||||
|
free(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool IsValid()
|
bool IsValid()
|
||||||
{
|
{
|
||||||
NS_WARN_IF_FALSE(!!(mTarget), "Event target is not valid!");
|
NS_WARN_IF_FALSE(!!(mTarget), "Event target is not valid!");
|
||||||
|
@ -205,7 +224,7 @@ public:
|
||||||
nsEventTargetChainItem* mChild;
|
nsEventTargetChainItem* mChild;
|
||||||
union {
|
union {
|
||||||
nsEventTargetChainItem* mParent;
|
nsEventTargetChainItem* mParent;
|
||||||
// This is used only when caching ETCI objects.
|
// This is used only when recycling ETCIs.
|
||||||
nsEventTargetChainItem* mNext;
|
nsEventTargetChainItem* mNext;
|
||||||
};
|
};
|
||||||
uint16_t mFlags;
|
uint16_t mFlags;
|
||||||
|
@ -220,8 +239,8 @@ public:
|
||||||
static uint32_t sCurrentEtciCount;
|
static uint32_t sCurrentEtciCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
uint32_t nsEventTargetChainItem::sMaxEtciCount = 0;
|
nsEventTargetChainItem* nsEventTargetChainItem::sEtciRecyclePool = nullptr;
|
||||||
uint32_t nsEventTargetChainItem::sCurrentEtciCount = 0;
|
uint32_t nsEventTargetChainItem::sNumRecycledEtcis = 0;
|
||||||
|
|
||||||
nsEventTargetChainItem::nsEventTargetChainItem(nsIDOMEventTarget* aTarget,
|
nsEventTargetChainItem::nsEventTargetChainItem(nsIDOMEventTarget* aTarget,
|
||||||
nsEventTargetChainItem* aChild)
|
nsEventTargetChainItem* aChild)
|
||||||
|
@ -231,10 +250,6 @@ nsEventTargetChainItem::nsEventTargetChainItem(nsIDOMEventTarget* aTarget,
|
||||||
if (mChild) {
|
if (mChild) {
|
||||||
mChild->mParent = this;
|
mChild->mParent = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (++sCurrentEtciCount > sMaxEtciCount) {
|
|
||||||
sMaxEtciCount = sCurrentEtciCount;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
|
@ -378,69 +393,13 @@ nsEventTargetChainItem::HandleEventTargetChain(
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define NS_CHAIN_POOL_SIZE 128
|
void NS_ShutdownEventTargetChainItemRecyclePool()
|
||||||
|
{
|
||||||
class ChainItemPool {
|
nsEventTargetChainItem::ShutdownRecyclePool();
|
||||||
public:
|
}
|
||||||
ChainItemPool() {
|
|
||||||
if (!sEtciPool) {
|
|
||||||
sEtciPool = new nsFixedSizeAllocator();
|
|
||||||
if (sEtciPool) {
|
|
||||||
static const size_t kBucketSizes[] = { sizeof(nsEventTargetChainItem) };
|
|
||||||
static const int32_t kNumBuckets = sizeof(kBucketSizes) / sizeof(size_t);
|
|
||||||
static const int32_t kInitialPoolSize =
|
|
||||||
sizeof(nsEventTargetChainItem) * NS_CHAIN_POOL_SIZE;
|
|
||||||
nsresult rv = sEtciPool->Init("EventTargetChainItem Pool", kBucketSizes,
|
|
||||||
kNumBuckets, kInitialPoolSize);
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
delete sEtciPool;
|
|
||||||
sEtciPool = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (sEtciPool) {
|
|
||||||
++sEtciPoolUsers;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~ChainItemPool() {
|
|
||||||
if (sEtciPool) {
|
|
||||||
--sEtciPoolUsers;
|
|
||||||
}
|
|
||||||
if (!sEtciPoolUsers) {
|
|
||||||
if (nsEventTargetChainItem::MaxEtciCount() > NS_CHAIN_POOL_SIZE) {
|
|
||||||
gCachedETCI = nullptr;
|
|
||||||
delete sEtciPool;
|
|
||||||
sEtciPool = nullptr;
|
|
||||||
nsEventTargetChainItem::ResetMaxEtciCount();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Shutdown()
|
|
||||||
{
|
|
||||||
if (!sEtciPoolUsers) {
|
|
||||||
gCachedETCI = nullptr;
|
|
||||||
delete sEtciPool;
|
|
||||||
sEtciPool = nullptr;
|
|
||||||
nsEventTargetChainItem::ResetMaxEtciCount();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
nsFixedSizeAllocator* GetPool() { return sEtciPool; }
|
|
||||||
|
|
||||||
static nsFixedSizeAllocator* sEtciPool;
|
|
||||||
static int32_t sEtciPoolUsers;
|
|
||||||
};
|
|
||||||
|
|
||||||
nsFixedSizeAllocator* ChainItemPool::sEtciPool = nullptr;
|
|
||||||
int32_t ChainItemPool::sEtciPoolUsers = 0;
|
|
||||||
|
|
||||||
void NS_ShutdownChainItemPool() { ChainItemPool::Shutdown(); }
|
|
||||||
|
|
||||||
nsEventTargetChainItem*
|
nsEventTargetChainItem*
|
||||||
EventTargetChainItemForChromeTarget(ChainItemPool& aPool,
|
EventTargetChainItemForChromeTarget(nsINode* aNode,
|
||||||
nsINode* aNode,
|
|
||||||
nsEventTargetChainItem* aChild = nullptr)
|
nsEventTargetChainItem* aChild = nullptr)
|
||||||
{
|
{
|
||||||
if (!aNode->IsInDoc()) {
|
if (!aNode->IsInDoc()) {
|
||||||
|
@ -451,12 +410,11 @@ EventTargetChainItemForChromeTarget(ChainItemPool& aPool,
|
||||||
NS_ENSURE_TRUE(piTarget, nullptr);
|
NS_ENSURE_TRUE(piTarget, nullptr);
|
||||||
|
|
||||||
nsEventTargetChainItem* etci =
|
nsEventTargetChainItem* etci =
|
||||||
nsEventTargetChainItem::Create(aPool.GetPool(),
|
nsEventTargetChainItem::Create(piTarget->GetTargetForEventTargetChain(),
|
||||||
piTarget->GetTargetForEventTargetChain(),
|
|
||||||
aChild);
|
aChild);
|
||||||
NS_ENSURE_TRUE(etci, nullptr);
|
NS_ENSURE_TRUE(etci, nullptr);
|
||||||
if (!etci->IsValid()) {
|
if (!etci->IsValid()) {
|
||||||
nsEventTargetChainItem::Destroy(aPool.GetPool(), etci);
|
nsEventTargetChainItem::Destroy(etci);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return etci;
|
return etci;
|
||||||
|
@ -551,16 +509,13 @@ nsEventDispatcher::Dispatch(nsISupports* aTarget,
|
||||||
// If we have a PresContext, make sure it doesn't die before
|
// If we have a PresContext, make sure it doesn't die before
|
||||||
// event dispatching is finished.
|
// event dispatching is finished.
|
||||||
nsRefPtr<nsPresContext> kungFuDeathGrip(aPresContext);
|
nsRefPtr<nsPresContext> kungFuDeathGrip(aPresContext);
|
||||||
ChainItemPool pool;
|
|
||||||
NS_ENSURE_TRUE(pool.GetPool(), NS_ERROR_OUT_OF_MEMORY);
|
|
||||||
|
|
||||||
// Create the event target chain item for the event target.
|
// Create the event target chain item for the event target.
|
||||||
nsEventTargetChainItem* targetEtci =
|
nsEventTargetChainItem* targetEtci =
|
||||||
nsEventTargetChainItem::Create(pool.GetPool(),
|
nsEventTargetChainItem::Create(target->GetTargetForEventTargetChain());
|
||||||
target->GetTargetForEventTargetChain());
|
|
||||||
NS_ENSURE_TRUE(targetEtci, NS_ERROR_OUT_OF_MEMORY);
|
NS_ENSURE_TRUE(targetEtci, NS_ERROR_OUT_OF_MEMORY);
|
||||||
if (!targetEtci->IsValid()) {
|
if (!targetEtci->IsValid()) {
|
||||||
nsEventTargetChainItem::Destroy(pool.GetPool(), targetEtci);
|
nsEventTargetChainItem::Destroy(targetEtci);
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -603,8 +558,8 @@ nsEventDispatcher::Dispatch(nsISupports* aTarget,
|
||||||
|
|
||||||
if (!preVisitor.mCanHandle && preVisitor.mAutomaticChromeDispatch && content) {
|
if (!preVisitor.mCanHandle && preVisitor.mAutomaticChromeDispatch && content) {
|
||||||
// Event target couldn't handle the event. Try to propagate to chrome.
|
// Event target couldn't handle the event. Try to propagate to chrome.
|
||||||
nsEventTargetChainItem::Destroy(pool.GetPool(), targetEtci);
|
nsEventTargetChainItem::Destroy(targetEtci);
|
||||||
targetEtci = EventTargetChainItemForChromeTarget(pool, content);
|
targetEtci = EventTargetChainItemForChromeTarget(content);
|
||||||
NS_ENSURE_STATE(targetEtci);
|
NS_ENSURE_STATE(targetEtci);
|
||||||
targetEtci->PreHandleEvent(preVisitor);
|
targetEtci->PreHandleEvent(preVisitor);
|
||||||
}
|
}
|
||||||
|
@ -617,8 +572,7 @@ nsEventDispatcher::Dispatch(nsISupports* aTarget,
|
||||||
while (preVisitor.mParentTarget) {
|
while (preVisitor.mParentTarget) {
|
||||||
nsIDOMEventTarget* parentTarget = preVisitor.mParentTarget;
|
nsIDOMEventTarget* parentTarget = preVisitor.mParentTarget;
|
||||||
nsEventTargetChainItem* parentEtci =
|
nsEventTargetChainItem* parentEtci =
|
||||||
nsEventTargetChainItem::Create(pool.GetPool(), preVisitor.mParentTarget,
|
nsEventTargetChainItem::Create(preVisitor.mParentTarget, topEtci);
|
||||||
topEtci);
|
|
||||||
if (!parentEtci) {
|
if (!parentEtci) {
|
||||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||||
break;
|
break;
|
||||||
|
@ -640,15 +594,14 @@ nsEventDispatcher::Dispatch(nsISupports* aTarget,
|
||||||
if (preVisitor.mCanHandle) {
|
if (preVisitor.mCanHandle) {
|
||||||
topEtci = parentEtci;
|
topEtci = parentEtci;
|
||||||
} else {
|
} else {
|
||||||
nsEventTargetChainItem::Destroy(pool.GetPool(), parentEtci);
|
nsEventTargetChainItem::Destroy(parentEtci);
|
||||||
parentEtci = nullptr;
|
parentEtci = nullptr;
|
||||||
if (preVisitor.mAutomaticChromeDispatch && content) {
|
if (preVisitor.mAutomaticChromeDispatch && content) {
|
||||||
// Even if the current target can't handle the event, try to
|
// Even if the current target can't handle the event, try to
|
||||||
// propagate to chrome.
|
// propagate to chrome.
|
||||||
nsCOMPtr<nsINode> disabledTarget = do_QueryInterface(parentTarget);
|
nsCOMPtr<nsINode> disabledTarget = do_QueryInterface(parentTarget);
|
||||||
if (disabledTarget) {
|
if (disabledTarget) {
|
||||||
parentEtci = EventTargetChainItemForChromeTarget(pool,
|
parentEtci = EventTargetChainItemForChromeTarget(disabledTarget,
|
||||||
disabledTarget,
|
|
||||||
topEtci);
|
topEtci);
|
||||||
if (parentEtci) {
|
if (parentEtci) {
|
||||||
parentEtci->PreHandleEvent(preVisitor);
|
parentEtci->PreHandleEvent(preVisitor);
|
||||||
|
@ -689,7 +642,7 @@ nsEventDispatcher::Dispatch(nsISupports* aTarget,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nsEventTargetChainItem::Destroy(pool.GetPool(), targetEtci);
|
nsEventTargetChainItem::Destroy(targetEtci);
|
||||||
targetEtci = nullptr;
|
targetEtci = nullptr;
|
||||||
|
|
||||||
aEvent->mFlags.mIsBeingDispatched = false;
|
aEvent->mFlags.mIsBeingDispatched = false;
|
||||||
|
|
|
@ -112,7 +112,7 @@ using namespace mozilla::system;
|
||||||
#include "mozilla/dom/time/DateCacheCleaner.h"
|
#include "mozilla/dom/time/DateCacheCleaner.h"
|
||||||
#include "nsIMEStateManager.h"
|
#include "nsIMEStateManager.h"
|
||||||
|
|
||||||
extern void NS_ShutdownChainItemPool();
|
extern void NS_ShutdownEventTargetChainItemRecyclePool();
|
||||||
|
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
using namespace mozilla::dom;
|
using namespace mozilla::dom;
|
||||||
|
@ -368,7 +368,7 @@ nsLayoutStatics::Shutdown()
|
||||||
|
|
||||||
nsRegion::ShutdownStatic();
|
nsRegion::ShutdownStatic();
|
||||||
|
|
||||||
NS_ShutdownChainItemPool();
|
NS_ShutdownEventTargetChainItemRecyclePool();
|
||||||
|
|
||||||
nsFrameList::Shutdown();
|
nsFrameList::Shutdown();
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче