ralloc: Hook up C++ destructors to ralloc when necessary.
authorFrancisco Jerez <currojerez@riseup.net>
Wed, 9 Oct 2013 18:02:51 +0000 (11:02 -0700)
committerFrancisco Jerez <currojerez@riseup.net>
Tue, 29 Oct 2013 19:40:55 +0000 (12:40 -0700)
This patch makes sure that class destructors are called as they should
be when a C++ object allocated by ralloc is released.

Based on a previous patch by Kenneth Graunke, but it doesn't exhibit
the ~0.8% performance regression in shader compilation times because
we now use the HAS_TRIVIAL_DESTRUCTOR() macro to detect the typical
case where the indirect function call can be avoided because the
object's destructor doesn't need to do anything.

Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
src/glsl/ralloc.h

index 31682d515e69382dc05f405725e1c5330e87142e..4581a7a4e41e35c1dc904a8464c13f91f40ce068 100644 (file)
@@ -415,15 +415,29 @@ bool ralloc_vasprintf_append(char **str, const char *fmt, va_list args);
  * which is more idiomatic in C++ than calling ralloc.
  */
 #define DECLARE_RALLOC_CXX_OPERATORS(TYPE)                               \
+private:                                                                 \
+   static void _ralloc_destructor(void *p)                               \
+   {                                                                     \
+      reinterpret_cast<TYPE *>(p)->~TYPE();                              \
+   }                                                                     \
+public:                                                                  \
    static void* operator new(size_t size, void *mem_ctx)                 \
    {                                                                     \
       void *p = ralloc_size(mem_ctx, size);                              \
       assert(p != NULL);                                                 \
+      if (!HAS_TRIVIAL_DESTRUCTOR(TYPE))                                 \
+         ralloc_set_destructor(p, _ralloc_destructor);                   \
       return p;                                                          \
    }                                                                     \
                                                                          \
    static void operator delete(void *p)                                  \
    {                                                                     \
+      /* The object's destructor is guaranteed to have already been      \
+       * called by the delete operator at this point -- Make sure it's   \
+       * not called again.                                               \
+       */                                                                \
+      if (!HAS_TRIVIAL_DESTRUCTOR(TYPE))                                 \
+         ralloc_set_destructor(p, NULL);                                 \
       ralloc_free(p);                                                    \
    }