[webkit-dev] Update on memory allocation control proposal...
Paul Pedriana
ppedriana at gmail.com
Wed Jun 18 15:09:33 PDT 2008
I've created a working wtf/New.h file and a basic unit test for it. It
implements both of Maciej's recent proposals, which were essentially 1:
provide an allocation base class and 2: provide a global allocator. I've
done basic testing of this within my WebKit build but haven't converted
every usage of new/malloc to it on my disk. This file wraps both
malloc-based allocation and new-based allocation and implements an
AllocBase class. This version passes everything to FastMalloc and so has
the same behavior as current. I thought I'd post this before doing any
additional work.
This version works via a templated function, which is essentially what a
C++ compiler generates on its own for new/delete. An alternative would
be to use a macro; the benefit would be that the macro could be simply
#defined to be new / delete for default users, and the downside is that
it would be a macro, which I understand is something WebKit likes to
avoid when possible.
I've attached both New.h and NewTest.cpp to this email, but perhaps the
mailing list server will scrub it away, and so here is New.h:
--------------------------------------------------------------------------------
// -*- mode: c++; c-basic-offset: 4 -*-
#ifndef WTF_New_h
#define WTF_New_h
// Provides customizable overrides of Malloc/Free and operator new/delete
//
// Provided functionality:
// class AllocBase{ ... };
//
// void* Malloc(size_t n)
// void* ZeroedMalloc(size_t n)
// void* Calloc(size_t n_elements, size_t element_size)
// void Free(void* p)
// void* Realloc(void* p, size_t n)
//
// T* New<T>();
// T* NewArray<T>(count);
// void Delete(T* p);
// void DeleteArray(T* p);
//
// Example usage:
// class Widget : public AllocBase { ... };
//
// char* pChar = New<char>();
// Delete(pChar);
//
// char* pCharArray = NewArray<char>(37);
// DeleteArray(pCharArray);
//
// void** pVoidPtr = New<void*>();
// Delete(pVoidPtr);
//
// void** pVoidPtrArray = NewArray<void*>(37);
// DeleteArray(pVoidPtrArray);
//
// POD* pPOD = New<POD>();
// Delete(pPOD);
//
// POD* pPODArray = NewArray<POD>(37);
// DeleteArray(pPODArray);
//
// Object* pObject = New<Object>();
// Delete(pObject);
//
// Object* pObjectArray = NewArray<Object>(37);
// DeleteArray(pObjectArray);
//
#include <stdlib.h>
#include <new>
#include <string.h>
#include <stdint.h>
#include <wtf/Assertions.h>
#include <wtf/FastMalloc.h>
// Define type traits that allow us to optimize templated array new/delete.
// These could possibly go into a separate header file if useful.
// Recent versions of GCC's libstdc++ and VC++ have support for type traits.
// To do: Include other compilers/libraries that support type_traits.
#if (defined(__GLIBCXX__) && (__GLIBCXX__ >= 20070724)) ||
(defined(_MSC_VER) && (_MSC_VER >= 1500))
#include <type_traits>
namespace WTF {
using std::has_trivial_constructor;
using std::has_trivial_destructor;
}
#else
namespace WTF {
// This compiler doesn't provide type traits, so we provide a
basic small set.
template <typename T, T v>
struct integral_constant
{
static const T value = v;
typedef T value_type;
typedef integral_constant<T, v> type;
};
typedef integral_constant<bool, true> true_type;
typedef integral_constant<bool, false> false_type;
template <typename T> struct has_trivial_constructor : public
false_type{};
template <typename T> struct has_trivial_destructor : public
false_type{};
// At least handle the case of scalar types.
// Ideally this would include volatile variations as well.
template <typename T> struct has_trivial_constructor<T*> :
public true_type{};
template <typename T> struct has_trivial_destructor<T*> :
public true_type{};
template <> struct
has_trivial_constructor<float> : public true_type{};
template <> struct has_trivial_constructor<const
float> : public true_type{};
template <> struct
has_trivial_constructor<double> : public true_type{};
template <> struct has_trivial_constructor<const
double> : public true_type{};
template <> struct has_trivial_constructor<long
double> : public true_type{};
template <> struct has_trivial_constructor<const long
double> : public true_type{};
template <> struct has_trivial_constructor<unsigned
char> : public true_type{};
template <> struct has_trivial_constructor<const unsigned
char> : public true_type{};
template <> struct has_trivial_constructor<unsigned
short> : public true_type{};
template <> struct has_trivial_constructor<const unsigned
short> : public true_type{};
template <> struct has_trivial_constructor<unsigned
int> : public true_type{};
template <> struct has_trivial_constructor<const unsigned
int> : public true_type{};
template <> struct has_trivial_constructor<unsigned
long> : public true_type{};
template <> struct has_trivial_constructor<const unsigned
long> : public true_type{};
template <> struct has_trivial_constructor<unsigned long
long> : public true_type{};
template <> struct has_trivial_constructor<const unsigned long
long> : public true_type{};
template <> struct has_trivial_constructor<signed
char> : public true_type{};
template <> struct has_trivial_constructor<const signed
char> : public true_type{};
template <> struct has_trivial_constructor<signed
short> : public true_type{};
template <> struct has_trivial_constructor<const signed
short> : public true_type{};
template <> struct has_trivial_constructor<signed
int> : public true_type{};
template <> struct has_trivial_constructor<const signed
int> : public true_type{};
template <> struct has_trivial_constructor<signed
long> : public true_type{};
template <> struct has_trivial_constructor<const signed
long> : public true_type{};
template <> struct has_trivial_constructor<signed long
long> : public true_type{};
template <> struct has_trivial_constructor<const signed long
long> : public true_type{};
template <> struct
has_trivial_constructor<bool> : public true_type{};
template <> struct has_trivial_constructor<const
bool> : public true_type{};
template <> struct
has_trivial_constructor<char> : public true_type{};
template <> struct has_trivial_constructor<const
char> : public true_type{};
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
template <> struct
has_trivial_constructor<wchar_t> : public true_type{};
template <> struct has_trivial_constructor<const
wchar_t> : public true_type{};
#endif
template <> struct
has_trivial_destructor<float> : public true_type{};
template <> struct has_trivial_destructor<const
float> : public true_type{};
template <> struct
has_trivial_destructor<double> : public true_type{};
template <> struct has_trivial_destructor<const
double> : public true_type{};
template <> struct has_trivial_destructor<long
double> : public true_type{};
template <> struct has_trivial_destructor<const long
double> : public true_type{};
template <> struct has_trivial_destructor<unsigned
char> : public true_type{};
template <> struct has_trivial_destructor<const unsigned
char> : public true_type{};
template <> struct has_trivial_destructor<unsigned
short> : public true_type{};
template <> struct has_trivial_destructor<const unsigned
short> : public true_type{};
template <> struct has_trivial_destructor<unsigned
int> : public true_type{};
template <> struct has_trivial_destructor<const unsigned
int> : public true_type{};
template <> struct has_trivial_destructor<unsigned
long> : public true_type{};
template <> struct has_trivial_destructor<const unsigned
long> : public true_type{};
template <> struct has_trivial_destructor<unsigned long
long> : public true_type{};
template <> struct has_trivial_destructor<const unsigned long
long> : public true_type{};
template <> struct has_trivial_destructor<signed
char> : public true_type{};
template <> struct has_trivial_destructor<const signed
char> : public true_type{};
template <> struct has_trivial_destructor<signed
short> : public true_type{};
template <> struct has_trivial_destructor<const signed
short> : public true_type{};
template <> struct has_trivial_destructor<signed
int> : public true_type{};
template <> struct has_trivial_destructor<const signed
int> : public true_type{};
template <> struct has_trivial_destructor<signed
long> : public true_type{};
template <> struct has_trivial_destructor<const signed
long> : public true_type{};
template <> struct has_trivial_destructor<signed long
long> : public true_type{};
template <> struct has_trivial_destructor<const signed long
long> : public true_type{};
template <> struct
has_trivial_destructor<bool> : public true_type{};
template <> struct has_trivial_destructor<const
bool> : public true_type{};
template <> struct
has_trivial_destructor<char> : public true_type{};
template <> struct has_trivial_destructor<const
char> : public true_type{};
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
template <> struct
has_trivial_destructor<wchar_t> : public true_type{};
template <> struct has_trivial_destructor<const
wchar_t> : public true_type{};
#endif
} // namespace WTF
#endif
namespace WTF {
///////////////////////////////////////////////////////////////////////////////
// AllocBase base class
///////////////////////////////////////////////////////////////////////////////
class AllocBase {
public:
void* operator new(size_t size) {
return fastMalloc(size);
}
void operator delete(void* p) {
fastFree(p); // We don't need to check for NULL; the compiler
does this.
}
void* operator new[](size_t size) {
return fastMalloc(size);
}
void operator delete[](void* p) {
fastFree(p); // We don't need to check for NULL; the compiler
does this.
}
};
///////////////////////////////////////////////////////////////////////////////
// Malloc / Free
///////////////////////////////////////////////////////////////////////////////
inline void* Malloc(size_t n) {
return fastMalloc(n);
}
inline void* ZeroedMalloc(size_t n) {
void* const p = fastMalloc(n);
if(p)
memset(p, 0, n);
return p;
}
inline void* Calloc(size_t n_elements, size_t element_size) {
return fastCalloc(n_elements, element_size);
}
inline void Free(void* p) {
fastFree(p);
}
inline void* Realloc(void* p, size_t n) {
return fastRealloc(p, n);
}
///////////////////////////////////////////////////////////////////////////////
// New / Delete
///////////////////////////////////////////////////////////////////////////////
template <typename T>
inline T* New() {
void* p = fastMalloc(sizeof(T));
if(p)
return ::new(p) T;
return NULL;
}
// This is a support template for NewArray.
// This handles the case whereby T has a trivial ctor and a trivial dtor.
template <typename T, bool trivialCtor, bool trivialDtor>
struct NewArrayImpl {
static T* NewArray(size_t count) {
return (T*)fastMalloc(sizeof(T) * count);
}
};
// This is a support template for NewArray.
// This handles the case whereby T has a non-trivial ctor and a trivial
dtor.
template <typename T>
struct NewArrayImpl<T, false, true> {
static T* NewArray(size_t count) {
uint64_t* p = (uint64_t*)fastMalloc(sizeof(uint64_t) +
(sizeof(T) * count));
if(p) {
*p++ = (uint64_t)count;
for(T* pObject = (T*)p, *pObjectEnd = pObject + count;
pObject != pObjectEnd; ++pObject)
::new(pObject) T; // To consider: handle ctor exceptions
if exceptions are enabled by the compiler.
}
return (T*)p;
}
};
// This is a support template for NewArray.
// This handles the case whereby T has a trivial ctor and a non-trivial
dtor.
template <typename T>
struct NewArrayImpl<T, true, false> {
static T* NewArray(size_t count) {
uint64_t* p = (uint64_t*)fastMalloc(sizeof(uint64_t) +
(sizeof(T) * count));
if(p) {
*p++ = (uint64_t)count;
// No need to construct the objects in this case.
}
return (T*)p;
}
};
// This is a support template for NewArray.
// This handles the case whereby T has a non-trivial ctor and a
non-trivial dtor.
template <typename T>
struct NewArrayImpl<T, false, false> {
static T* NewArray(size_t count) {
uint64_t* p = (uint64_t*)fastMalloc(sizeof(uint64_t) +
(sizeof(T) * count));
if(p) {
*p++ = (uint64_t)count;
for(T* pObject = (T*)p, *pObjectEnd = pObject + count;
pObject != pObjectEnd; ++pObject)
::new(pObject) T; // To consider: handle ctor exceptions
if exceptions are enabled by the compiler.
}
return (T*)p;
}
};
template <typename T>
inline T* NewArray(size_t count) {
return NewArrayImpl<T, WTF::has_trivial_constructor<T>::value,
WTF::has_trivial_destructor<T>::value>::NewArray(count);
}
template <typename T>
inline void Delete(T* p) {
if(p) {// As per the C++ standard, test for NULL.
p->~T();
fastFree(p);
}
}
// This is a support template for DeleteArray.
// This handles the case whereby T has a trivial dtor.
template <typename T, bool trivialDtor>
struct DeleteArrayImpl {
static void DeleteArray(void* p) {
if(p) { // As per the C++ standard, test for NULL.
// No need to destruct the objects in this case.
fastFree(p);
}
}
};
// This is a support template for DeleteArray.
// This handles the case whereby T has a non-trivial dtor.
template <typename T>
struct DeleteArrayImpl<T, false> {
static void DeleteArray(T* p) {
if(p) { // As per the C++ standard, test for NULL.
T* pEnd = p + *((uint64_t*)p - 1);
while(pEnd-- != p)
pEnd->~T();
fastFree((void*)((uint64_t*)p - 1));
}
}
};
template <typename T>
void DeleteArray(T* p) {
DeleteArrayImpl<T,
WTF::has_trivial_destructor<T>::value>::DeleteArray(p);
}
} // namespace WTF
#endif // WTF_New_h
--------------------------------------------------------------------------------
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: New.h
Url: http://lists.webkit.org/pipermail/webkit-dev/attachments/20080618/884e8b7f/attachment.pl
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: NewTest.cpp
Url: http://lists.webkit.org/pipermail/webkit-dev/attachments/20080618/884e8b7f/attachment-0001.pl
More information about the webkit-dev
mailing list