<div dir="ltr">On 15 September 2013 00:10, Francisco Jerez <span dir="ltr"><<a href="mailto:currojerez@riseup.net" target="_blank">currojerez@riseup.net</a>></span> wrote:<br><div class="gmail_extra"><div class="gmail_quote">
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">This patch introduces a pair of helper functions providing a common<br>
implementation of the "new" and "delete" operators for all C++ classes<br>
that are allocated by ralloc via placement new. The 'ralloc_new'<br>
helper function takes care of setting up an ralloc destructor callback<br>
that will call the appropriate destructor before the memory allocated<br>
to an object is released.<br>
<br>
Until now objects needed to call 'ralloc_set_destructor' explicitly<br>
with a pointer to a static method which in turn called the actual<br>
destructor in order to get something that should be transparent to<br>
them. After this patch they'll only need to call 'ralloc_new' from<br>
the new operator and 'ralloc_delete' from the delete operator, turning<br>
all overloads of new and delete into one-liners.<br>
---<br>
src/glsl/ast.h | 26 +++----------<br>
src/glsl/glsl_parser_extras.h | 9 +----<br>
src/glsl/glsl_symbol_table.cpp | 7 +---<br>
src/glsl/glsl_symbol_table.h | 23 +----------<br>
src/glsl/glsl_types.h | 11 +-----<br>
src/glsl/ir_function_detect_recursion.cpp | 11 +-----<br>
src/glsl/list.h | 22 ++---------<br>
src/glsl/loop_analysis.h | 14 +------<br>
src/glsl/ralloc.h | 44 ++++++++++++++++++++++<br>
src/mesa/drivers/dri/i965/brw_cfg.h | 14 +------<br>
src/mesa/drivers/dri/i965/brw_fs.h | 21 ++---------<br>
src/mesa/drivers/dri/i965/brw_fs_live_variables.h | 7 +---<br>
src/mesa/drivers/dri/i965/brw_vec4.h | 21 ++---------<br>
.../drivers/dri/i965/brw_vec4_live_variables.h | 7 +---<br>
src/mesa/program/ir_to_mesa.cpp | 7 +---<br>
src/mesa/state_tracker/st_glsl_to_tgsi.cpp | 7 +---<br>
16 files changed, 77 insertions(+), 174 deletions(-)<br>
<br>
diff --git a/src/glsl/ast.h b/src/glsl/ast.h<br>
index 1c7fc63..26c4701 100644<br>
--- a/src/glsl/ast.h<br>
+++ b/src/glsl/ast.h<br>
@@ -53,19 +53,12 @@ public:<br>
* easier to just ralloc_free 'ctx' (or any of its ancestors). */<br>
static void* operator new(size_t size, void *ctx)<br>
{<br>
- void *node;<br>
-<br>
- node = rzalloc_size(ctx, size);<br>
- assert(node != NULL);<br>
-<br>
- return node;<br>
+ return ralloc_new<ast_node>(size, ctx);<br>
}<br>
<br>
- /* If the user *does* call delete, that's OK, we will just<br>
- * ralloc_free in that case. */<br>
- static void operator delete(void *table)<br>
+ static void operator delete(void *p)<br>
{<br>
- ralloc_free(table);<br>
+ ralloc_delete(p);<br>
}<br>
<br>
/**<br>
@@ -367,19 +360,12 @@ struct ast_type_qualifier {<br>
* easier to just ralloc_free 'ctx' (or any of its ancestors). */<br>
static void* operator new(size_t size, void *ctx)<br>
{<br>
- void *node;<br>
-<br>
- node = rzalloc_size(ctx, size);<br>
- assert(node != NULL);<br>
-<br>
- return node;<br>
+ return ralloc_new<ast_type_qualifier>(size, ctx);<br>
}<br>
<br>
- /* If the user *does* call delete, that's OK, we will just<br>
- * ralloc_free in that case. */<br>
- static void operator delete(void *table)<br>
+ static void operator delete(void *p)<br>
{<br>
- ralloc_free(table);<br>
+ ralloc_delete(p);<br>
}<br>
<br>
union {<br>
diff --git a/src/glsl/glsl_parser_extras.h b/src/glsl/glsl_parser_extras.h<br>
index 2e2440a..6c2a63e 100644<br>
--- a/src/glsl/glsl_parser_extras.h<br>
+++ b/src/glsl/glsl_parser_extras.h<br>
@@ -77,17 +77,12 @@ struct _mesa_glsl_parse_state {<br>
* easier to just ralloc_free 'ctx' (or any of its ancestors). */<br>
static void* operator new(size_t size, void *ctx)<br>
{<br>
- void *mem = rzalloc_size(ctx, size);<br>
- assert(mem != NULL);<br>
-<br>
- return mem;<br>
+ return ralloc_new<_mesa_glsl_parse_state>(size, ctx);<br>
}<br>
<br>
- /* If the user *does* call delete, that's OK, we will just<br>
- * ralloc_free in that case. */<br>
static void operator delete(void *mem)<br>
{<br>
- ralloc_free(mem);<br>
+ ralloc_delete(mem);<br>
}<br>
<br>
/**<br>
diff --git a/src/glsl/glsl_symbol_table.cpp b/src/glsl/glsl_symbol_table.cpp<br>
index 4c96620..11fe06e 100644<br>
--- a/src/glsl/glsl_symbol_table.cpp<br>
+++ b/src/glsl/glsl_symbol_table.cpp<br>
@@ -30,15 +30,12 @@ public:<br>
* easier to just ralloc_free 'ctx' (or any of its ancestors). */<br>
static void* operator new(size_t size, void *ctx)<br>
{<br>
- void *entry = ralloc_size(ctx, size);<br>
- assert(entry != NULL);<br>
- return entry;<br>
+ return ralloc_new<symbol_table_entry>(size, ctx);<br>
}<br>
<br>
- /* If the user *does* call delete, that's OK, we will just ralloc_free. */<br>
static void operator delete(void *entry)<br>
{<br>
- ralloc_free(entry);<br>
+ ralloc_delete(entry);<br>
}<br>
<br>
bool add_interface(const glsl_type *i, enum ir_variable_mode mode)<br>
diff --git a/src/glsl/glsl_symbol_table.h b/src/glsl/glsl_symbol_table.h<br>
index 62d26b8..f850d9f 100644<br>
--- a/src/glsl/glsl_symbol_table.h<br>
+++ b/src/glsl/glsl_symbol_table.h<br>
@@ -43,35 +43,16 @@ class symbol_table_entry;<br>
* type safe and some symbol table invariants.<br>
*/<br>
struct glsl_symbol_table {<br>
-private:<br>
- static void<br>
- _glsl_symbol_table_destructor (glsl_symbol_table *table)<br>
- {<br>
- table->~glsl_symbol_table();<br>
- }<br>
-<br>
-public:<br>
/* Callers of this ralloc-based new need not call delete. It's<br>
* easier to just ralloc_free 'ctx' (or any of its ancestors). */<br>
static void* operator new(size_t size, void *ctx)<br>
{<br>
- void *table;<br>
-<br>
- table = ralloc_size(ctx, size);<br>
- assert(table != NULL);<br>
-<br>
- ralloc_set_destructor(table, (void (*)(void*)) _glsl_symbol_table_destructor);<br>
-<br>
- return table;<br>
+ return ralloc_new<glsl_symbol_table>(size, ctx);<br>
}<br>
<br>
- /* If the user *does* call delete, that's OK, we will just<br>
- * ralloc_free in that case. Here, C++ will have already called the<br>
- * destructor so tell ralloc not to do that again. */<br>
static void operator delete(void *table)<br>
{<br>
- ralloc_set_destructor(table, NULL);<br>
- ralloc_free(table);<br>
+ ralloc_delete(table);<br>
}<br>
<br>
glsl_symbol_table();<br>
diff --git a/src/glsl/glsl_types.h b/src/glsl/glsl_types.h<br>
index 9f61eee..acdf48f 100644<br>
--- a/src/glsl/glsl_types.h<br>
+++ b/src/glsl/glsl_types.h<br>
@@ -103,19 +103,12 @@ struct glsl_type {<br>
assert(glsl_type::mem_ctx != NULL);<br>
}<br>
<br>
- void *type;<br>
-<br>
- type = ralloc_size(glsl_type::mem_ctx, size);<br>
- assert(type != NULL);<br>
-<br>
- return type;<br>
+ return ralloc_new<glsl_type>(size, glsl_type::mem_ctx);<br>
}<br>
<br>
- /* If the user *does* call delete, that's OK, we will just<br>
- * ralloc_free in that case. */<br>
static void operator delete(void *type)<br>
{<br>
- ralloc_free(type);<br>
+ ralloc_delete(type);<br>
}<br>
<br>
/**<br>
diff --git a/src/glsl/ir_function_detect_recursion.cpp b/src/glsl/ir_function_detect_recursion.cpp<br>
index 280c473..1b21672 100644<br>
--- a/src/glsl/ir_function_detect_recursion.cpp<br>
+++ b/src/glsl/ir_function_detect_recursion.cpp<br>
@@ -144,19 +144,12 @@ public:<br>
* easier to just ralloc_free 'ctx' (or any of its ancestors). */<br>
static void* operator new(size_t size, void *ctx)<br>
{<br>
- void *node;<br>
-<br>
- node = ralloc_size(ctx, size);<br>
- assert(node != NULL);<br>
-<br>
- return node;<br>
+ return ralloc_new<function>(size, ctx);<br>
}<br>
<br>
- /* If the user *does* call delete, that's OK, we will just<br>
- * ralloc_free in that case. */<br>
static void operator delete(void *node)<br>
{<br>
- ralloc_free(node);<br>
+ ralloc_delete(node);<br>
}<br>
<br>
ir_function_signature *sig;<br>
diff --git a/src/glsl/list.h b/src/glsl/list.h<br>
index 1d46365..dfd6378 100644<br>
--- a/src/glsl/list.h<br>
+++ b/src/glsl/list.h<br>
@@ -80,19 +80,12 @@ struct exec_node {<br>
* easier to just ralloc_free 'ctx' (or any of its ancestors). */<br>
static void* operator new(size_t size, void *ctx)<br>
{<br>
- void *node;<br>
-<br>
- node = ralloc_size(ctx, size);<br>
- assert(node != NULL);<br>
-<br>
- return node;<br>
+ return ralloc_new<exec_node>(size, ctx);<br>
}<br>
<br>
- /* If the user *does* call delete, that's OK, we will just<br>
- * ralloc_free in that case. */<br>
static void operator delete(void *node)<br>
{<br>
- ralloc_free(node);<br>
+ ralloc_delete(node);<br>
}<br>
<br>
exec_node() : next(NULL), prev(NULL)<br>
@@ -289,19 +282,12 @@ struct exec_list {<br>
* easier to just ralloc_free 'ctx' (or any of its ancestors). */<br>
static void* operator new(size_t size, void *ctx)<br>
{<br>
- void *node;<br>
-<br>
- node = ralloc_size(ctx, size);<br>
- assert(node != NULL);<br>
-<br>
- return node;<br>
+ return ralloc_new<exec_list>(size, ctx);<br>
}<br>
<br>
- /* If the user *does* call delete, that's OK, we will just<br>
- * ralloc_free in that case. */<br>
static void operator delete(void *node)<br>
{<br>
- ralloc_free(node);<br>
+ ralloc_delete(node);<br>
}<br>
<br>
exec_list()<br>
diff --git a/src/glsl/loop_analysis.h b/src/glsl/loop_analysis.h<br>
index 769d626..2a10211 100644<br>
--- a/src/glsl/loop_analysis.h<br>
+++ b/src/glsl/loop_analysis.h<br>
@@ -143,19 +143,7 @@ public:<br>
<br>
static void* operator new(size_t size, void *ctx)<br>
{<br>
- void *lvs = ralloc_size(ctx, size);<br>
- assert(lvs != NULL);<br>
-<br>
- ralloc_set_destructor(lvs, (void (*)(void*)) destructor);<br>
-<br>
- return lvs;<br>
- }<br>
-<br>
-private:<br>
- static void<br>
- destructor(loop_variable_state *lvs)<br>
- {<br>
- lvs->~loop_variable_state();<br>
+ return ralloc_new<loop_variable_state>(size, ctx);<br>
}<br>
};<br>
<br>
diff --git a/src/glsl/ralloc.h b/src/glsl/ralloc.h<br>
index 67eb938..6df4b89 100644<br>
--- a/src/glsl/ralloc.h<br>
+++ b/src/glsl/ralloc.h<br>
@@ -402,6 +402,50 @@ bool ralloc_vasprintf_append(char **str, const char *fmt, va_list args);<br>
<br>
#ifdef __cplusplus<br>
} /* end of extern "C" */<br>
+<br>
+namespace detail {<br>
+ template<typename T><br>
+ void<br>
+ ralloc_destroy(void *ptr) {<br>
+ reinterpret_cast<T *>(ptr)->~T();<br>
+ }<br>
+}<br>
+<br>
+/**<br>
+ * Helper function intended to be used as implementation of an<br>
+ * overload of the new operator for some specific type \p T.<br>
+ *<br>
+ * The allocated object will be owned by the given ralloc context \p<br>
+ * ctx: The object's destructor will be executed and its memory will<br>
+ * be deallocated automatically when the parent object \p ctx is<br>
+ * released.<br>
+ */<br>
+template<typename T><br>
+void *<br>
+ralloc_new(size_t size, const void *ctx) {<br>
+ void *ptr = ralloc_size(ctx, size);<br>
+ assert(ptr != NULL);<br>
+ ralloc_set_destructor(ptr, detail::ralloc_destroy<T>);<br>
+ return ptr;<br>
+}<br>
+<br>
+/**<br>
+ * Helper function that should be called from the delete operator<br>
+ * overload in classes using \c ralloc_new as implementation of the<br>
+ * new operator.<br>
+ *<br>
+ * \c ralloc_free should NOT be called directly by the delete<br>
+ * overload, because it will result in the object destructor being<br>
+ * called twice when the user deletes the object explicitly: first by<br>
+ * the compiler before the delete overload is executed and then by \c<br>
+ * ralloc_free.<br>
+ */<br>
+inline void<br>
+ralloc_delete(void *ptr) {<br>
+ ralloc_set_destructor(ptr, NULL);<br>
+ ralloc_free(ptr);<br>
+}<br>
+<br>
#endif<br>
<br>
#endif<br>
diff --git a/src/mesa/drivers/dri/i965/brw_cfg.h b/src/mesa/drivers/dri/i965/brw_cfg.h<br>
index 95a18e9..f8037a9 100644<br>
--- a/src/mesa/drivers/dri/i965/brw_cfg.h<br>
+++ b/src/mesa/drivers/dri/i965/brw_cfg.h<br>
@@ -41,12 +41,7 @@ class bblock_t {<br>
public:<br>
static void* operator new(size_t size, void *ctx)<br>
{<br>
- void *node;<br>
-<br>
- node = rzalloc_size(ctx, size);<br>
- assert(node != NULL);<br>
-<br>
- return node;<br>
+ return ralloc_new<bblock_t>(size, ctx);<br>
}<br>
<br>
bblock_link *make_list(void *mem_ctx);<br>
@@ -70,12 +65,7 @@ class cfg_t {<br>
public:<br>
static void* operator new(size_t size, void *ctx)<br>
{<br>
- void *node;<br>
-<br>
- node = rzalloc_size(ctx, size);<br>
- assert(node != NULL);<br>
-<br>
- return node;<br>
+ return ralloc_new<cfg_t>(size, ctx);<br>
}<br></blockquote><div><br></div><div>I'm worried about this one--it introduces a behavioural change. Previously, if a cfg_t object was reclaimed through the standard ralloc mechanism, cfg_t::~cfg_t() would *not* be called. Now it will be. Since cfg_t::~cfg_t() calls ralloc_free(mem_ctx), and since cfg_t's mem_ctx is usually (always?) the same mem_ctx that the cfg_t is contained in, I think that will result in double-freeing of the mem_ctx.<br>
<br></div><div>However, looking further into the users of cfg_t, it looks like they all pass it a "borrowed" mem_ctx (in other words, the caller always retains responsibility for freeing the mem_ctx. So I believe we have a pre-existing double-free bug. The correct solution is probably to get rid of the cfg_t destructor entirely.<br>
</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
cfg_t(backend_visitor *v);<br>
diff --git a/src/mesa/drivers/dri/i965/brw_fs.h b/src/mesa/drivers/dri/i965/brw_fs.h<br>
index cb4ac3b..7cd9fd8 100644<br>
--- a/src/mesa/drivers/dri/i965/brw_fs.h<br>
+++ b/src/mesa/drivers/dri/i965/brw_fs.h<br>
@@ -61,12 +61,7 @@ public:<br>
* easier to just ralloc_free 'ctx' (or any of its ancestors). */<br>
static void* operator new(size_t size, void *ctx)<br>
{<br>
- void *node;<br>
-<br>
- node = ralloc_size(ctx, size);<br>
- assert(node != NULL);<br>
-<br>
- return node;<br>
+ return ralloc_new<fs_reg>(size, ctx);<br>
}<br>
<br>
void init();<br>
@@ -124,12 +119,7 @@ class ip_record : public exec_node {<br>
public:<br>
static void* operator new(size_t size, void *ctx)<br>
{<br>
- void *node;<br>
-<br>
- node = rzalloc_size(ctx, size);<br>
- assert(node != NULL);<br>
-<br>
- return node;<br>
+ return ralloc_new<ip_record>(size, ctx);<br>
}<br>
<br>
ip_record(int ip)<br>
@@ -146,12 +136,7 @@ public:<br>
* easier to just ralloc_free 'ctx' (or any of its ancestors). */<br>
static void* operator new(size_t size, void *ctx)<br>
{<br>
- void *node;<br>
-<br>
- node = rzalloc_size(ctx, size);<br>
- assert(node != NULL);<br>
-<br>
- return node;<br>
+ return ralloc_new<fs_inst>(size, ctx);<br>
}<br>
<br>
void init();<br>
diff --git a/src/mesa/drivers/dri/i965/brw_fs_live_variables.h b/src/mesa/drivers/dri/i965/brw_fs_live_variables.h<br>
index 1cde5f4..74542e5 100644<br>
--- a/src/mesa/drivers/dri/i965/brw_fs_live_variables.h<br>
+++ b/src/mesa/drivers/dri/i965/brw_fs_live_variables.h<br>
@@ -55,12 +55,7 @@ class fs_live_variables {<br>
public:<br>
static void* operator new(size_t size, void *ctx)<br>
{<br>
- void *node;<br>
-<br>
- node = rzalloc_size(ctx, size);<br>
- assert(node != NULL);<br>
-<br>
- return node;<br>
+ return ralloc_new<fs_live_variables>(size, ctx);<br>
}<br></blockquote><div><br></div><div>I'm worried about this one too, for similar reasons. I believe in this case the appropriate solution is the same: get rid of the fs_live_variables destructor entirely.<br> <br>
</div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
fs_live_variables(fs_visitor *v, cfg_t *cfg);<br>
diff --git a/src/mesa/drivers/dri/i965/brw_vec4.h b/src/mesa/drivers/dri/i965/brw_vec4.h<br>
index f0ab53d..c177d05 100644<br>
--- a/src/mesa/drivers/dri/i965/brw_vec4.h<br>
+++ b/src/mesa/drivers/dri/i965/brw_vec4.h<br>
@@ -122,12 +122,7 @@ public:<br>
* easier to just ralloc_free 'ctx' (or any of its ancestors). */<br>
static void* operator new(size_t size, void *ctx)<br>
{<br>
- void *node;<br>
-<br>
- node = ralloc_size(ctx, size);<br>
- assert(node != NULL);<br>
-<br>
- return node;<br>
+ return ralloc_new<src_reg>(size, ctx);<br>
}<br>
<br>
void init();<br>
@@ -160,12 +155,7 @@ public:<br>
* easier to just ralloc_free 'ctx' (or any of its ancestors). */<br>
static void* operator new(size_t size, void *ctx)<br>
{<br>
- void *node;<br>
-<br>
- node = ralloc_size(ctx, size);<br>
- assert(node != NULL);<br>
-<br>
- return node;<br>
+ return ralloc_new<dst_reg>(size, ctx);<br>
}<br>
<br>
void init();<br>
@@ -192,12 +182,7 @@ public:<br>
* easier to just ralloc_free 'ctx' (or any of its ancestors). */<br>
static void* operator new(size_t size, void *ctx)<br>
{<br>
- void *node;<br>
-<br>
- node = rzalloc_size(ctx, size);<br>
- assert(node != NULL);<br>
-<br>
- return node;<br>
+ return ralloc_new<vec4_instruction>(size, ctx);<br>
}<br>
<br>
vec4_instruction(vec4_visitor *v, enum opcode opcode,<br>
diff --git a/src/mesa/drivers/dri/i965/brw_vec4_live_variables.h b/src/mesa/drivers/dri/i965/brw_vec4_live_variables.h<br>
index 438a03e..168da40 100644<br>
--- a/src/mesa/drivers/dri/i965/brw_vec4_live_variables.h<br>
+++ b/src/mesa/drivers/dri/i965/brw_vec4_live_variables.h<br>
@@ -54,12 +54,7 @@ class vec4_live_variables {<br>
public:<br>
static void* operator new(size_t size, void *ctx)<br>
{<br>
- void *node;<br>
-<br>
- node = rzalloc_size(ctx, size);<br>
- assert(node != NULL);<br>
-<br>
- return node;<br>
+ return ralloc_new<vec4_live_variables>(size, ctx);<br>
}<br></blockquote><div><br></div><div>The exact same situation exists here (yay code duplication).<br><br></div><div>Other than these double-free issues, I really like what you've done here. It's a substantial reduction in boilerplate code that's easy to get wrong.<br>
</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
vec4_live_variables(vec4_visitor *v, cfg_t *cfg);<br>
diff --git a/src/mesa/program/ir_to_mesa.cpp b/src/mesa/program/ir_to_mesa.cpp<br>
index 8bc5412..41274a2 100644<br>
--- a/src/mesa/program/ir_to_mesa.cpp<br>
+++ b/src/mesa/program/ir_to_mesa.cpp<br>
@@ -153,12 +153,7 @@ public:<br>
* easier to just ralloc_free 'ctx' (or any of its ancestors). */<br>
static void* operator new(size_t size, void *ctx)<br>
{<br>
- void *node;<br>
-<br>
- node = rzalloc_size(ctx, size);<br>
- assert(node != NULL);<br>
-<br>
- return node;<br>
+ return ralloc_new<ir_to_mesa_instruction>(size, ctx);<br>
}<br>
<br>
enum prog_opcode op;<br>
diff --git a/src/mesa/state_tracker/st_glsl_to_tgsi.cpp b/src/mesa/state_tracker/st_glsl_to_tgsi.cpp<br>
index ff1ebd5..cd4802b 100644<br>
--- a/src/mesa/state_tracker/st_glsl_to_tgsi.cpp<br>
+++ b/src/mesa/state_tracker/st_glsl_to_tgsi.cpp<br>
@@ -221,12 +221,7 @@ public:<br>
* easier to just ralloc_free 'ctx' (or any of its ancestors). */<br>
static void* operator new(size_t size, void *ctx)<br>
{<br>
- void *node;<br>
-<br>
- node = rzalloc_size(ctx, size);<br>
- assert(node != NULL);<br>
-<br>
- return node;<br>
+ return ralloc_new<glsl_to_tgsi_instruction>(size, ctx);<br>
}<br>
<br>
unsigned op;<br>
<span class=""><font color="#888888">--<br>
1.8.3.4<br>
<br>
_______________________________________________<br>
mesa-dev mailing list<br>
<a href="mailto:mesa-dev@lists.freedesktop.org">mesa-dev@lists.freedesktop.org</a><br>
<a href="http://lists.freedesktop.org/mailman/listinfo/mesa-dev" target="_blank">http://lists.freedesktop.org/mailman/listinfo/mesa-dev</a><br>
</font></span></blockquote></div><br></div></div>