[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