From: Jürg Billeter Date: Fri, 10 Apr 2009 15:02:22 +0000 (+0200) Subject: Arrays: Add experimental support for fixed-length arrays X-Git-Tag: 0.7.1~45 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e065e581748863cb7c90fabb2bb39d6671dfbe8f;p=thirdparty%2Fvala.git Arrays: Add experimental support for fixed-length arrays Local fixed-length arrays are allocated on the stack. int[3] array = { 1, 2, 3 }; Fixes bug 492481. --- diff --git a/ccode/valaccodevariabledeclarator.vala b/ccode/valaccodevariabledeclarator.vala index c28704d20..fdb9dfab8 100644 --- a/ccode/valaccodevariabledeclarator.vala +++ b/ccode/valaccodevariabledeclarator.vala @@ -36,13 +36,22 @@ public class Vala.CCodeVariableDeclarator : CCodeDeclarator { */ public CCodeExpression? initializer { get; set; } - public CCodeVariableDeclarator (string name, CCodeExpression? initializer = null) { + /** + * The optional declarator suffix. + */ + public string? declarator_suffix { get; set; } + + public CCodeVariableDeclarator (string name, CCodeExpression? initializer = null, string? declarator_suffix = null) { this.name = name; this.initializer = initializer; + this.declarator_suffix = declarator_suffix; } public override void write (CCodeWriter writer) { writer.write_string (name); + if (declarator_suffix != null) { + writer.write_string (declarator_suffix); + } if (initializer != null) { writer.write_string (" = "); @@ -52,6 +61,9 @@ public class Vala.CCodeVariableDeclarator : CCodeDeclarator { public override void write_declaration (CCodeWriter writer) { writer.write_string (name); + if (declarator_suffix != null) { + writer.write_string (declarator_suffix); + } // initializer lists can't be moved to a separate statement if (initializer is CCodeInitializerList) { diff --git a/gobject/valaccodearraymodule.vala b/gobject/valaccodearraymodule.vala index f1a9ba8b1..2143f3f25 100644 --- a/gobject/valaccodearraymodule.vala +++ b/gobject/valaccodearraymodule.vala @@ -46,6 +46,26 @@ internal class Vala.CCodeArrayModule : CCodeMethodCallModule { public override void visit_array_creation_expression (ArrayCreationExpression expr) { expr.accept_children (codegen); + var array_type = expr.target_type as ArrayType; + if (array_type != null && array_type.fixed_length) { + // no heap allocation for fixed-length arrays + + var ce = new CCodeCommaExpression (); + var temp_var = get_temp_variable (array_type, true, expr); + var name_cnode = new CCodeIdentifier (temp_var.name); + int i = 0; + + temp_vars.insert (0, temp_var); + + append_initializer_list (ce, name_cnode, expr.initializer_list, expr.rank, ref i); + + ce.append_expression (name_cnode); + + expr.ccodenode = ce; + + return; + } + var gnew = new CCodeFunctionCall (new CCodeIdentifier ("g_new0")); gnew.add_argument (new CCodeIdentifier (expr.element_type.get_cname ())); bool first = true; @@ -105,9 +125,14 @@ internal class Vala.CCodeArrayModule : CCodeMethodCallModule { } public override CCodeExpression get_array_length_cexpression (Expression array_expr, int dim = -1) { + var array_type = array_expr.value_type as ArrayType; + + if (array_type != null && array_type.fixed_length) { + return new CCodeConstant (array_type.length.to_string ()); + } + // dim == -1 => total size over all dimensions if (dim == -1) { - var array_type = array_expr.value_type as ArrayType; if (array_type != null && array_type.rank > 1) { CCodeExpression cexpr = get_array_length_cexpression (array_expr, 1); for (dim = 2; dim <= array_type.rank; dim++) { @@ -370,7 +395,9 @@ internal class Vala.CCodeArrayModule : CCodeMethodCallModule { } public override void append_vala_array_free () { - var fun = new CCodeFunction ("_vala_array_free", "void"); + // _vala_array_destroy only frees elements but not the array itself + + var fun = new CCodeFunction ("_vala_array_destroy", "void"); fun.modifiers = CCodeModifiers.STATIC; fun.add_parameter (new CCodeFormalParameter ("array", "gpointer")); fun.add_parameter (new CCodeFormalParameter ("array_length", "gint")); @@ -391,6 +418,26 @@ internal class Vala.CCodeArrayModule : CCodeMethodCallModule { fun.block = new CCodeBlock (); fun.block.add_statement (cif); + source_type_member_definition.append (fun); + + // _vala_array_free frees elements and array + + fun = new CCodeFunction ("_vala_array_free", "void"); + fun.modifiers = CCodeModifiers.STATIC; + fun.add_parameter (new CCodeFormalParameter ("array", "gpointer")); + fun.add_parameter (new CCodeFormalParameter ("array_length", "gint")); + fun.add_parameter (new CCodeFormalParameter ("destroy_func", "GDestroyNotify")); + source_declarations.add_type_member_declaration (fun.copy ()); + + // call _vala_array_destroy to free the array elements + var ccall = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_destroy")); + ccall.add_argument (new CCodeIdentifier ("array")); + ccall.add_argument (new CCodeIdentifier ("array_length")); + ccall.add_argument (new CCodeIdentifier ("destroy_func")); + + fun.block = new CCodeBlock (); + fun.block.add_statement (new CCodeExpressionStatement (ccall)); + var carrfree = new CCodeFunctionCall (new CCodeIdentifier ("g_free")); carrfree.add_argument (new CCodeIdentifier ("array")); fun.block.add_statement (new CCodeExpressionStatement (carrfree)); @@ -480,14 +527,69 @@ internal class Vala.CCodeArrayModule : CCodeMethodCallModule { source_type_member_definition.append (fun); } + public override CCodeExpression? get_ref_cexpression (DataType expression_type, CCodeExpression cexpr, Expression? expr, CodeNode node) { + if (expression_type is ArrayType) { + var array_type = (ArrayType) expression_type; + + if (!array_type.fixed_length) { + return base.get_ref_cexpression (expression_type, cexpr, expr, node); + } + + var decl = get_temp_variable (expression_type, false, node); + temp_vars.insert (0, decl); + + var ctemp = get_variable_cexpression (decl.name); + + var copy_call = new CCodeFunctionCall (new CCodeIdentifier (generate_array_copy_wrapper (array_type))); + copy_call.add_argument (cexpr); + copy_call.add_argument (ctemp); + + var ccomma = new CCodeCommaExpression (); + + ccomma.append_expression (copy_call); + ccomma.append_expression (ctemp); + + return ccomma; + } else { + return base.get_ref_cexpression (expression_type, cexpr, expr, node); + } + } + public override CCodeExpression? get_dup_func_expression (DataType type, SourceReference? source_reference) { if (type is ArrayType) { - return new CCodeIdentifier (generate_array_dup_wrapper ((ArrayType) type)); + var array_type = (ArrayType) type; + // fixed length arrays use different code + // generated by overridden get_ref_cexpression method + assert (!array_type.fixed_length); + return new CCodeIdentifier (generate_array_dup_wrapper (array_type)); } else { return base.get_dup_func_expression (type, source_reference); } } + public override CCodeExpression get_unref_expression (CCodeExpression cvar, DataType type, Expression expr) { + if (type is ArrayType) { + var array_type = (ArrayType) type; + + if (!array_type.fixed_length) { + return base.get_unref_expression (cvar, type, expr); + } + + requires_array_free = true; + + var ccall = new CCodeFunctionCall (get_destroy_func_expression (type)); + + ccall = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_destroy")); + ccall.add_argument (cvar); + ccall.add_argument (new CCodeConstant ("%d".printf (array_type.length))); + ccall.add_argument (new CCodeCastExpression (get_destroy_func_expression (array_type.element_type), "GDestroyNotify")); + + return ccall; + } else { + return base.get_unref_expression (cvar, type, expr); + } + } + string generate_array_dup_wrapper (ArrayType array_type) { string dup_func = "_vala_array_dup%d".printf (++next_array_dup_id); @@ -560,6 +662,67 @@ internal class Vala.CCodeArrayModule : CCodeMethodCallModule { return dup_func; } + string generate_array_copy_wrapper (ArrayType array_type) { + string dup_func = "_vala_array_copy%d".printf (++next_array_dup_id); + + if (!add_wrapper (dup_func)) { + // wrapper already defined + return dup_func; + } + + // declaration + + var function = new CCodeFunction (dup_func, "void"); + function.modifiers = CCodeModifiers.STATIC; + + function.add_parameter (new CCodeFormalParameter ("self", array_type.get_cname () + "*")); + function.add_parameter (new CCodeFormalParameter ("dest", array_type.get_cname () + "*")); + + // definition + + var block = new CCodeBlock (); + + if (requires_copy (array_type.element_type)) { + var old_temp_vars = temp_vars; + + var idx_decl = new CCodeDeclaration ("int"); + idx_decl.add_declarator (new CCodeVariableDeclarator ("i")); + block.add_statement (idx_decl); + + var loop_body = new CCodeBlock (); + loop_body.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeElementAccess (new CCodeIdentifier ("dest"), new CCodeIdentifier ("i")), get_ref_cexpression (array_type.element_type, new CCodeElementAccess (new CCodeIdentifier ("self"), new CCodeIdentifier ("i")), null, array_type)))); + + var cfor = new CCodeForStatement (new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), new CCodeConstant ("%d".printf (array_type.length))), loop_body); + cfor.add_initializer (new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0"))); + cfor.add_iterator (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("i"))); + block.add_statement (cfor); + + var cfrag = new CCodeFragment (); + append_temp_decl (cfrag, temp_vars); + block.add_statement (cfrag); + temp_vars = old_temp_vars; + } else { + var dup_call = new CCodeFunctionCall (new CCodeIdentifier ("memcpy")); + dup_call.add_argument (new CCodeIdentifier ("dest")); + dup_call.add_argument (new CCodeIdentifier ("self")); + + var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof")); + sizeof_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ())); + dup_call.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeConstant ("%d".printf (array_type.length)), sizeof_call)); + + block.add_statement (new CCodeExpressionStatement (dup_call)); + } + + // append to file + + source_declarations.add_type_member_declaration (function.copy ()); + + function.block = block; + source_type_member_definition.append (function); + + return dup_func; + } + string generate_array_add_wrapper (ArrayType array_type) { string add_func = "_vala_array_add%d".printf (++next_array_add_id); diff --git a/gobject/valaccodeassignmentmodule.vala b/gobject/valaccodeassignmentmodule.vala index fa64ccc21..44706288d 100644 --- a/gobject/valaccodeassignmentmodule.vala +++ b/gobject/valaccodeassignmentmodule.vala @@ -208,6 +208,23 @@ internal class Vala.CCodeAssignmentModule : CCodeMemberAccessModule { return codenode; } + CCodeExpression emit_fixed_length_array_assignment (Assignment assignment, ArrayType array_type) { + CCodeExpression rhs = (CCodeExpression) assignment.right.ccodenode; + CCodeExpression lhs = (CCodeExpression) get_ccodenode (assignment.left); + + // it is necessary to use memcpy for fixed-length (stack-allocated) arrays + // simple assignments do not work in C + var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof")); + sizeof_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ())); + var size = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeConstant ("%d".printf (array_type.length)), sizeof_call); + var ccopy = new CCodeFunctionCall (new CCodeIdentifier ("memcpy")); + ccopy.add_argument (lhs); + ccopy.add_argument (rhs); + ccopy.add_argument (size); + + return ccopy; + } + public override void visit_assignment (Assignment assignment) { assignment.right.accept (codegen); @@ -219,7 +236,12 @@ internal class Vala.CCodeAssignmentModule : CCodeMemberAccessModule { if (assignment.left.symbol_reference is Property) { assignment.ccodenode = emit_property_assignment (assignment); } else { - assignment.ccodenode = emit_simple_assignment (assignment); + var array_type = assignment.left.value_type as ArrayType; + if (array_type != null && array_type.fixed_length) { + assignment.ccodenode = emit_fixed_length_array_assignment (assignment, array_type); + } else { + assignment.ccodenode = emit_simple_assignment (assignment); + } } } } diff --git a/gobject/valaccodebasemodule.vala b/gobject/valaccodebasemodule.vala index e11eece0d..a4e5506bb 100644 --- a/gobject/valaccodebasemodule.vala +++ b/gobject/valaccodebasemodule.vala @@ -1480,15 +1480,17 @@ internal class Vala.CCodeBaseModule : CCodeModule { if (local.variable_type is ArrayType) { // create variables to store array dimensions var array_type = (ArrayType) local.variable_type; - - for (int dim = 1; dim <= array_type.rank; dim++) { - var len_var = new LocalVariable (int_type.copy (), head.get_array_length_cname (get_variable_cname (local.name), dim)); - temp_vars.insert (0, len_var); - } - if (array_type.rank == 1) { - var size_var = new LocalVariable (int_type.copy (), head.get_array_size_cname (get_variable_cname (local.name))); - temp_vars.insert (0, size_var); + if (!array_type.fixed_length) { + for (int dim = 1; dim <= array_type.rank; dim++) { + var len_var = new LocalVariable (int_type.copy (), head.get_array_length_cname (get_variable_cname (local.name), dim)); + temp_vars.insert (0, len_var); + } + + if (array_type.rank == 1) { + var size_var = new LocalVariable (int_type.copy (), head.get_array_size_cname (get_variable_cname (local.name))); + temp_vars.insert (0, size_var); + } } } else if (local.variable_type is DelegateType) { var deleg_type = (DelegateType) local.variable_type; @@ -1507,26 +1509,30 @@ internal class Vala.CCodeBaseModule : CCodeModule { if (local.variable_type is ArrayType) { var array_type = (ArrayType) local.variable_type; - var ccomma = new CCodeCommaExpression (); + if (array_type.fixed_length) { + rhs = null; + } else { + var ccomma = new CCodeCommaExpression (); - var temp_var = get_temp_variable (local.variable_type, true, local); - temp_vars.insert (0, temp_var); - ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (temp_var.name), rhs)); + var temp_var = get_temp_variable (local.variable_type, true, local); + temp_vars.insert (0, temp_var); + ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (temp_var.name), rhs)); - for (int dim = 1; dim <= array_type.rank; dim++) { - var lhs_array_len = get_variable_cexpression (head.get_array_length_cname (get_variable_cname (local.name), dim)); - var rhs_array_len = head.get_array_length_cexpression (local.initializer, dim); - ccomma.append_expression (new CCodeAssignment (lhs_array_len, rhs_array_len)); - } - if (array_type.rank == 1) { - var lhs_array_size = get_variable_cexpression (head.get_array_size_cname (get_variable_cname (local.name))); - var rhs_array_len = get_variable_cexpression (head.get_array_length_cname (get_variable_cname (local.name), 1)); - ccomma.append_expression (new CCodeAssignment (lhs_array_size, rhs_array_len)); - } + for (int dim = 1; dim <= array_type.rank; dim++) { + var lhs_array_len = get_variable_cexpression (head.get_array_length_cname (get_variable_cname (local.name), dim)); + var rhs_array_len = head.get_array_length_cexpression (local.initializer, dim); + ccomma.append_expression (new CCodeAssignment (lhs_array_len, rhs_array_len)); + } + if (array_type.rank == 1) { + var lhs_array_size = get_variable_cexpression (head.get_array_size_cname (get_variable_cname (local.name))); + var rhs_array_len = get_variable_cexpression (head.get_array_length_cname (get_variable_cname (local.name), 1)); + ccomma.append_expression (new CCodeAssignment (lhs_array_size, rhs_array_len)); + } - ccomma.append_expression (get_variable_cexpression (temp_var.name)); + ccomma.append_expression (get_variable_cexpression (temp_var.name)); - rhs = ccomma; + rhs = ccomma; + } } else if (local.variable_type is DelegateType) { var deleg_type = (DelegateType) local.variable_type; var d = deleg_type.delegate_symbol; @@ -1553,15 +1559,19 @@ internal class Vala.CCodeBaseModule : CCodeModule { // initialize array length variables var array_type = (ArrayType) local.variable_type; - var ccomma = new CCodeCommaExpression (); + if (array_type.fixed_length) { + rhs = null; + } else { + var ccomma = new CCodeCommaExpression (); - for (int dim = 1; dim <= array_type.rank; dim++) { - ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (head.get_array_length_cname (get_variable_cname (local.name), dim)), new CCodeConstant ("0"))); - } + for (int dim = 1; dim <= array_type.rank; dim++) { + ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (head.get_array_length_cname (get_variable_cname (local.name), dim)), new CCodeConstant ("0"))); + } - ccomma.append_expression (rhs); + ccomma.append_expression (rhs); - rhs = ccomma; + rhs = ccomma; + } } } @@ -1573,13 +1583,13 @@ internal class Vala.CCodeBaseModule : CCodeModule { } if (current_method != null && current_method.coroutine) { - closure_struct.add_field (local.variable_type.get_cname (), get_variable_cname (local.name)); + closure_struct.add_field (local.variable_type.get_cname (), get_variable_cname (local.name) + local.variable_type.get_cdeclarator_suffix ()); if (local.initializer != null) { cfrag.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), get_variable_cname (local.name)), rhs))); } } else { - var cvar = new CCodeVariableDeclarator (get_variable_cname (local.name), rhs); + var cvar = new CCodeVariableDeclarator (get_variable_cname (local.name), rhs, local.variable_type.get_cdeclarator_suffix ()); var cdecl = new CCodeDeclaration (local.variable_type.get_cname ()); cdecl.add_declarator (cvar); @@ -1592,6 +1602,24 @@ internal class Vala.CCodeBaseModule : CCodeModule { } } + if (local.initializer != null && local.variable_type is ArrayType) { + var array_type = (ArrayType) local.variable_type; + + if (array_type.fixed_length) { + // it is necessary to use memcpy for fixed-length (stack-allocated) arrays + // simple assignments do not work in C + var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof")); + sizeof_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ())); + var size = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeConstant ("%d".printf (array_type.length)), sizeof_call); + + var ccopy = new CCodeFunctionCall (new CCodeIdentifier ("memcpy")); + ccopy.add_argument (get_variable_cexpression (local.name)); + ccopy.add_argument ((CCodeExpression) local.initializer.ccodenode); + ccopy.add_argument (size); + cfrag.append (new CCodeExpressionStatement (ccopy)); + } + } + if (local.initializer != null && local.initializer.tree_can_fail) { head.add_simple_check (local.initializer, cfrag); } @@ -1883,7 +1911,7 @@ internal class Vala.CCodeBaseModule : CCodeModule { return destroy_func; } - public CCodeExpression get_unref_expression (CCodeExpression cvar, DataType type, Expression expr) { + public virtual CCodeExpression get_unref_expression (CCodeExpression cvar, DataType type, Expression expr) { var ccall = new CCodeFunctionCall (get_destroy_func_expression (type)); if (type is ValueType && !type.nullable) { @@ -1938,8 +1966,8 @@ internal class Vala.CCodeBaseModule : CCodeModule { if (array_type.element_type.data_type == null || array_type.element_type.data_type.is_reference_type ()) { requires_array_free = true; - bool first = true; CCodeExpression csizeexpr = null; + bool first = true; for (int dim = 1; dim <= array_type.rank; dim++) { if (first) { csizeexpr = head.get_array_length_cexpression (expr, dim); @@ -2029,27 +2057,29 @@ internal class Vala.CCodeBaseModule : CCodeModule { } else { var cdecl = new CCodeDeclaration (local.variable_type.get_cname ()); - var vardecl = new CCodeVariableDeclarator (local.name); + var vardecl = new CCodeVariableDeclarator (local.name, null, local.variable_type.get_cdeclarator_suffix ()); // sets #line local.ccodenode = vardecl; cdecl.add_declarator (vardecl); var st = local.variable_type.data_type as Struct; + var array_type = local.variable_type as ArrayType; if (local.name.has_prefix ("*")) { // do not dereference unintialized variable // initialization is not needed for these special // pointer temp variables // used to avoid side-effects in assignments - } else if (local.variable_type.is_reference_type_or_type_parameter ()) { - vardecl.initializer = new CCodeConstant ("NULL"); - } else if (st != null && !st.is_simple_type ()) { + } else if ((st != null && !st.is_simple_type ()) || + (array_type != null && array_type.fixed_length)) { // 0-initialize struct with struct initializer { 0 } // necessary as they will be passed by reference var clist = new CCodeInitializerList (); clist.append (new CCodeConstant ("0")); vardecl.initializer = clist; + } else if (local.variable_type.is_reference_type_or_type_parameter ()) { + vardecl.initializer = new CCodeConstant ("NULL"); } cfrag.append (cdecl); @@ -2530,6 +2560,11 @@ internal class Vala.CCodeBaseModule : CCodeModule { return false; } + var array_type = type as ArrayType; + if (array_type != null && array_type.fixed_length) { + return requires_destroy (array_type.element_type); + } + var cl = type.data_type as Class; if (cl != null && cl.is_reference_counting () && cl.get_unref_function () == "") { @@ -2555,7 +2590,7 @@ internal class Vala.CCodeBaseModule : CCodeModule { } } - public CCodeExpression? get_ref_cexpression (DataType expression_type, CCodeExpression cexpr, Expression? expr, CodeNode node) { + public virtual CCodeExpression? get_ref_cexpression (DataType expression_type, CCodeExpression cexpr, Expression? expr, CodeNode node) { if (expression_type is ValueType && !expression_type.nullable) { // normal value type, no null check // (copy (&expr, &temp), temp) @@ -3678,17 +3713,20 @@ internal class Vala.CCodeBaseModule : CCodeModule { } public CCodeExpression? default_value_for_type (DataType type, bool initializer_expression) { - if ((type.data_type != null && type.data_type.is_reference_type ()) - || type is PointerType || type is ArrayType || type is DelegateType) { - return new CCodeConstant ("NULL"); - } else if (type.data_type != null && type.data_type.get_default_value () != null) { - return new CCodeConstant (type.data_type.get_default_value ()); - } else if (type.data_type is Struct && initializer_expression) { + var array_type = type as ArrayType; + if (initializer_expression && (type.data_type is Struct || + (array_type != null && array_type.fixed_length))) { // 0-initialize struct with struct initializer { 0 } // only allowed as initializer expression in C var clist = new CCodeInitializerList (); clist.append (new CCodeConstant ("0")); return clist; + } else if ((type.data_type != null && type.data_type.is_reference_type ()) + || type is PointerType || type is DelegateType + || (array_type != null && !array_type.fixed_length)) { + return new CCodeConstant ("NULL"); + } else if (type.data_type != null && type.data_type.get_default_value () != null) { + return new CCodeConstant (type.data_type.get_default_value ()); } else if (type.type_parameter != null) { return new CCodeConstant ("NULL"); } else if (type is ErrorType) { diff --git a/gobject/valaccodecontrolflowmodule.vala b/gobject/valaccodecontrolflowmodule.vala index a9348d9c5..fda6f4623 100644 --- a/gobject/valaccodecontrolflowmodule.vala +++ b/gobject/valaccodecontrolflowmodule.vala @@ -1,6 +1,7 @@ /* valaccodecontrolflowmodule.vala * - * Copyright (C) 2006-2008 Jürg Billeter, Raffaele Sandrini + * Copyright (C) 2006-2009 Jürg Billeter + * Copyright (C) 2006-2008 Raffaele Sandrini * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -282,6 +283,12 @@ internal class Vala.CCodeControlFlowModule : CCodeMethodModule { var collection_backup = stmt.collection_variable; var collection_type = collection_backup.variable_type.copy (); + var array_type = collection_type as ArrayType; + if (array_type != null) { + // avoid assignment issues + array_type.fixed_length = false; + } + if (current_method != null && current_method.coroutine) { closure_struct.add_field (collection_type.get_cname (), collection_backup.name); cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (get_variable_cexpression (collection_backup.name), (CCodeExpression) stmt.collection.ccodenode))); @@ -301,7 +308,7 @@ internal class Vala.CCodeControlFlowModule : CCodeMethodModule { } if (stmt.collection.value_type is ArrayType) { - var array_type = (ArrayType) stmt.collection.value_type; + array_type = (ArrayType) stmt.collection.value_type; var array_len = head.get_array_length_cexpression (stmt.collection); diff --git a/gobject/valaccodestructmodule.vala b/gobject/valaccodestructmodule.vala index bbc2c9456..b45578cdf 100644 --- a/gobject/valaccodestructmodule.vala +++ b/gobject/valaccodestructmodule.vala @@ -45,18 +45,21 @@ internal class Vala.CCodeStructModule : CCodeBaseModule { if (f.binding == MemberBinding.INSTANCE) { generate_type_declaration (f.field_type, decl_space); - instance_struct.add_field (field_ctype, f.get_cname ()); + instance_struct.add_field (field_ctype, f.get_cname () + f.field_type.get_cdeclarator_suffix ()); if (f.field_type is ArrayType && !f.no_array_length) { // create fields to store array dimensions var array_type = (ArrayType) f.field_type; - var len_type = int_type.copy (); - for (int dim = 1; dim <= array_type.rank; dim++) { - instance_struct.add_field (len_type.get_cname (), head.get_array_length_cname (f.name, dim)); - } + if (!array_type.fixed_length) { + var len_type = int_type.copy (); + + for (int dim = 1; dim <= array_type.rank; dim++) { + instance_struct.add_field (len_type.get_cname (), head.get_array_length_cname (f.name, dim)); + } - if (array_type.rank == 1 && f.is_internal_symbol ()) { - instance_struct.add_field (len_type.get_cname (), head.get_array_size_cname (f.name)); + if (array_type.rank == 1 && f.is_internal_symbol ()) { + instance_struct.add_field (len_type.get_cname (), head.get_array_size_cname (f.name)); + } } } else if (f.field_type is DelegateType) { var delegate_type = (DelegateType) f.field_type; @@ -201,14 +204,28 @@ internal class Vala.CCodeStructModule : CCodeBaseModule { copy = get_ref_cexpression (f.field_type, copy, ma, f); } var dest = new CCodeMemberAccess.pointer (new CCodeIdentifier ("dest"), f.name); - cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (dest, copy))); var array_type = f.field_type as ArrayType; - if (array_type != null) { - for (int dim = 1; dim <= array_type.rank; dim++) { - var len_src = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), get_array_length_cname (f.name, dim)); - var len_dest = new CCodeMemberAccess.pointer (new CCodeIdentifier ("dest"), get_array_length_cname (f.name, dim)); - cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (len_dest, len_src))); + if (array_type != null && array_type.fixed_length) { + // fixed-length (stack-allocated) arrays + var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof")); + sizeof_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ())); + var size = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeConstant ("%d".printf (array_type.length)), sizeof_call); + + var array_copy_call = new CCodeFunctionCall (new CCodeIdentifier ("memcpy")); + array_copy_call.add_argument (dest); + array_copy_call.add_argument (copy); + array_copy_call.add_argument (size); + cblock.add_statement (new CCodeExpressionStatement (array_copy_call)); + } else { + cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (dest, copy))); + + if (array_type != null) { + for (int dim = 1; dim <= array_type.rank; dim++) { + var len_src = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), get_array_length_cname (f.name, dim)); + var len_dest = new CCodeMemberAccess.pointer (new CCodeIdentifier ("dest"), get_array_length_cname (f.name, dim)); + cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (len_dest, len_src))); + } } } } diff --git a/vala/valaarraytype.vala b/vala/valaarraytype.vala index 1534c6ddf..471155562 100644 --- a/vala/valaarraytype.vala +++ b/vala/valaarraytype.vala @@ -37,6 +37,13 @@ public class Vala.ArrayType : ReferenceType { } } + public bool fixed_length { get; set; } + + /** + * The length of this fixed-length array. + */ + public int length { get; set; } + /** * The rank of this array. */ @@ -127,13 +134,30 @@ public class Vala.ArrayType : ReferenceType { result.value_owned = value_owned; result.nullable = nullable; result.floating_reference = floating_reference; - + + if (fixed_length) { + result.fixed_length = true; + result.length = length; + } + return result; } public override string? get_cname () { // FIXME add support for [Immutable] or [Const] attribute to support arrays to const data - return element_type.get_cname () + "*"; + if (fixed_length) { + return element_type.get_cname (); + } else { + return element_type.get_cname () + "*"; + } + } + + public override string get_cdeclarator_suffix () { + if (fixed_length) { + return "[%d]".printf (length); + } else { + return ""; + } } public override bool is_array () { diff --git a/vala/valadatatype.vala b/vala/valadatatype.vala index 68199e86d..45af86606 100644 --- a/vala/valadatatype.vala +++ b/vala/valadatatype.vala @@ -118,6 +118,10 @@ public abstract class Vala.DataType : CodeNode { return null; } + public virtual string get_cdeclarator_suffix () { + return ""; + } + /** * Returns the name and qualifiers of this type as it is used in C code * in a const declaration. diff --git a/vala/valaparser.vala b/vala/valaparser.vala index ee9e696ef..ab11ad142 100644 --- a/vala/valaparser.vala +++ b/vala/valaparser.vala @@ -422,13 +422,18 @@ public class Vala.Parser : CodeVisitor { // this is more logical, especially when nullable arrays // or pointers are involved while (accept (TokenType.OPEN_BRACKET)) { + int array_length = -1; int array_rank = 0; do { array_rank++; // support for stack-allocated arrays // also required for decision between expression and declaration statement if (current () != TokenType.COMMA && current () != TokenType.CLOSE_BRACKET) { - parse_expression (); + var length_expression = parse_expression (); + var length_literal = length_expression as IntegerLiteral; + if (length_literal != null) { + array_length = length_literal.value.to_int (); + } } } while (accept (TokenType.COMMA)); @@ -437,8 +442,16 @@ public class Vala.Parser : CodeVisitor { // arrays contain strong references by default type.value_owned = true; - type = new ArrayType (type, array_rank, get_src (begin)); - type.nullable = accept (TokenType.INTERR); + var array_type = new ArrayType (type, array_rank, get_src (begin)); + array_type.nullable = accept (TokenType.INTERR); + + if (array_rank == 1 && array_length > 0) { + // fixed length (stack-allocated) array + array_type.fixed_length = true; + array_type.length = array_length; + } + + type = array_type; } if (accept (TokenType.OP_NEG)) {