From: Juerg Billeter Date: Fri, 27 Jul 2007 11:38:55 +0000 (+0000) Subject: fix memory management in foreach statements X-Git-Tag: VALA_0_1_2~5 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=db01616747c694fd5cce09c4356769e28c75fd66;p=thirdparty%2Fvala.git fix memory management in foreach statements 2007-07-27 Juerg Billeter * vala/parser.y, vala/valaforeachstatement.vala, vala/valamemorymanager.vala, vala/valasemanticanalyzer.vala, gobject/valacodegenerator.vala, gobject/valacodegeneratorassignment.vala: fix memory management in foreach statements svn path=/trunk/; revision=402 --- diff --git a/ChangeLog b/ChangeLog index 42c4fa646..4f55df916 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2007-07-27 Jürg Billeter + + * vala/parser.y, vala/valaforeachstatement.vala, + vala/valamemorymanager.vala, vala/valasemanticanalyzer.vala, + gobject/valacodegenerator.vala, + gobject/valacodegeneratorassignment.vala: fix memory management in + foreach statements + 2007-07-27 Jürg Billeter * gobject/valacodegenerator.vala: use cast for field initializers when diff --git a/gobject/valacodegenerator.vala b/gobject/valacodegenerator.vala index eb546130e..89c7749de 100644 --- a/gobject/valacodegenerator.vala +++ b/gobject/valacodegenerator.vala @@ -1321,16 +1321,26 @@ public class Vala.CodeGenerator : CodeVisitor { create_temp_decl (stmt, stmt.condition.temp_vars); } + public override void visit_begin_foreach_statement (ForeachStatement! stmt) { + stmt.variable_declarator.active = true; + stmt.collection_variable_declarator.active = true; + if (stmt.iterator_variable_declarator != null) { + stmt.iterator_variable_declarator.active = true; + } + } + public override void visit_end_foreach_statement (ForeachStatement! stmt) { var cblock = new CCodeBlock (); CCodeForStatement cfor; - VariableDeclarator collection_backup = get_temp_variable_declarator (stmt.collection.static_type); - - stmt.collection.temp_vars.prepend (collection_backup); + var cfrag = new CCodeFragment (); append_temp_decl (cfrag, stmt.collection.temp_vars); cblock.add_statement (cfrag); - cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (collection_backup.name), (CCodeExpression) stmt.collection.ccodenode))); + + var collection_backup = stmt.collection_variable_declarator; + var ccoldecl = new CCodeDeclaration (collection_backup.type_reference.get_cname ()); + ccoldecl.add_declarator (new CCodeVariableDeclarator.with_initializer (collection_backup.name, (CCodeExpression) stmt.collection.ccodenode)); + cblock.add_statement (ccoldecl); stmt.ccodenode = cblock; @@ -1348,9 +1358,23 @@ public class Vala.CodeGenerator : CodeVisitor { cblock.add_statement (citdecl); var cbody = new CCodeBlock (); - + + CCodeExpression element_expr = new CCodeIdentifier ("*%s".printf (it_name)); + + if (stmt.type_reference.takes_ownership) { + var ma = new MemberAccess.simple (stmt.variable_name); + ma.static_type = stmt.type_reference; + ma.ccodenode = element_expr; + element_expr = get_ref_expression (ma); + + var cfrag = new CCodeFragment (); + append_temp_decl (cfrag, temp_vars); + cbody.add_statement (cfrag); + temp_vars = null; + } + var cdecl = new CCodeDeclaration (stmt.type_reference.get_cname ()); - cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (stmt.variable_name, new CCodeIdentifier ("*%s".printf (it_name)))); + cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (stmt.variable_name, element_expr)); cbody.add_statement (cdecl); cbody.add_statement (stmt.body.ccodenode); @@ -1372,9 +1396,23 @@ public class Vala.CodeGenerator : CodeVisitor { cblock.add_statement (citdecl); var cbody = new CCodeBlock (); - + + CCodeExpression element_expr = new CCodeElementAccess (new CCodeIdentifier (collection_backup.name), new CCodeIdentifier (it_name)); + + if (stmt.type_reference.takes_ownership) { + var ma = new MemberAccess.simple (stmt.variable_name); + ma.static_type = stmt.type_reference; + ma.ccodenode = element_expr; + element_expr = get_ref_expression (ma); + + var cfrag = new CCodeFragment (); + append_temp_decl (cfrag, temp_vars); + cbody.add_statement (cfrag); + temp_vars = null; + } + var cdecl = new CCodeDeclaration (stmt.type_reference.get_cname ()); - cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (stmt.variable_name, new CCodeElementAccess (new CCodeIdentifier (collection_backup.name), new CCodeIdentifier (it_name)))); + cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (stmt.variable_name, element_expr)); cbody.add_statement (cdecl); cbody.add_statement (stmt.body.ccodenode); @@ -1419,6 +1457,18 @@ public class Vala.CodeGenerator : CodeVisitor { element_expr = convert_from_generic_pointer (element_expr, stmt.type_reference); + if (stmt.type_reference.takes_ownership) { + var ma = new MemberAccess.simple (stmt.variable_name); + ma.static_type = stmt.type_reference; + ma.ccodenode = element_expr; + element_expr = get_ref_expression (ma); + + var cfrag = new CCodeFragment (); + append_temp_decl (cfrag, temp_vars); + cbody.add_statement (cfrag); + temp_vars = null; + } + var cdecl = new CCodeDeclaration (stmt.type_reference.get_cname ()); cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (stmt.variable_name, element_expr)); cbody.add_statement (cdecl); @@ -1453,29 +1503,42 @@ public class Vala.CodeGenerator : CodeVisitor { element_expr = convert_from_generic_pointer (element_expr, stmt.type_reference); + List type_arg_list = it_method.return_type.get_type_arguments (); + var it_type = SemanticAnalyzer.get_actual_type (stmt.collection.static_type, it_method, (TypeReference) type_arg_list.data, stmt); + + if (stmt.type_reference.takes_ownership && !it_type.takes_ownership) { + var ma = new MemberAccess.simple (stmt.variable_name); + ma.static_type = stmt.type_reference; + ma.ccodenode = element_expr; + element_expr = get_ref_expression (ma); + + var cfrag = new CCodeFragment (); + append_temp_decl (cfrag, temp_vars); + cbody.add_statement (cfrag); + temp_vars = null; + } + var cdecl = new CCodeDeclaration (stmt.type_reference.get_cname ()); cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (stmt.variable_name, element_expr)); cbody.add_statement (cdecl); cbody.add_statement (stmt.body.ccodenode); - cbody.add_statement (new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier (stmt.variable_name), stmt.type_reference, null))); - var next_method = (Method) iterator_type.scope.lookup ("next"); var next_ccall = new CCodeFunctionCall (new CCodeIdentifier (next_method.get_cname ())); next_ccall.add_argument (new CCodeIdentifier (it_name)); cblock.add_statement (new CCodeWhileStatement (next_ccall, cbody)); - - var it_unref_ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref")); - it_unref_ccall.add_argument (new CCodeIdentifier (it_name)); - cblock.add_statement (new CCodeExpressionStatement (it_unref_ccall)); } - - if (memory_management && stmt.collection.static_type.transfers_ownership) { - var ma = new MemberAccess.simple (collection_backup.name); - ma.symbol_reference = collection_backup; - cblock.add_statement (new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier (collection_backup.name), stmt.collection.static_type, ma))); + + if (memory_management) { + foreach (VariableDeclarator decl in stmt.get_local_variables ()) { + if (decl.type_reference.takes_ownership) { + var ma = new MemberAccess.simple (decl.name); + ma.symbol_reference = decl; + cblock.add_statement (new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier (get_variable_cname (decl.name)), decl.type_reference, ma))); + } + } } } @@ -1987,7 +2050,7 @@ public class Vala.CodeGenerator : CodeVisitor { var get_param = (FormalParameter) get_params.data; if (get_param.type_reference.type_parameter != null) { - var index_type = SemanticAnalyzer.get_actual_type (expr.container.static_type, get_method, get_param.type_reference.type_parameter, expr); + var index_type = SemanticAnalyzer.get_actual_type (expr.container.static_type, get_method, get_param.type_reference, expr); cindex = convert_to_generic_pointer (cindex, index_type); } diff --git a/gobject/valacodegeneratorassignment.vala b/gobject/valacodegeneratorassignment.vala index 062dd0715..591e39b4e 100644 --- a/gobject/valacodegeneratorassignment.vala +++ b/gobject/valacodegeneratorassignment.vala @@ -219,7 +219,7 @@ public class Vala.CodeGenerator { var set_param = (FormalParameter) set_params.data; if (set_param.type_reference.type_parameter != null) { - var index_type = SemanticAnalyzer.get_actual_type (expr.container.static_type, set_method, set_param.type_reference.type_parameter, a); + var index_type = SemanticAnalyzer.get_actual_type (expr.container.static_type, set_method, set_param.type_reference, a); cindex = convert_to_generic_pointer (cindex, index_type); } diff --git a/vala/parser.y b/vala/parser.y index 8826842fc..4e573ec1f 100644 --- a/vala/parser.y +++ b/vala/parser.y @@ -1817,6 +1817,9 @@ foreach_statement : FOREACH OPEN_PARENS type identifier IN expression CLOSE_PARENS embedded_statement { ValaSourceReference *src = src(@3); + if (!vala_type_reference_get_is_weak ($3)) { + vala_type_reference_set_takes_ownership ($3, TRUE); + } $$ = VALA_STATEMENT (vala_foreach_statement_new ($3, $4, $6, $8, src)); g_object_unref ($3); g_free ($4); diff --git a/vala/valaforeachstatement.vala b/vala/valaforeachstatement.vala index 9ec45970a..1fecf9f9b 100644 --- a/vala/valaforeachstatement.vala +++ b/vala/valaforeachstatement.vala @@ -26,7 +26,7 @@ using GLib; * Represents a foreach statement in the source code. Foreach statements iterate * over the elements of a collection. */ -public class Vala.ForeachStatement : CodeNode, Statement { +public class Vala.ForeachStatement : Block { /** * Specifies the element type. */ @@ -68,6 +68,16 @@ public class Vala.ForeachStatement : CodeNode, Statement { */ public VariableDeclarator variable_declarator { get; set; } + /** + * Specifies the declarator for the generated collection variable. + */ + public VariableDeclarator collection_variable_declarator { get; set; } + + /** + * Specifies the declarator for the generated iterator variable. + */ + public VariableDeclarator iterator_variable_declarator { get; set; } + private Expression! _collection; private Block _body; @@ -86,6 +96,8 @@ public class Vala.ForeachStatement : CodeNode, Statement { public override void accept (CodeVisitor! visitor) { visitor.visit_begin_foreach_statement (this); + visitor.visit_begin_block (this); + type_reference.accept (visitor); collection.accept (visitor); @@ -93,6 +105,8 @@ public class Vala.ForeachStatement : CodeNode, Statement { body.accept (visitor); + visitor.visit_end_block (this); + visitor.visit_end_foreach_statement (this); } diff --git a/vala/valamemorymanager.vala b/vala/valamemorymanager.vala index f1fd96e30..43149c86f 100644 --- a/vala/valamemorymanager.vala +++ b/vala/valamemorymanager.vala @@ -186,7 +186,7 @@ public class Vala.MemoryManager : CodeVisitor { if (is_ref && param.type_reference.type_parameter != null) { if (expr.call is MemberAccess) { var ma = (MemberAccess) expr.call; - var param_type = SemanticAnalyzer.get_actual_type (ma.inner.static_type, msym, param.type_reference.type_parameter, expr); + var param_type = SemanticAnalyzer.get_actual_type (ma.inner.static_type, msym, param.type_reference, expr); if (param_type != null) { is_ref = param_type.takes_ownership; } @@ -227,7 +227,7 @@ public class Vala.MemoryManager : CodeVisitor { || param.type_reference.type_parameter != null)) { bool is_ref = param.type_reference.takes_ownership; if (is_ref && param.type_reference.type_parameter != null) { - var param_type = SemanticAnalyzer.get_actual_type (expr.type_reference, msym, param.type_reference.type_parameter, expr); + var param_type = SemanticAnalyzer.get_actual_type (expr.type_reference, msym, param.type_reference, expr); if (param_type != null) { is_ref = param_type.takes_ownership; } diff --git a/vala/valasemanticanalyzer.vala b/vala/valasemanticanalyzer.vala index 2ed03e90e..0b0ea404f 100644 --- a/vala/valasemanticanalyzer.vala +++ b/vala/valasemanticanalyzer.vala @@ -55,6 +55,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor { DataType gslist_type; DataType gerror_type; DataType iterable_type; + DataType iterator_type; DataType list_type; DataType map_type; @@ -110,6 +111,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor { var gee_ns = root_symbol.scope.lookup ("Gee"); if (gee_ns != null) { iterable_type = (DataType) gee_ns.scope.lookup ("Iterable"); + iterator_type = (DataType) gee_ns.scope.lookup ("Iterator"); list_type = (DataType) gee_ns.scope.lookup ("List"); map_type = (DataType) gee_ns.scope.lookup ("Map"); } @@ -861,11 +863,31 @@ public class Vala.SemanticAnalyzer : CodeVisitor { stmt.variable_declarator.type_reference = stmt.type_reference; stmt.body.scope.add (stmt.variable_name, stmt.variable_declarator); + + stmt.body.add_local_variable (stmt.variable_declarator); + stmt.variable_declarator.active = true; } public override void visit_end_foreach_statement (ForeachStatement! stmt) { + stmt.collection_variable_declarator = new VariableDeclarator ("%s_collection".printf (stmt.variable_name)); + stmt.collection_variable_declarator.type_reference = stmt.collection.static_type.copy (); + stmt.collection_variable_declarator.type_reference.transfers_ownership = false; + stmt.collection_variable_declarator.type_reference.takes_ownership = stmt.collection.static_type.transfers_ownership; + + stmt.add_local_variable (stmt.collection_variable_declarator); + stmt.collection_variable_declarator.active = true; + var collection_type = stmt.collection.static_type.data_type; - if (!(collection_type is Array || collection_type == glist_type || collection_type == gslist_type || collection_type == iterable_type || collection_type.is_subtype_of (iterable_type))) { + if (iterable_type != null && (collection_type == iterable_type || collection_type.is_subtype_of (iterable_type))) { + stmt.iterator_variable_declarator = new VariableDeclarator ("%s_it".printf (stmt.variable_name)); + stmt.iterator_variable_declarator.type_reference = new TypeReference (); + stmt.iterator_variable_declarator.type_reference.data_type = iterator_type; + stmt.iterator_variable_declarator.type_reference.takes_ownership = true; + stmt.iterator_variable_declarator.type_reference.add_type_argument (stmt.type_reference); + + stmt.add_local_variable (stmt.iterator_variable_declarator); + stmt.iterator_variable_declarator.active = true; + } else if (!(collection_type is Array || collection_type == glist_type || collection_type == gslist_type)) { stmt.error = true; Report.error (stmt.source_reference, "Collection not iterable"); return; @@ -1438,7 +1460,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor { expr.error = true; return; } else { - ret_type = get_actual_type (ma.inner.static_type, msym, ret_type.type_parameter, expr); + ret_type = get_actual_type (ma.inner.static_type, msym, ret_type, expr); if (ret_type == null) { return; } @@ -1456,7 +1478,8 @@ public class Vala.SemanticAnalyzer : CodeVisitor { check_arguments (expr, msym, params, expr.get_argument_list ()); } - public static TypeReference get_actual_type (TypeReference instance_type, Symbol generic_member, TypeParameter type_parameter, CodeNode node_reference) { + public static TypeReference get_actual_type (TypeReference derived_instance_type, Symbol generic_member, TypeReference generic_type, CodeNode node_reference) { + TypeReference instance_type = derived_instance_type; // trace type arguments back to the datatype where the method has been declared while (instance_type.data_type != generic_member.parent_symbol) { List base_types = null; @@ -1498,18 +1521,21 @@ public class Vala.SemanticAnalyzer : CodeVisitor { node_reference.error = true; return null; } - int param_index = instance_type.data_type.get_type_parameter_index (type_parameter.name); + int param_index = instance_type.data_type.get_type_parameter_index (generic_type.type_parameter.name); if (param_index == -1) { - Report.error (node_reference.source_reference, "internal error: unknown type parameter %s".printf (type_parameter.name)); + Report.error (node_reference.source_reference, "internal error: unknown type parameter %s".printf (generic_type.type_parameter.name)); node_reference.error = true; return null; } var actual_type = (TypeReference) instance_type.get_type_arguments ().nth_data (param_index); if (actual_type == null) { - Report.error (node_reference.source_reference, "internal error: no actual argument found for type parameter %s".printf (type_parameter.name)); + Report.error (node_reference.source_reference, "internal error: no actual argument found for type parameter %s".printf (generic_type.type_parameter.name)); node_reference.error = true; return null; } + actual_type = actual_type.copy (); + actual_type.transfers_ownership = actual_type.takes_ownership && generic_type.transfers_ownership; + actual_type.takes_ownership = actual_type.takes_ownership && generic_type.takes_ownership; return actual_type; } @@ -1567,7 +1593,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor { var index_type = get_param.type_reference; if (index_type.type_parameter != null) { - index_type = get_actual_type (expr.container.static_type, get_method, get_param.type_reference.type_parameter, expr); + index_type = get_actual_type (expr.container.static_type, get_method, get_param.type_reference, expr); } if (!is_type_compatible (index.static_type, index_type)) { @@ -1576,7 +1602,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor { return; } - expr.static_type = get_actual_type (expr.container.static_type, get_method, get_method.return_type.type_parameter, expr).copy (); + expr.static_type = get_actual_type (expr.container.static_type, get_method, get_method.return_type, expr).copy (); expr.static_type.takes_ownership = false; } else { expr.error = true;