Bug 497495 (frame poisoning) part 2: Introduce nsIPresShell::AllocateMisc/FreeMisc functions; add an as-yet-unused "code" parameter to AllocateFrame/FreeFrame; fix up nsFrame to match; use AllocateMisc/FreeMisc for all non-frame pres arena objects; move clearing of frame objects from nsFrame::operator new to AllocateFrame. r=roc sr=dbaron

This commit is contained in:
Zack Weinberg
2009-08-17 20:21:06 -07:00
parent 4c412996ad
commit 1bc6a7615f
7 changed files with 84 additions and 53 deletions

View File

@@ -104,9 +104,10 @@ class nsDisplayListBuilder;
typedef short SelectionType;
typedef PRUint32 nsFrameState;
#define NS_IPRESSHELL_IID \
{ 0xfea81c36, 0xed5b, 0x41f5, \
{ 0x89, 0x5d, 0x4c, 0x50, 0x79, 0x49, 0xad, 0x3b } }
// eba51d41-68db-4dab-a57b-dc1a2704de87
#define NS_IPRESSHELL_IID \
{ 0xeba51d41, 0x68db, 0x4dab, \
{ 0xa5, 0x7b, 0xdc, 0x1a, 0x27, 0x04, 0xde, 0x87 } }
// Constants for ScrollContentIntoView() function
#define NS_PRESSHELL_SCROLL_TOP 0
@@ -169,11 +170,19 @@ public:
PRBool IsDestroying() { return mIsDestroying; }
// All frames owned by the shell are allocated from an arena. They are also recycled
// using free lists (separate free lists being maintained for each size_t).
// Methods for recycling frames.
virtual void* AllocateFrame(size_t aSize) = 0;
virtual void FreeFrame(size_t aSize, void* aFreeChunk) = 0;
// All frames owned by the shell are allocated from an arena. They
// are also recycled using free lists. Separate free lists are
// maintained for each combination of aSize and aCode. AllocateFrame
// clears the memory that it returns.
virtual void* AllocateFrame(size_t aSize, unsigned int aCode) = 0;
virtual void FreeFrame(size_t aSize, unsigned int aCode, void* aChunk) = 0;
// Objects closely related to the frame tree, but that are not
// actual frames (subclasses of nsFrame) are also allocated from the
// arena, and recycled via a separate set of per-size free lists.
// AllocateMisc does *not* clear the memory that it returns.
virtual void* AllocateMisc(size_t aSize) = 0;
virtual void FreeMisc(size_t aSize, void* aChunk) = 0;
/**
* Stack memory allocation:

View File

@@ -280,7 +280,7 @@ public:
void* AllocateFromShell(size_t aSize)
{
if (mShell)
return mShell->AllocateFrame(aSize);
return mShell->AllocateMisc(aSize);
return nsnull;
}
@@ -288,7 +288,7 @@ public:
{
NS_ASSERTION(mShell, "freeing after shutdown");
if (mShell)
mShell->FreeFrame(aSize, aFreeChunk);
mShell->FreeMisc(aSize, aFreeChunk);
}
/**

View File

@@ -659,8 +659,12 @@ public:
nsCompatibility aCompatMode);
NS_IMETHOD Destroy();
virtual NS_HIDDEN_(void*) AllocateFrame(size_t aSize);
virtual NS_HIDDEN_(void) FreeFrame(size_t aSize, void* aFreeChunk);
virtual NS_HIDDEN_(void*) AllocateFrame(size_t aSize, unsigned int aCode);
virtual NS_HIDDEN_(void) FreeFrame(size_t aSize, unsigned int aCode,
void* aChunk);
virtual NS_HIDDEN_(void*) AllocateMisc(size_t aSize);
virtual NS_HIDDEN_(void) FreeMisc(size_t aSize, void* aChunk);
// Dynamic stack memory allocation
virtual NS_HIDDEN_(void) PushStackMemory();
@@ -1967,13 +1971,30 @@ PresShell::AllocateStackMemory(size_t aSize)
}
void
PresShell::FreeFrame(size_t aSize, void* aPtr)
PresShell::FreeFrame(size_t aSize, unsigned int /*unused*/, void* aPtr)
{
mFrameArena.Free(aSize, aPtr);
}
void*
PresShell::AllocateFrame(size_t aSize)
PresShell::AllocateFrame(size_t aSize, unsigned int /*unused*/)
{
void* result = mFrameArena.Allocate(aSize);
if (result) {
memset(result, 0, aSize);
}
return result;
}
void
PresShell::FreeMisc(size_t aSize, void* aPtr)
{
mFrameArena.Free(aSize, aPtr);
}
void*
PresShell::AllocateMisc(size_t aSize)
{
return mFrameArena.Allocate(aSize);
}
@@ -4581,7 +4602,7 @@ PresShell::IsThemeSupportEnabled()
NS_IMETHODIMP
PresShell::PostReflowCallback(nsIReflowCallback* aCallback)
{
void* result = AllocateFrame(sizeof(nsCallbackEventRequest));
void* result = AllocateMisc(sizeof(nsCallbackEventRequest));
if (NS_UNLIKELY(!result)) {
return NS_ERROR_OUT_OF_MEMORY;
}
@@ -4625,7 +4646,7 @@ PresShell::CancelReflowCallback(nsIReflowCallback* aCallback)
mLastCallbackEventRequest = before;
}
FreeFrame(sizeof(nsCallbackEventRequest), toFree);
FreeMisc(sizeof(nsCallbackEventRequest), toFree);
} else {
before = node;
node = node->next;
@@ -4645,7 +4666,7 @@ PresShell::CancelPostedReflowCallbacks()
mLastCallbackEventRequest = nsnull;
}
nsIReflowCallback* callback = node->callback;
FreeFrame(sizeof(nsCallbackEventRequest), node);
FreeMisc(sizeof(nsCallbackEventRequest), node);
if (callback) {
callback->ReflowCallbackCanceled();
}
@@ -4664,7 +4685,7 @@ PresShell::HandlePostedReflowCallbacks(PRBool aInterruptible)
mLastCallbackEventRequest = nsnull;
}
nsIReflowCallback* callback = node->callback;
FreeFrame(sizeof(nsCallbackEventRequest), node);
FreeMisc(sizeof(nsCallbackEventRequest), node);
if (callback) {
if (callback->ReflowFinished()) {
shouldFlush = PR_TRUE;

View File

@@ -55,14 +55,14 @@ void* nsFloatManager::sCachedFloatManagers[NS_FLOAT_MANAGER_CACHE_SIZE];
static void*
PSArenaAllocCB(size_t aSize, void* aClosure)
{
return static_cast<nsIPresShell*>(aClosure)->AllocateFrame(aSize);
return static_cast<nsIPresShell*>(aClosure)->AllocateMisc(aSize);
}
// PresShell Arena free callback (for nsIntervalSet use below)
static void
PSArenaFreeCB(size_t aSize, void* aPtr, void* aClosure)
{
static_cast<nsIPresShell*>(aClosure)->FreeFrame(aSize, aPtr);
static_cast<nsIPresShell*>(aClosure)->FreeMisc(aSize, aPtr);
}
/////////////////////////////////////////////////////////////////////////////

View File

@@ -290,24 +290,17 @@ NS_NewEmptyFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
return new (aPresShell) nsFrame(aContext);
}
// Overloaded new operator. Initializes the memory to 0 and relies on an arena
// (which comes from the presShell) to perform the allocation.
void*
// Overloaded new operator. Relies on an arena (which comes from the
// presShell) to perform the allocation.
void*
nsFrame::operator new(size_t sz, nsIPresShell* aPresShell) CPP_THROW_NEW
{
// Check the recycle list first.
void* result = aPresShell->AllocateFrame(sz);
if (result) {
memset(result, 0, sz);
}
return result;
return aPresShell->AllocateFrame(sz, 0 /* dummy */);
}
// Overridden to prevent the global delete from being called, since the memory
// came out of an nsIArena instead of the global delete operator's heap.
void
void
nsFrame::operator delete(void* aPtr, size_t sz)
{
// Don't let the memory be freed, since it will be recycled
@@ -477,7 +470,7 @@ nsFrame::Destroy()
if (view) {
// Break association between view and frame
view->SetClientData(nsnull);
// Destroy the view
view->Destroy();
}
@@ -489,7 +482,7 @@ nsFrame::Destroy()
// Now that we're totally cleaned out, we need to add ourselves to the presshell's
// recycler.
size_t* sz = (size_t*)this;
shell->FreeFrame(*sz, (void*)this);
shell->FreeFrame(*sz, 0 /* dummy */, (void*)this);
}
NS_IMETHODIMP

View File

@@ -134,25 +134,29 @@ public:
* Create a new "empty" frame that maps a given piece of content into a
* 0,0 area.
*/
friend nsIFrame* NS_NewEmptyFrame(nsIPresShell* aShell, nsStyleContext* aContext);
friend nsIFrame* NS_NewEmptyFrame(nsIPresShell* aShell,
nsStyleContext* aContext);
// Overloaded new operator. Initializes the memory to 0 and relies on an arena
// (which comes from the presShell) to perform the allocation.
// Overloaded new operator. Relies on an arena (which comes from the
// presShell) to perform the allocation.
void* operator new(size_t sz, nsIPresShell* aPresShell) CPP_THROW_NEW;
// Overridden to prevent the global delete from being called, since the memory
// came out of an arena instead of the global delete operator's heap.
// XXX Would like to make this private some day, but our UNIX compilers can't
// deal with it.
void operator delete(void* aPtr, size_t sz);
// We compute and store the HTML content's overflow area. So don't
// try to compute it in the box code.
virtual PRBool ComputesOwnOverflowArea() { return PR_TRUE; }
private:
// The normal operator new is disallowed on nsFrames.
void* operator new(size_t sz) CPP_THROW_NEW { return nsnull; }
// Left undefined; nsFrame objects are never allocated from the heap.
void* operator new(size_t sz) CPP_THROW_NEW;
protected:
// Overridden to prevent the global delete from being called, since
// the memory came out of an arena instead of the heap.
//
// Ideally this would be private and undefined, like the normal
// operator new. Unfortunately, the C++ standard requires an
// overridden operator delete to be accessible to any subclass that
// defines a virtual destructor, so we can only make it protected;
// worse, some C++ compilers will synthesize calls to this function
// from the "deleting destructors" that they emit in case of
// delete-expressions, so it can't even be undefined.
void operator delete(void* aPtr, size_t sz);
public:
@@ -371,6 +375,10 @@ public:
virtual nscoord GetFlex(nsBoxLayoutState& aBoxLayoutState);
virtual nscoord GetBoxAscent(nsBoxLayoutState& aBoxLayoutState);
// We compute and store the HTML content's overflow area. So don't
// try to compute it in the box code.
virtual PRBool ComputesOwnOverflowArea() { return PR_TRUE; }
//--------------------------------------------------
// Additional methods

View File

@@ -96,15 +96,15 @@ NS_NewLineBox(nsIPresShell* aPresShell, nsIFrame* aFrame,
// Overloaded new operator. Uses an arena (which comes from the presShell)
// to perform the allocation.
void*
void*
nsLineBox::operator new(size_t sz, nsIPresShell* aPresShell) CPP_THROW_NEW
{
return aPresShell->AllocateFrame(sz);
return aPresShell->AllocateMisc(sz);
}
// Overloaded delete operator. Doesn't actually free the memory, because we
// use an arena
void
void
nsLineBox::operator delete(void* aPtr, size_t sz)
{
}
@@ -116,7 +116,7 @@ nsLineBox::Destroy(nsIPresShell* aPresShell)
delete this;
// Have the pres shell recycle the memory
aPresShell->FreeFrame(sizeof(*this), (void*)this);
aPresShell->FreeMisc(sizeof(*this), (void*)this);
}
void