[webkit-dev] WebKit memory management?

Paul Pedriana ppedriana at gmail.com
Wed Jun 4 16:33:54 PDT 2008


I have implemented a version of Maciej's suggestion #2 below, with basic 
documentation and a basic test. A slight alternative would be to change 
the 'new' syntax to to use a macro which would allow for a simpler 
reference version that used global new/delete, but would introduce a 
preprocessor macro. I can also create an example of Maciej's suggestion 
#1, though it will have to wait a few hours while I finish some other work.

------------------------------------------------------------------------

// Customizable overrides of operator new/delete
//
// Provided functionality:
//    T*   wk_new<T>();
//    T*   wk_new_array<T>(count);
//    void wk_delete(T* p);
//    void wk_delete_array(T* p);
//
// Example usage:
//    char* pChar = wk_new<char>();
//    wk_delete(pChar);
//
//    char* pCharArray = wk_new_array<char>(37);
//    wk_delete_array(pCharArray);
//
//    POD* pPOD = wk_new<POD>();
//    wk_delete(pPOD);
//
//    POD* pPODArray = wk_new_array<POD>(37);
//    wk_delete_array(pPODArray);
//
//    Object* pObject = wk_new<Object>();
//    wk_delete(pObject);
//
//    Object* pObjectArray = wk_new_array<Object>(37);
//    wk_delete_array(pObjectArray);
//


template <typename T>
inline T* wk_new()
{
    void* p = malloc(sizeof(T));

    if(p)
        return new(p) T;

    return NULL;
}


// Note that the code below is similar to what the compiler generates 
for built-in array operator new.
// This can be specialized for POD types to avoid the array size prefix 
altogether.
// It can be specialized for types with natural alignment less than 
uint64_t and save 4 bytes on 32 bit systems.
template <typename T>
inline T* wk_new_array(size_t count)
{
    uint64_t* p = (uint64_t*)malloc(sizeof(uint64_t) + (sizeof(T) * count));

    if(p)
    {
        *p++ = (uint64_t)count;

        for(T* pObject = (T*)(void*)p, *pObjectEnd = pObject + count; 
pObject != pObjectEnd; ++pObject)
            new(pObject) T; // To consider: handle ctor exceptions.
    }

    return (T*)(void*)p;
}


// Note that the code below is similar to what the compiler generates 
for built-in array operator new.
template <typename T>
inline void wk_delete(T* p)
{
    if(p) // As per the C++ standard, test for NULL.
    {
        p->~T();
        free(p);
    }
}


// Note that the code below is similar to what the compiler generates 
for built-in array operator delete.
// This can be specialized for POD types to avoid the array size prefix 
altogether.
// It can be specialized for types with natural alignment less than 
uint64_t and save 4 bytes on 32 bit systems.
template <typename T>
void wk_delete_array(T* p)
{
    if(p) // As per the C++ standard, test for NULL.
    {
        T* pEnd = p + *((uint64_t*)p - 1);
        while(pEnd-- != p)
            pEnd->~T();

        free((void*)((uint64_t*)p - 1));
    }
}
------------------------------------------------------------------------



Basic test code:
------------------------------------------------------------------------
struct Object
{
    static int ctorCount;
    static int dtorCount;

    Object() { ++ctorCount; }
    Object(const Object&) { ++ctorCount; }
   ~Object() { ++dtorCount; }
    Object& operator =(const Object&) {  }
};

int Object::ctorCount = 0;
int Object::dtorCount = 0;


struct POD
{
    int x;
};


template <typename T>
void VerifyIsAligned(T* p)
{
    assert((size_t)((((uintptr_t)p ^ ((uintptr_t)p - 1)) >> 1) + 1) >= 
sizeof(T));
}


void DoSomething()
{
    // char
    char* pChar = wk_new<char>();
    wk_delete(pChar);

    char* pCharArray = wk_new_array<char>(37);
    wk_delete_array(pCharArray);

    // double
    double* pDouble = wk_new<double>();
    VerifyIsAligned(pDouble);
    wk_delete(pDouble);

    double* pDoubleArray = wk_new_array<double>(37);
    VerifyIsAligned(pDoubleArray);
    wk_delete_array(pDoubleArray);

    // POD
    POD* pPOD = wk_new<POD>();
    VerifyIsAligned(pPOD);
    wk_delete(pPOD);

    POD* pPODArray = wk_new_array<POD>(37);
    VerifyIsAligned(pPODArray);
    wk_delete_array(pPODArray);

    // Object
    Object* pObject = wk_new<Object>();
    VerifyIsAligned(pObject);
    wk_delete(pObject);

    Object* pObjectArray = wk_new_array<Object>(37);
    VerifyIsAligned(pObjectArray);
    wk_delete_array(pObjectArray);
    assert((Object::ctorCount == 38) && (Object::dtorCount == 38));
}

------------------------------------------------------------------------







>
> On Jun 3, 2008, at 10:58 PM, Paul Pedriana wrote:
>> Thanks for the response. I'm sorry, and perhaps I misunderstand, but 
>> I believe your statement about inline operator new is incorrect. 
>> Unless I misunderstand you, what you say is not supported by any 
>> existing compiler nor is it supported by the C++ language standard. 
>> In summary, the 'inline' keyword does not negate or obviate the One 
>> Definition Rule. You can demonstrate the problem with the code below. 
>> Feel free to correct any misunderstanding that I may have of your 
>> explanation.
>
> This happens to work as intended on Mac OS X because 
> WTF_PRIVATE_INLINE expands to:
>
> __private_extern__ inline __attribute__((always_inline))
>
> This prevents an externally visible definition of global operator new 
> and delete from being seen.
>
> I agree this is technically wrong and I suspect it may cause problems 
> on, for example, Linux platforms. I think the Qt port has turned off 
> FastMalloc for this reason.
>
> I can think of two possible solutions:
>
> 1) Instead of overloading the global operator new and delete, have a 
> FastAllocated base class that overloads the class operator new and 
> delete, and make every class in WebCore and JavaScriptCore inherit 
> from it; for non-class types, avoid using new, delete, new[] or 
> delete[] (perhaps template functions could be provided). The downside 
> is that I can't think of an easy way to then flag mistaken use of 
> new/delete on primitive types, or forgetting to inherit from the 
> FastAllocated base class. Then again, we don't try to flag mistaken 
> use of malloc() instead of fastMalloc() and that has been ok.
>
> 2) Require allocation to happen in some way other than "new" and 
> "delete", for instance always with template functions. Then perhaps we 
> could use #defines to make any actual use of "new" and "delete" an error.
>
> Either of these would be a large change to the source, especially #2 
> (#1 only needs to affect classes with no other subclass and the few 
> places we use new[] on non-class types to make arrays).
>
> Perhaps someone else has a more clever idea.
>
> Regards,
> Maciej
>
>>
>



More information about the webkit-dev mailing list