mirror of
https://github.com/darlinghq/darling-WTF.git
synced 2024-11-23 11:59:47 +00:00
368 lines
8.4 KiB
C++
368 lines
8.4 KiB
C++
/*
|
|
* Copyright (c) 2005, 2007, Google Inc. All rights reserved.
|
|
* Copyright (C) 2005-2009, 2011, 2015-2016 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 met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include "FastMalloc.h"
|
|
|
|
#include "CheckedArithmetic.h"
|
|
#include "CurrentTime.h"
|
|
#include <limits>
|
|
#include <string.h>
|
|
#include <wtf/DataLog.h>
|
|
|
|
#if OS(WINDOWS)
|
|
#include <windows.h>
|
|
#else
|
|
#include <pthread.h>
|
|
#include <sys/resource.h>
|
|
#endif
|
|
|
|
#if OS(DARWIN)
|
|
#include <mach/mach_init.h>
|
|
#include <malloc/malloc.h>
|
|
#endif
|
|
|
|
namespace WTF {
|
|
|
|
#if !defined(NDEBUG)
|
|
namespace {
|
|
// We do not use std::numeric_limits<size_t>::max() here due to the edge case in VC++.
|
|
// https://bugs.webkit.org/show_bug.cgi?id=173720
|
|
static size_t maxSingleAllocationSize = SIZE_MAX;
|
|
};
|
|
|
|
void fastSetMaxSingleAllocationSize(size_t size)
|
|
{
|
|
maxSingleAllocationSize = size;
|
|
}
|
|
|
|
#define ASSERT_IS_WITHIN_LIMIT(size) do { \
|
|
size_t size__ = (size); \
|
|
ASSERT_WITH_MESSAGE((size__) <= maxSingleAllocationSize, "Requested size (%zu) exceeds max single allocation size set for testing (%zu)", (size__), maxSingleAllocationSize); \
|
|
} while (false)
|
|
|
|
#define FAIL_IF_EXCEEDS_LIMIT(size) do { \
|
|
if (UNLIKELY((size) > maxSingleAllocationSize)) \
|
|
return nullptr; \
|
|
} while (false)
|
|
|
|
#else // !defined(NDEBUG)
|
|
|
|
#define ASSERT_IS_WITHIN_LIMIT(size)
|
|
#define FAIL_IF_EXCEEDS_LIMIT(size)
|
|
|
|
#endif // !defined(NDEBUG)
|
|
|
|
void* fastZeroedMalloc(size_t n)
|
|
{
|
|
void* result = fastMalloc(n);
|
|
memset(result, 0, n);
|
|
return result;
|
|
}
|
|
|
|
char* fastStrDup(const char* src)
|
|
{
|
|
size_t len = strlen(src) + 1;
|
|
char* dup = static_cast<char*>(fastMalloc(len));
|
|
memcpy(dup, src, len);
|
|
return dup;
|
|
}
|
|
|
|
TryMallocReturnValue tryFastZeroedMalloc(size_t n)
|
|
{
|
|
void* result;
|
|
if (!tryFastMalloc(n).getValue(result))
|
|
return 0;
|
|
memset(result, 0, n);
|
|
return result;
|
|
}
|
|
|
|
} // namespace WTF
|
|
|
|
#if defined(USE_SYSTEM_MALLOC) && USE_SYSTEM_MALLOC
|
|
|
|
#if OS(WINDOWS)
|
|
#include <malloc.h>
|
|
#endif
|
|
|
|
namespace WTF {
|
|
|
|
bool isFastMallocEnabled()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
size_t fastMallocGoodSize(size_t bytes)
|
|
{
|
|
#if OS(DARWIN)
|
|
return malloc_good_size(bytes);
|
|
#else
|
|
return bytes;
|
|
#endif
|
|
}
|
|
|
|
#if OS(WINDOWS)
|
|
|
|
void* fastAlignedMalloc(size_t alignment, size_t size)
|
|
{
|
|
ASSERT_IS_WITHIN_LIMIT(size);
|
|
void* p = _aligned_malloc(size, alignment);
|
|
if (UNLIKELY(!p))
|
|
CRASH();
|
|
return p;
|
|
}
|
|
|
|
void* tryFastAlignedMalloc(size_t alignment, size_t size)
|
|
{
|
|
FAIL_IF_EXCEEDS_LIMIT(size);
|
|
return _aligned_malloc(size, alignment);
|
|
}
|
|
|
|
void fastAlignedFree(void* p)
|
|
{
|
|
_aligned_free(p);
|
|
}
|
|
|
|
#else
|
|
|
|
void* fastAlignedMalloc(size_t alignment, size_t size)
|
|
{
|
|
ASSERT_IS_WITHIN_LIMIT(size);
|
|
void* p = nullptr;
|
|
posix_memalign(&p, alignment, size);
|
|
if (UNLIKELY(!p))
|
|
CRASH();
|
|
return p;
|
|
}
|
|
|
|
void* tryFastAlignedMalloc(size_t alignment, size_t size)
|
|
{
|
|
FAIL_IF_EXCEEDS_LIMIT(size);
|
|
void* p = nullptr;
|
|
posix_memalign(&p, alignment, size);
|
|
return p;
|
|
}
|
|
|
|
void fastAlignedFree(void* p)
|
|
{
|
|
free(p);
|
|
}
|
|
|
|
#endif // OS(WINDOWS)
|
|
|
|
TryMallocReturnValue tryFastMalloc(size_t n)
|
|
{
|
|
FAIL_IF_EXCEEDS_LIMIT(n);
|
|
return malloc(n);
|
|
}
|
|
|
|
void* fastMalloc(size_t n)
|
|
{
|
|
ASSERT_IS_WITHIN_LIMIT(n);
|
|
void* result = malloc(n);
|
|
if (!result)
|
|
CRASH();
|
|
|
|
return result;
|
|
}
|
|
|
|
TryMallocReturnValue tryFastCalloc(size_t n_elements, size_t element_size)
|
|
{
|
|
FAIL_IF_EXCEEDS_LIMIT(n_elements * element_size);
|
|
return calloc(n_elements, element_size);
|
|
}
|
|
|
|
void* fastCalloc(size_t n_elements, size_t element_size)
|
|
{
|
|
ASSERT_IS_WITHIN_LIMIT(n_elements * element_size);
|
|
void* result = calloc(n_elements, element_size);
|
|
if (!result)
|
|
CRASH();
|
|
|
|
return result;
|
|
}
|
|
|
|
void fastFree(void* p)
|
|
{
|
|
free(p);
|
|
}
|
|
|
|
void* fastRealloc(void* p, size_t n)
|
|
{
|
|
ASSERT_IS_WITHIN_LIMIT(n);
|
|
void* result = realloc(p, n);
|
|
if (!result)
|
|
CRASH();
|
|
return result;
|
|
}
|
|
|
|
void releaseFastMallocFreeMemory() { }
|
|
void releaseFastMallocFreeMemoryForThisThread() { }
|
|
|
|
FastMallocStatistics fastMallocStatistics()
|
|
{
|
|
FastMallocStatistics statistics = { 0, 0, 0 };
|
|
return statistics;
|
|
}
|
|
|
|
size_t fastMallocSize(const void* p)
|
|
{
|
|
#if OS(DARWIN)
|
|
return malloc_size(p);
|
|
#elif OS(WINDOWS)
|
|
return _msize(const_cast<void*>(p));
|
|
#else
|
|
UNUSED_PARAM(p);
|
|
return 1;
|
|
#endif
|
|
}
|
|
|
|
} // namespace WTF
|
|
|
|
#else // defined(USE_SYSTEM_MALLOC) && USE_SYSTEM_MALLOC
|
|
|
|
#include <bmalloc/bmalloc.h>
|
|
|
|
namespace WTF {
|
|
|
|
bool isFastMallocEnabled()
|
|
{
|
|
return bmalloc::api::isEnabled();
|
|
}
|
|
|
|
void* fastMalloc(size_t size)
|
|
{
|
|
ASSERT_IS_WITHIN_LIMIT(size);
|
|
return bmalloc::api::malloc(size);
|
|
}
|
|
|
|
void* fastCalloc(size_t numElements, size_t elementSize)
|
|
{
|
|
ASSERT_IS_WITHIN_LIMIT(numElements * elementSize);
|
|
Checked<size_t> checkedSize = elementSize;
|
|
checkedSize *= numElements;
|
|
void* result = fastZeroedMalloc(checkedSize.unsafeGet());
|
|
if (!result)
|
|
CRASH();
|
|
return result;
|
|
}
|
|
|
|
void* fastRealloc(void* object, size_t size)
|
|
{
|
|
ASSERT_IS_WITHIN_LIMIT(size);
|
|
return bmalloc::api::realloc(object, size);
|
|
}
|
|
|
|
void fastFree(void* object)
|
|
{
|
|
bmalloc::api::free(object);
|
|
}
|
|
|
|
size_t fastMallocSize(const void*)
|
|
{
|
|
// FIXME: This is incorrect; best fix is probably to remove this function.
|
|
// Caller currently are all using this for assertion, not to actually check
|
|
// the size of the allocation, so maybe we can come up with something for that.
|
|
return 1;
|
|
}
|
|
|
|
size_t fastMallocGoodSize(size_t size)
|
|
{
|
|
return size;
|
|
}
|
|
|
|
void* fastAlignedMalloc(size_t alignment, size_t size)
|
|
{
|
|
ASSERT_IS_WITHIN_LIMIT(size);
|
|
return bmalloc::api::memalign(alignment, size);
|
|
}
|
|
|
|
void* tryFastAlignedMalloc(size_t alignment, size_t size)
|
|
{
|
|
FAIL_IF_EXCEEDS_LIMIT(size);
|
|
return bmalloc::api::tryMemalign(alignment, size);
|
|
}
|
|
|
|
void fastAlignedFree(void* p)
|
|
{
|
|
bmalloc::api::free(p);
|
|
}
|
|
|
|
TryMallocReturnValue tryFastMalloc(size_t size)
|
|
{
|
|
FAIL_IF_EXCEEDS_LIMIT(size);
|
|
return bmalloc::api::tryMalloc(size);
|
|
}
|
|
|
|
TryMallocReturnValue tryFastCalloc(size_t numElements, size_t elementSize)
|
|
{
|
|
FAIL_IF_EXCEEDS_LIMIT(numElements * elementSize);
|
|
Checked<size_t, RecordOverflow> checkedSize = elementSize;
|
|
checkedSize *= numElements;
|
|
if (checkedSize.hasOverflowed())
|
|
return nullptr;
|
|
return tryFastZeroedMalloc(checkedSize.unsafeGet());
|
|
}
|
|
|
|
void releaseFastMallocFreeMemoryForThisThread()
|
|
{
|
|
bmalloc::api::scavengeThisThread();
|
|
}
|
|
|
|
void releaseFastMallocFreeMemory()
|
|
{
|
|
bmalloc::api::scavenge();
|
|
}
|
|
|
|
FastMallocStatistics fastMallocStatistics()
|
|
{
|
|
|
|
// FIXME: Can bmalloc itself report the stats instead of relying on the OS?
|
|
FastMallocStatistics statistics;
|
|
statistics.freeListBytes = 0;
|
|
statistics.reservedVMBytes = 0;
|
|
|
|
#if OS(WINDOWS)
|
|
PROCESS_MEMORY_COUNTERS resourceUsage;
|
|
GetProcessMemoryInfo(GetCurrentProcess(), &resourceUsage, sizeof(resourceUsage));
|
|
statistics.committedVMBytes = resourceUsage.PeakWorkingSetSize;
|
|
#else
|
|
struct rusage resourceUsage;
|
|
getrusage(RUSAGE_SELF, &resourceUsage);
|
|
|
|
#if OS(DARWIN)
|
|
statistics.committedVMBytes = resourceUsage.ru_maxrss;
|
|
#else
|
|
statistics.committedVMBytes = resourceUsage.ru_maxrss * 1024;
|
|
#endif // OS(DARWIN)
|
|
|
|
#endif // OS(WINDOWS)
|
|
return statistics;
|
|
}
|
|
|
|
} // namespace WTF
|
|
|
|
#endif // defined(USE_SYSTEM_MALLOC) && USE_SYSTEM_MALLOC
|