// Copyright (c) 2005, 2007, Google Inc.
// All rights reserved.
-// Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+// Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
#endif
#endif
-#if !defined(USE_SYSTEM_MALLOC) && defined(NDEBUG)
+#if !(defined(USE_SYSTEM_MALLOC) && USE_SYSTEM_MALLOC) && defined(NDEBUG)
#define FORCE_SYSTEM_MALLOC 0
#else
#define FORCE_SYSTEM_MALLOC 1
#endif
-
// Use a background thread to periodically scavenge memory to release back to the system
// https://bugs.webkit.org/show_bug.cgi?id=27900: don't turn this on for Tiger until we have figured out why it caused a crash.
#define USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY 0
pthread_key_create(&isForbiddenKey, 0);
}
+#if !ASSERT_DISABLED
static bool isForbidden()
{
pthread_once(&isForbiddenKeyOnce, initializeIsForbiddenKey);
return !!pthread_getspecific(isForbiddenKey);
}
+#endif
void fastMallocForbid()
{
memset(result, 0, n);
return result;
}
+
+char* fastStrDup(const char* src)
+{
+ int len = strlen(src) + 1;
+ char* dup = static_cast<char*>(fastMalloc(len));
+
+ if (dup)
+ memcpy(dup, src, len);
+
+ return dup;
+}
-void* tryFastZeroedMalloc(size_t n)
+TryMallocReturnValue tryFastZeroedMalloc(size_t n)
{
- void* result = tryFastMalloc(n);
- if (!result)
+ void* result;
+ if (!tryFastMalloc(n).getValue(result))
return 0;
memset(result, 0, n);
return result;
#if FORCE_SYSTEM_MALLOC
-#include <stdlib.h>
-#if !PLATFORM(WIN_OS)
- #include <pthread.h>
-#else
- #include "windows.h"
-#endif
-
namespace WTF {
-void* tryFastMalloc(size_t n)
+TryMallocReturnValue tryFastMalloc(size_t n)
{
ASSERT(!isForbidden());
ASSERT(!isForbidden());
#if ENABLE(FAST_MALLOC_MATCH_VALIDATION)
- void* result = tryFastMalloc(n);
+ TryMallocReturnValue returnValue = tryFastMalloc(n);
+ void* result;
+ returnValue.getValue(result);
#else
void* result = malloc(n);
#endif
return result;
}
-void* tryFastCalloc(size_t n_elements, size_t element_size)
+TryMallocReturnValue tryFastCalloc(size_t n_elements, size_t element_size)
{
ASSERT(!isForbidden());
ASSERT(!isForbidden());
#if ENABLE(FAST_MALLOC_MATCH_VALIDATION)
- void* result = tryFastCalloc(n_elements, element_size);
+ TryMallocReturnValue returnValue = tryFastCalloc(n_elements, element_size);
+ void* result;
+ returnValue.getValue(result);
#else
void* result = calloc(n_elements, element_size);
#endif
#endif
}
-void* tryFastRealloc(void* p, size_t n)
+TryMallocReturnValue tryFastRealloc(void* p, size_t n)
{
ASSERT(!isForbidden());
ASSERT(!isForbidden());
#if ENABLE(FAST_MALLOC_MATCH_VALIDATION)
- void* result = tryFastRealloc(p, n);
+ TryMallocReturnValue returnValue = tryFastRealloc(p, n);
+ void* result;
+ returnValue.getValue(result);
#else
void* result = realloc(p, n);
#endif
} // namespace WTF
-#if PLATFORM(DARWIN)
+#if OS(DARWIN)
// This symbol is present in the JavaScriptCore exports file even when FastMalloc is disabled.
// It will never be used in this case, so it's type and value are less interesting than its presence.
extern "C" const int jscore_fastmalloc_introspection = 0;
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
+#if OS(UNIX)
+#include <unistd.h>
+#endif
#if COMPILER(MSVC)
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#if WTF_CHANGES
-#if PLATFORM(DARWIN)
+#if OS(DARWIN)
#include "MallocZoneSupport.h"
#include <wtf/HashSet.h>
+#include <wtf/Vector.h>
#endif
+#if HAVE(DISPATCH_H)
+#include <dispatch/dispatch.h>
+#endif
+
#ifndef PRIuS
#define PRIuS "zu"
// call to the function on Mac OS X, and it's used in performance-critical code. So we
// use a function pointer. But that's not necessarily faster on other platforms, and we had
// problems with this technique on Windows, so we'll do this only on Mac OS X.
-#if PLATFORM(DARWIN)
+#if OS(DARWIN)
static void* (*pthread_getspecific_function_pointer)(pthread_key_t) = pthread_getspecific;
#define pthread_getspecific(key) pthread_getspecific_function_pointer(key)
#endif
#define MESSAGE LOG_ERROR
#define CHECK_CONDITION ASSERT
-#if PLATFORM(DARWIN)
+#if OS(DARWIN)
class Span;
class TCMalloc_Central_FreeListPadded;
class TCMalloc_PageHeap;
static const size_t kPageMapBigAllocationThreshold = 128 << 20;
// Minimum number of pages to fetch from system at a time. Must be
-// significantly bigger than kBlockSize to amortize system-call
+// significantly bigger than kPageSize to amortize system-call
// overhead, and also to reduce external fragementation. Also, we
// should keep this value big because various incarnations of Linux
// have small limits on the number of mmap() regions per
int inuse() const { return inuse_; }
-#if defined(WTF_CHANGES) && PLATFORM(DARWIN)
+#if defined(WTF_CHANGES) && OS(DARWIN)
template <class Recorder>
void recordAdministrativeRegions(Recorder& recorder, const RemoteMemoryReader& reader)
{
};
#if defined(WTF_CHANGES)
-#if PLATFORM(X86_64)
+#if CPU(X86_64)
// On all known X86-64 platforms, the upper 16 bits are always unused and therefore
// can be excluded from the PageMap key.
// See http://en.wikipedia.org/wiki/X86-64#Virtual_address_space_details
static const size_t kMinimumFreeCommittedPageCount = 512;
// During a scavenge, we'll release up to a fraction of the free committed pages.
-#if PLATFORM(WIN)
+#if OS(WINDOWS)
// We are slightly less aggressive in releasing memory on Windows due to performance reasons.
static const int kMaxScavengeAmountFactor = 3;
#else
// Index of last free list we scavenged
size_t scavenge_index_;
-#if defined(WTF_CHANGES) && PLATFORM(DARWIN)
+#if defined(WTF_CHANGES) && OS(DARWIN)
friend class FastMallocZone;
#endif
#if USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY
- static NO_RETURN void* runScavengerThread(void*);
+ void initializeScavenger();
+ ALWAYS_INLINE void signalScavenger();
+ void scavenge();
+ ALWAYS_INLINE bool shouldContinueScavenging() const;
+#if !HAVE(DISPATCH_H)
+ static NO_RETURN void* runScavengerThread(void*);
NO_RETURN void scavengerThread();
- void scavenge();
-
- inline bool shouldContinueScavenging() const;
+ // Keeps track of whether the background thread is actively scavenging memory every kScavengeTimerDelayInSeconds, or
+ // it's blocked waiting for more pages to be deleted.
+ bool m_scavengeThreadActive;
pthread_mutex_t m_scavengeMutex;
-
pthread_cond_t m_scavengeCondition;
+#else // !HAVE(DISPATCH_H)
+ void periodicScavenge();
+
+ dispatch_queue_t m_scavengeQueue;
+ dispatch_source_t m_scavengeTimer;
+ bool m_scavengingScheduled;
+#endif
- // Keeps track of whether the background thread is actively scavenging memory every kScavengeTimerDelayInSeconds, or
- // it's blocked waiting for more pages to be deleted.
- bool m_scavengeThreadActive;
#endif // USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY
};
}
#if USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY
+ initializeScavenger();
+#endif // USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY
+}
+
+#if USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY
+
+#if !HAVE(DISPATCH_H)
+
+void TCMalloc_PageHeap::initializeScavenger()
+{
pthread_mutex_init(&m_scavengeMutex, 0);
pthread_cond_init(&m_scavengeCondition, 0);
m_scavengeThreadActive = true;
pthread_t thread;
pthread_create(&thread, 0, runScavengerThread, this);
-#endif // USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY
}
-#if USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY
void* TCMalloc_PageHeap::runScavengerThread(void* context)
{
static_cast<TCMalloc_PageHeap*>(context)->scavengerThread();
#endif
}
+ALWAYS_INLINE void TCMalloc_PageHeap::signalScavenger()
+{
+ if (!m_scavengeThreadActive && shouldContinueScavenging())
+ pthread_cond_signal(&m_scavengeCondition);
+}
+
+#else // !HAVE(DISPATCH_H)
+
+void TCMalloc_PageHeap::initializeScavenger()
+{
+ m_scavengeQueue = dispatch_queue_create("com.apple.JavaScriptCore.FastMallocSavenger", NULL);
+ m_scavengeTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, m_scavengeQueue);
+ dispatch_time_t startTime = dispatch_time(DISPATCH_TIME_NOW, kScavengeTimerDelayInSeconds * NSEC_PER_SEC);
+ dispatch_source_set_timer(m_scavengeTimer, startTime, kScavengeTimerDelayInSeconds * NSEC_PER_SEC, 1000 * NSEC_PER_USEC);
+ dispatch_source_set_event_handler(m_scavengeTimer, ^{ periodicScavenge(); });
+ m_scavengingScheduled = false;
+}
+
+ALWAYS_INLINE void TCMalloc_PageHeap::signalScavenger()
+{
+ if (!m_scavengingScheduled && shouldContinueScavenging()) {
+ m_scavengingScheduled = true;
+ dispatch_resume(m_scavengeTimer);
+ }
+}
+
+#endif
+
void TCMalloc_PageHeap::scavenge()
{
// If we have to commit memory in the last 5 seconds, it means we don't have enough free committed pages
free_committed_pages_ -= pagesDecommitted;
}
-inline bool TCMalloc_PageHeap::shouldContinueScavenging() const
+ALWAYS_INLINE bool TCMalloc_PageHeap::shouldContinueScavenging() const
{
return free_committed_pages_ > kMinimumFreeCommittedPageCount;
}
}
// Make sure the scavenge thread becomes active if we have enough freed pages to release some back to the system.
- if (!m_scavengeThreadActive && shouldContinueScavenging())
- pthread_cond_signal(&m_scavengeCondition);
+ signalScavenger();
#else
IncrementalScavenge(n);
#endif
#define pageheap getPageHeap()
#if USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY
-#if PLATFORM(WIN)
+
+#if !HAVE(DISPATCH_H)
+#if OS(WINDOWS)
static void sleep(unsigned seconds)
{
::Sleep(seconds * 1000);
}
}
}
+
+#else
+
+void TCMalloc_PageHeap::periodicScavenge()
+{
+ {
+ SpinLockHolder h(&pageheap_lock);
+ pageheap->scavenge();
+ }
+
+ if (!shouldContinueScavenging()) {
+ m_scavengingScheduled = false;
+ dispatch_suspend(m_scavengeTimer);
+ }
+}
+#endif // HAVE(DISPATCH_H)
+
#endif
// If TLS is available, we also store a copy
// The following check is expensive, so it is disabled by default
if (false) {
// Check that object does not occur in list
- int got = 0;
+ unsigned got = 0;
for (void* p = span->objects; p != NULL; p = *((void**) p)) {
ASSERT(p != object);
got++;
}
pageheap->init();
phinited = 1;
-#if defined(WTF_CHANGES) && PLATFORM(DARWIN)
+#if defined(WTF_CHANGES) && OS(DARWIN)
FastMallocZone::init();
#endif
}
return malloc<true>(size);
}
-void* tryFastMalloc(size_t size)
+TryMallocReturnValue tryFastMalloc(size_t size)
{
return malloc<false>(size);
}
return calloc<true>(n, elem_size);
}
-void* tryFastCalloc(size_t n, size_t elem_size)
+TryMallocReturnValue tryFastCalloc(size_t n, size_t elem_size)
{
return calloc<false>(n, elem_size);
}
return realloc<true>(old_ptr, new_size);
}
-void* tryFastRealloc(void* old_ptr, size_t new_size)
+TryMallocReturnValue tryFastRealloc(void* old_ptr, size_t new_size)
{
return realloc<false>(old_ptr, new_size);
}
return new_ptr;
} else {
#if ENABLE(FAST_MALLOC_MATCH_VALIDATION)
- old_ptr = pByte + sizeof(AllocAlignmentInteger); // Set old_ptr back to the user pointer.
+ old_ptr = static_cast<AllocAlignmentInteger*>(old_ptr) + 1; // Set old_ptr back to the user pointer.
#endif
return old_ptr;
}
#endif
-#if defined(WTF_CHANGES) && PLATFORM(DARWIN)
+#if defined(WTF_CHANGES) && OS(DARWIN)
class FreeObjectFinder {
const RemoteMemoryReader& m_reader;
malloc_introspection_t jscore_fastmalloc_introspection = { &FastMallocZone::enumerate, &FastMallocZone::goodSize, &FastMallocZone::check, &FastMallocZone::print,
&FastMallocZone::log, &FastMallocZone::forceLock, &FastMallocZone::forceUnlock, &FastMallocZone::statistics
-#if !PLATFORM(IPHONE_SIMULATOR)
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) || PLATFORM(IPHONE)
, 0 // zone_locked will not be called on the zone unless it advertises itself as version five or higher.
#endif
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) && !OS(IPHONE_OS)
+ , 0, 0, 0, 0 // These members will not be used unless the zone advertises itself as version seven or higher.
+#endif
};
}