Commit 20c85fe3 authored by mrowe@apple.com's avatar mrowe@apple.com

Prepration for returning memory to the OS on Windows. Track whether a portion...

Prepration for returning memory to the OS on Windows.  Track whether a portion of a span of memory was returned to the OS.
If it was, ask that it be recommitted before returning it to the application as an allocated region.

Reviewed by Oliver Hunt.

* wtf/FastMalloc.cpp:
(WTF::TCMalloc_PageHeap::New):  If the span was decommitted, ask that it be recommitted before returning it.
(WTF::TCMalloc_PageHeap::AllocLarge):  Ditto.
(WTF::TCMalloc_PageHeap::Carve):  When splitting a span, ensure that the decommitted state propogates to the two new spans.
(WTF::TCMalloc_PageHeap::Delete):  When merging a span, ensure that the resulting span is marked as decommitted if any of the
spans being merged were marked as decommitted.
(WTF::TCMalloc_PageHeap::IncrementalScavenge):  Mark as decommitted after releasing the span.
(WTF::TCMalloc_Central_FreeList::FetchFromSpans): Add an assertion to catch a decommitted span being returned to the application
without first being recommitted.
(WTF::TCMalloc_Central_FreeList::Populate): Ditto.
* wtf/TCSystemAlloc.cpp: Stub out TCMalloc_SystemCommit.
* wtf/TCSystemAlloc.h:


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@34756 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 8ace5e01
2008-06-23 Mark Rowe <mrowe@apple.com>
Reviewed by Oliver Hunt.
Prepration for returning memory to the OS on Windows. Track whether a portion of a span of memory was returned to the OS.
If it was, ask that it be recommitted before returning it to the application as an allocated region.
* wtf/FastMalloc.cpp:
(WTF::TCMalloc_PageHeap::New): If the span was decommitted, ask that it be recommitted before returning it.
(WTF::TCMalloc_PageHeap::AllocLarge): Ditto.
(WTF::TCMalloc_PageHeap::Carve): When splitting a span, ensure that the decommitted state propogates to the two new spans.
(WTF::TCMalloc_PageHeap::Delete): When merging a span, ensure that the resulting span is marked as decommitted if any of the
spans being merged were marked as decommitted.
(WTF::TCMalloc_PageHeap::IncrementalScavenge): Mark as decommitted after releasing the span.
(WTF::TCMalloc_Central_FreeList::FetchFromSpans): Add an assertion to catch a decommitted span being returned to the application
without first being recommitted.
(WTF::TCMalloc_Central_FreeList::Populate): Ditto.
* wtf/TCSystemAlloc.cpp: Stub out TCMalloc_SystemCommit.
* wtf/TCSystemAlloc.h:
2008-06-23 Mark Rowe <mrowe@apple.com>
Reviewed by Sam Weinig.
......
......@@ -93,6 +93,8 @@
#define FORCE_SYSTEM_MALLOC 1
#endif
#define TCMALLOC_TRACK_DECOMMITED_SPANS (HAVE(VIRTUALALLOC))
#ifndef NDEBUG
namespace WTF {
......@@ -869,6 +871,7 @@ struct Span {
#endif
unsigned int sizeclass : 8; // Size-class for small objects (or 0)
unsigned int refcount : 11; // Number of non-free objects
bool decommitted : 1;
#undef SPAN_HISTORY
#ifdef SPAN_HISTORY
......@@ -879,6 +882,12 @@ struct Span {
#endif
};
#if TCMALLOC_TRACK_DECOMMITED_SPANS
#define ASSERT_SPAN_COMMITTED(span) ASSERT(!span->decommitted)
#else
#define ASSERT_SPAN_COMMITTED(span)
#endif
#ifdef SPAN_HISTORY
void Event(Span* span, char op, int v = 0) {
span->history[span->nexthistory] = op;
......@@ -1180,13 +1189,22 @@ inline Span* TCMalloc_PageHeap::New(Length n) {
Span* result = ll->next;
Carve(result, n, released);
#if TCMALLOC_TRACK_DECOMMITED_SPANS
if (result->decommitted) {
TCMalloc_SystemCommit(reinterpret_cast<void*>(result->start << kPageShift), static_cast<size_t>(n << kPageShift));
result->decommitted = false;
}
#endif
ASSERT(Check());
free_pages_ -= n;
return result;
}
Span* result = AllocLarge(n);
if (result != NULL) return result;
if (result != NULL) {
ASSERT_SPAN_COMMITTED(result);
return result;
}
// Grow the heap and try again
if (!GrowHeap(n)) {
......@@ -1233,6 +1251,12 @@ Span* TCMalloc_PageHeap::AllocLarge(Length n) {
if (best != NULL) {
Carve(best, n, from_released);
#if TCMALLOC_TRACK_DECOMMITED_SPANS
if (best->decommitted) {
TCMalloc_SystemCommit(reinterpret_cast<void*>(best->start << kPageShift), static_cast<size_t>(n << kPageShift));
best->decommitted = false;
}
#endif
ASSERT(Check());
free_pages_ -= n;
return best;
......@@ -1257,6 +1281,15 @@ Span* TCMalloc_PageHeap::Split(Span* span, Length n) {
return leftover;
}
#if !TCMALLOC_TRACK_DECOMMITED_SPANS
static ALWAYS_INLINE void propagateDecommittedState(Span*, Span*) { }
#else
static ALWAYS_INLINE void propagateDecommittedState(Span* destination, Span* source)
{
destination->decommitted = source->decommitted;
}
#endif
inline void TCMalloc_PageHeap::Carve(Span* span, Length n, bool released) {
ASSERT(n > 0);
DLL_Remove(span);
......@@ -1268,6 +1301,7 @@ inline void TCMalloc_PageHeap::Carve(Span* span, Length n, bool released) {
if (extra > 0) {
Span* leftover = NewSpan(span->start + n, extra);
leftover->free = 1;
propagateDecommittedState(leftover, span);
Event(leftover, 'S', extra);
RecordSpan(leftover);
......@@ -1281,6 +1315,16 @@ inline void TCMalloc_PageHeap::Carve(Span* span, Length n, bool released) {
}
}
#if !TCMALLOC_TRACK_DECOMMITED_SPANS
static ALWAYS_INLINE void mergeDecommittedStates(Span*, Span*) { }
#else
static ALWAYS_INLINE void mergeDecommittedStates(Span* destination, Span* other)
{
if (other->decommitted)
destination->decommitted = true;
}
#endif
inline void TCMalloc_PageHeap::Delete(Span* span) {
ASSERT(Check());
ASSERT(!span->free);
......@@ -1307,6 +1351,7 @@ inline void TCMalloc_PageHeap::Delete(Span* span) {
// Merge preceding span into this span
ASSERT(prev->start + prev->length == p);
const Length len = prev->length;
mergeDecommittedStates(span, prev);
DLL_Remove(prev);
DeleteSpan(prev);
span->start -= len;
......@@ -1319,6 +1364,7 @@ inline void TCMalloc_PageHeap::Delete(Span* span) {
// Merge next span into this span
ASSERT(next->start == p+n);
const Length len = next->length;
mergeDecommittedStates(span, next);
DLL_Remove(next);
DeleteSpan(next);
span->length += len;
......@@ -1359,6 +1405,9 @@ void TCMalloc_PageHeap::IncrementalScavenge(Length n) {
DLL_Remove(s);
TCMalloc_SystemRelease(reinterpret_cast<void*>(s->start << kPageShift),
static_cast<size_t>(s->length << kPageShift));
#if TCMALLOC_TRACK_DECOMMITED_SPANS
s->decommitted = true;
#endif
DLL_Prepend(&slist->returned, s);
scavenge_counter_ = std::max<size_t>(64UL, std::min<size_t>(kDefaultReleaseDelay, kDefaultReleaseDelay - (free_pages_ / kDefaultReleaseDelay)));
......@@ -2099,6 +2148,7 @@ void* TCMalloc_Central_FreeList::FetchFromSpans() {
Span* span = nonempty_.next;
ASSERT(span->objects != NULL);
ASSERT_SPAN_COMMITTED(span);
span->refcount++;
void* result = span->objects;
span->objects = *(reinterpret_cast<void**>(result));
......@@ -2129,6 +2179,7 @@ ALWAYS_INLINE void TCMalloc_Central_FreeList::Populate() {
lock_.Lock();
return;
}
ASSERT_SPAN_COMMITTED(span);
ASSERT(span->length == npages);
// Cache sizeclass info eagerly. Locking is not necessary.
// (Instead of being eager, we could just replace any stale info
......@@ -2905,6 +2956,7 @@ static inline void* CheckedMallocResult(void *result)
}
static inline void* SpanToMallocResult(Span *span) {
ASSERT_SPAN_COMMITTED(span);
pageheap->CacheSizeClass(span->start, 0);
return
CheckedMallocResult(reinterpret_cast<void*>(span->start << kPageShift));
......
......@@ -428,3 +428,11 @@ void TCMalloc_SystemRelease(void* start, size_t length)
return;
#endif
}
#if HAVE(VIRTUALALLOC)
void TCMalloc_SystemCommit(void* start, size_t length)
{
UNUSED_PARAM(start);
UNUSED_PARAM(length);
}
#endif
......@@ -62,4 +62,10 @@ extern void* TCMalloc_SystemAlloc(size_t bytes, size_t *actual_bytes,
// be released, partial pages will not.)
extern void TCMalloc_SystemRelease(void* start, size_t length);
#if HAVE(VIRTUALALLOC)
extern void TCMalloc_SystemCommit(void* start, size_t length);
#else
inline void TCMalloc_SystemCommit(void*, size_t) { }
#endif
#endif /* TCMALLOC_SYSTEM_ALLOC_H__ */
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment