1/* valaccodearraymodule.vala 2 * 3 * Copyright (C) 2006-2010 Jürg Billeter 4 * Copyright (C) 2006-2008 Raffaele Sandrini 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 * 20 * Author: 21 * Jürg Billeter <j@bitron.ch> 22 * Raffaele Sandrini <raffaele@sandrini.ch> 23 */ 24 25 26public class Vala.CCodeArrayModule : CCodeMethodCallModule { 27 int next_array_dup_id = 0; 28 int next_array_add_id = 0; 29 30 void append_initializer_list (CCodeExpression name_cnode, InitializerList initializer_list, int rank, ref int i) { 31 foreach (Expression e in initializer_list.get_initializers ()) { 32 if (rank > 1) { 33 append_initializer_list (name_cnode, (InitializerList) e, rank - 1, ref i); 34 } else { 35 ccode.add_assignment (new CCodeElementAccess (name_cnode, new CCodeConstant (i.to_string ())), get_cvalue (e)); 36 i++; 37 } 38 } 39 } 40 41 public override void visit_array_creation_expression (ArrayCreationExpression expr) { 42 var array_type = expr.target_type as ArrayType; 43 if (array_type != null && array_type.fixed_length) { 44 // no heap allocation for fixed-length arrays 45 46 var temp_var = get_temp_variable (array_type, true, expr); 47 temp_var.init = true; 48 var name_cnode = get_variable_cexpression (temp_var.name); 49 int i = 0; 50 51 emit_temp_var (temp_var); 52 53 append_initializer_list (name_cnode, expr.initializer_list, expr.rank, ref i); 54 55 set_cvalue (expr, name_cnode); 56 57 return; 58 } 59 60 CCodeFunctionCall gnew; 61 if (context.profile == Profile.POSIX) { 62 cfile.add_include ("stdlib.h"); 63 gnew = new CCodeFunctionCall (new CCodeIdentifier ("calloc")); 64 } else { 65 gnew = new CCodeFunctionCall (new CCodeIdentifier ("g_new0")); 66 gnew.add_argument (new CCodeIdentifier (get_ccode_name (expr.element_type))); 67 } 68 69 bool first = true; 70 CCodeExpression cexpr = null; 71 72 // iterate over each dimension 73 foreach (Expression size in expr.get_sizes ()) { 74 CCodeExpression csize = get_cvalue (size); 75 append_array_length (expr, csize); 76 77 if (first) { 78 cexpr = csize; 79 first = false; 80 } else { 81 cexpr = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, cexpr, csize); 82 } 83 } 84 85 // add extra item to have array NULL-terminated for all reference types 86 if (expr.element_type.type_symbol != null && expr.element_type.type_symbol.is_reference_type ()) { 87 cexpr = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, cexpr, new CCodeConstant ("1")); 88 } 89 90 gnew.add_argument (cexpr); 91 92 if (context.profile == Profile.POSIX) { 93 var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof")); 94 csizeof.add_argument (new CCodeIdentifier (get_ccode_name (expr.element_type))); 95 gnew.add_argument (csizeof); 96 } 97 98 var temp_var = get_temp_variable (expr.value_type, true, expr); 99 var name_cnode = get_variable_cexpression (temp_var.name); 100 int i = 0; 101 102 emit_temp_var (temp_var); 103 104 ccode.add_assignment (name_cnode, gnew); 105 106 if (expr.initializer_list != null) { 107 append_initializer_list (name_cnode, expr.initializer_list, expr.rank, ref i); 108 } 109 110 set_cvalue (expr, name_cnode); 111 } 112 113 public override string get_array_length_cname (string array_cname, int dim) { 114 return "%s_length%d".printf (array_cname, dim); 115 } 116 117 public override string get_variable_array_length_cname (Variable variable, int dim) { 118 string? length_cname = get_ccode_array_length_name (variable); 119 if (length_cname == null) { 120 length_cname = get_array_length_cname (get_ccode_name (variable), dim); 121 } 122 return (!) length_cname; 123 } 124 125 public override CCodeExpression get_array_length_cexpression (Expression array_expr, int dim = -1) { 126 return get_array_length_cvalue (array_expr.target_value, dim); 127 } 128 129 public override CCodeExpression get_array_length_cvalue (TargetValue value, int dim = -1) { 130 var array_type = value.value_type as ArrayType; 131 132 if (array_type != null && array_type.fixed_length) { 133 return get_ccodenode (array_type.length); 134 } 135 136 // dim == -1 => total size over all dimensions 137 if (dim == -1) { 138 if (array_type != null && array_type.rank > 1) { 139 CCodeExpression cexpr = get_array_length_cvalue (value, 1); 140 for (dim = 2; dim <= array_type.rank; dim++) { 141 cexpr = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, cexpr, get_array_length_cvalue (value, dim)); 142 } 143 return cexpr; 144 } else { 145 dim = 1; 146 } 147 } 148 149 List<CCodeExpression> size = ((GLibValue) value).array_length_cvalues; 150 if (size == null || size.size < dim) { 151 Report.error (array_type.source_reference, "internal: invalid array_length for given dimension"); 152 return new CCodeInvalidExpression (); 153 } 154 return size[dim - 1]; 155 } 156 157 public override string get_array_size_cname (string array_cname) { 158 return "_%s_size_".printf (array_cname); 159 } 160 161 public override void visit_element_access (ElementAccess expr) { 162 List<Expression> indices = expr.get_indices (); 163 int rank = indices.size; 164 165 var ccontainer = get_cvalue (expr.container); 166 var cindex = get_cvalue (indices[0]); 167 if (expr.container.symbol_reference is ArrayLengthField) { 168 /* Figure if cindex is a constant expression and calculate dim...*/ 169 var lit = indices[0] as IntegerLiteral; 170 var memberaccess = expr.container as MemberAccess; 171 if (lit != null && memberaccess != null) { 172 int dim = int.parse (lit.value); 173 set_cvalue (expr, get_array_length_cexpression (memberaccess.inner, dim + 1)); 174 } else { 175 Report.error (expr.source_reference, "internal error: only integer literals supported as index"); 176 } 177 } else if (expr.container.symbol_reference is Constant && rank > 1) { 178 // access to element in a multi-dimensional array constant 179 var cindices = new ArrayList<CCodeExpression> (); 180 cindices.add (cindex); 181 for (int i = 1; i < rank; i++) { 182 cindices.add (get_cvalue (indices[i])); 183 } 184 set_cvalue (expr, new CCodeElementAccess.with_indices (ccontainer, cindices)); 185 } else { 186 // access to element in an array 187 for (int i = 1; i < rank; i++) { 188 var cmul = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, cindex, get_array_length_cexpression (expr.container, i + 1)); 189 cindex = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, cmul, get_cvalue (indices[i])); 190 if (expr.container.is_constant ()) { 191 ccontainer = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, ccontainer); 192 } 193 } 194 set_cvalue (expr, new CCodeElementAccess (ccontainer, cindex)); 195 } 196 197 expr.target_value.value_type = expr.value_type.copy (); 198 if (!expr.lvalue) { 199 expr.target_value = store_temp_value (expr.target_value, expr); 200 } 201 ((GLibValue) expr.target_value).lvalue = true; 202 } 203 204 public override void visit_slice_expression (SliceExpression expr) { 205 var ccontainer = get_cvalue (expr.container); 206 var cstart = get_cvalue (expr.start); 207 var cstop = get_cvalue (expr.stop); 208 209 var cstartpointer = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, ccontainer, cstart); 210 var splicelen = new CCodeBinaryExpression (CCodeBinaryOperator.MINUS, cstop, cstart); 211 212 set_cvalue (expr, cstartpointer); 213 append_array_length (expr, splicelen); 214 } 215 216 void append_struct_array_free_loop (Struct st) { 217 var cforinit = new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0")); 218 var cforcond = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), new CCodeIdentifier ("array_length")); 219 var cforiter = new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("i"), new CCodeConstant ("1"))); 220 ccode.open_for (cforinit, cforcond, cforiter); 221 222 var cptrarray = new CCodeIdentifier ("array"); 223 var cea = new CCodeElementAccess (cptrarray, new CCodeIdentifier ("i")); 224 225 var cfreecall = new CCodeFunctionCall (get_destroy_func_expression (new StructValueType (st))); 226 cfreecall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cea)); 227 ccode.add_expression (cfreecall); 228 229 ccode.close (); 230 } 231 232 public override string? append_struct_array_free (Struct st) { 233 string cname = "_vala_%s_array_free".printf (get_ccode_name (st)); 234 235 if (cfile.add_declaration (cname)) { 236 return cname; 237 } 238 239 var fun = new CCodeFunction (cname, "void"); 240 fun.modifiers = CCodeModifiers.STATIC; 241 fun.add_parameter (new CCodeParameter ("array", "%s *".printf (get_ccode_name (st)))); 242 fun.add_parameter (new CCodeParameter ("array_length", get_ccode_name (int_type))); 243 244 push_function (fun); 245 246 var ccondarr = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("array"), new CCodeConstant ("NULL")); 247 ccode.open_if (ccondarr); 248 249 ccode.add_declaration (get_ccode_name (int_type), new CCodeVariableDeclarator ("i")); 250 append_struct_array_free_loop (st); 251 252 ccode.close (); 253 254 CCodeFunctionCall carrfree; 255 if (context.profile == Profile.POSIX) { 256 cfile.add_include ("stdlib.h"); 257 carrfree = new CCodeFunctionCall (new CCodeIdentifier ("free")); 258 } else { 259 carrfree = new CCodeFunctionCall (new CCodeIdentifier ("g_free")); 260 } 261 carrfree.add_argument (new CCodeIdentifier ("array")); 262 ccode.add_expression (carrfree); 263 264 pop_function (); 265 266 cfile.add_function_declaration (fun); 267 cfile.add_function (fun); 268 269 return cname; 270 } 271 272 public override string? append_struct_array_destroy (Struct st) { 273 string cname = "_vala_%s_array_destroy".printf (get_ccode_name (st)); 274 275 if (cfile.add_declaration (cname)) { 276 return cname; 277 } 278 279 var fun = new CCodeFunction (cname, "void"); 280 fun.modifiers = CCodeModifiers.STATIC; 281 fun.add_parameter (new CCodeParameter ("array", "%s *".printf (get_ccode_name (st)))); 282 fun.add_parameter (new CCodeParameter ("array_length", get_ccode_name (int_type))); 283 284 push_function (fun); 285 286 var ccondarr = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("array"), new CCodeConstant ("NULL")); 287 ccode.open_if (ccondarr); 288 289 ccode.add_declaration (get_ccode_name (int_type), new CCodeVariableDeclarator ("i")); 290 append_struct_array_free_loop (st); 291 292 ccode.close (); 293 294 pop_function (); 295 296 cfile.add_function_declaration (fun); 297 cfile.add_function (fun); 298 299 return cname; 300 } 301 302 void append_vala_array_free_loop () { 303 var cforinit = new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0")); 304 var cforcond = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), new CCodeIdentifier ("array_length")); 305 var cforiter = new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("i"), new CCodeConstant ("1"))); 306 ccode.open_for (cforinit, cforcond, cforiter); 307 308 var cptrarray = new CCodeCastExpression (new CCodeIdentifier ("array"), "%s*".printf (get_ccode_name (pointer_type))); 309 var cea = new CCodeElementAccess (cptrarray, new CCodeIdentifier ("i")); 310 311 var cfreecond = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, cea, new CCodeConstant ("NULL")); 312 ccode.open_if (cfreecond); 313 314 var cfreecall = new CCodeFunctionCall (new CCodeIdentifier ("destroy_func")); 315 cfreecall.add_argument (cea); 316 ccode.add_expression (cfreecall); 317 318 ccode.close (); 319 } 320 321 public override void append_vala_array_free () { 322 // _vala_array_destroy only frees elements but not the array itself 323 generate_type_declaration (delegate_target_destroy_type, cfile); 324 325 var fun = new CCodeFunction ("_vala_array_destroy", "void"); 326 fun.modifiers = CCodeModifiers.STATIC; 327 fun.add_parameter (new CCodeParameter ("array", get_ccode_name (pointer_type))); 328 fun.add_parameter (new CCodeParameter ("array_length", get_ccode_name (int_type))); 329 fun.add_parameter (new CCodeParameter ("destroy_func", get_ccode_name (delegate_target_destroy_type))); 330 331 push_function (fun); 332 333 var ccondarr = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("array"), new CCodeConstant ("NULL")); 334 var ccondfunc = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("destroy_func"), new CCodeConstant ("NULL")); 335 ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.AND, ccondarr, ccondfunc)); 336 337 ccode.add_declaration (get_ccode_name (int_type), new CCodeVariableDeclarator ("i")); 338 append_vala_array_free_loop (); 339 340 ccode.close (); 341 342 pop_function (); 343 344 cfile.add_function_declaration (fun); 345 cfile.add_function (fun); 346 347 // _vala_array_free frees elements and array 348 349 fun = new CCodeFunction ("_vala_array_free", "void"); 350 fun.modifiers = CCodeModifiers.STATIC; 351 fun.add_parameter (new CCodeParameter ("array", get_ccode_name (pointer_type))); 352 fun.add_parameter (new CCodeParameter ("array_length", get_ccode_name (int_type))); 353 fun.add_parameter (new CCodeParameter ("destroy_func", get_ccode_name (delegate_target_destroy_type))); 354 355 push_function (fun); 356 357 // call _vala_array_destroy to free the array elements 358 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_destroy")); 359 ccall.add_argument (new CCodeIdentifier ("array")); 360 ccall.add_argument (new CCodeIdentifier ("array_length")); 361 ccall.add_argument (new CCodeIdentifier ("destroy_func")); 362 ccode.add_expression (ccall); 363 364 CCodeFunctionCall carrfree; 365 if (context.profile == Profile.POSIX) { 366 cfile.add_include ("stdlib.h"); 367 carrfree = new CCodeFunctionCall (new CCodeIdentifier ("free")); 368 } else { 369 carrfree = new CCodeFunctionCall (new CCodeIdentifier ("g_free")); 370 } 371 carrfree.add_argument (new CCodeIdentifier ("array")); 372 ccode.add_expression (carrfree); 373 374 pop_function (); 375 376 cfile.add_function_declaration (fun); 377 cfile.add_function (fun); 378 } 379 380 public override void append_vala_array_move () { 381 cfile.add_include ("string.h"); 382 383 // assumes that overwritten array elements are null before invocation 384 // FIXME will leak memory if that's not the case 385 var fun = new CCodeFunction ("_vala_array_move", "void"); 386 fun.modifiers = CCodeModifiers.STATIC; 387 fun.add_parameter (new CCodeParameter ("array", get_ccode_name (pointer_type))); 388 fun.add_parameter (new CCodeParameter ("element_size", get_ccode_name (size_t_type))); 389 fun.add_parameter (new CCodeParameter ("src", get_ccode_name (int_type))); 390 fun.add_parameter (new CCodeParameter ("dest", get_ccode_name (int_type))); 391 fun.add_parameter (new CCodeParameter ("length", get_ccode_name (int_type))); 392 393 push_function (fun); 394 395 var array = new CCodeCastExpression (new CCodeIdentifier ("array"), "char*"); 396 var element_size = new CCodeIdentifier ("element_size"); 397 var length = new CCodeIdentifier ("length"); 398 var src = new CCodeIdentifier ("src"); 399 var src_end = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, src, length); 400 var dest = new CCodeIdentifier ("dest"); 401 var dest_end = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, dest, length); 402 var src_address = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, array, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, src, element_size)); 403 var dest_address = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, array, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, dest, element_size)); 404 var dest_end_address = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, array, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, dest_end, element_size)); 405 406 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("memmove")); 407 ccall.add_argument (dest_address); 408 ccall.add_argument (src_address); 409 ccall.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, length, element_size)); 410 ccode.add_expression (ccall); 411 412 ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.AND, new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, src, dest), new CCodeBinaryExpression (CCodeBinaryOperator.GREATER_THAN, src_end, dest))); 413 414 var czero1 = new CCodeFunctionCall (new CCodeIdentifier ("memset")); 415 czero1.add_argument (src_address); 416 czero1.add_argument (new CCodeConstant ("0")); 417 czero1.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeBinaryExpression (CCodeBinaryOperator.MINUS, dest, src), element_size)); 418 ccode.add_expression (czero1); 419 420 ccode.else_if (new CCodeBinaryExpression (CCodeBinaryOperator.AND, new CCodeBinaryExpression (CCodeBinaryOperator.GREATER_THAN, src, dest), new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, src, dest_end))); 421 422 var czero2 = new CCodeFunctionCall (new CCodeIdentifier ("memset")); 423 czero2.add_argument (dest_end_address); 424 czero2.add_argument (new CCodeConstant ("0")); 425 czero2.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeBinaryExpression (CCodeBinaryOperator.MINUS, src, dest), element_size)); 426 ccode.add_expression (czero2); 427 428 ccode.else_if (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, src, dest)); 429 430 var czero3 = new CCodeFunctionCall (new CCodeIdentifier ("memset")); 431 czero3.add_argument (src_address); 432 czero3.add_argument (new CCodeConstant ("0")); 433 czero3.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, length, element_size)); 434 ccode.add_expression (czero3); 435 436 ccode.close (); 437 438 pop_function (); 439 440 cfile.add_function_declaration (fun); 441 cfile.add_function (fun); 442 } 443 444 public override void append_vala_array_length () { 445 var fun = new CCodeFunction ("_vala_array_length", get_ccode_name (int_type)); 446 fun.modifiers = CCodeModifiers.STATIC; 447 fun.add_parameter (new CCodeParameter ("array", get_ccode_name (pointer_type))); 448 449 push_function (fun); 450 451 ccode.add_declaration (get_ccode_name (int_type), new CCodeVariableDeclarator ("length", new CCodeConstant ("0"))); 452 453 // return 0 if the array is NULL 454 // avoids an extra NULL check on the caller side 455 var array_check = new CCodeIdentifier ("array"); 456 ccode.open_if (array_check); 457 458 var array_element_check = new CCodeElementAccess (new CCodeCastExpression (new CCodeIdentifier ("array"), "%s*".printf (get_ccode_name (pointer_type))), new CCodeConstant ("length")); 459 ccode.open_while (array_element_check); 460 ccode.add_expression (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("length"))); 461 ccode.close (); 462 463 ccode.close (); 464 465 ccode.add_return (new CCodeIdentifier ("length")); 466 467 pop_function (); 468 469 cfile.add_function_declaration (fun); 470 cfile.add_function (fun); 471 } 472 473 public override TargetValue? copy_value (TargetValue value, CodeNode node) { 474 var type = value.value_type; 475 var cexpr = get_cvalue_ (value); 476 477 if (type is ArrayType) { 478 var array_type = (ArrayType) type; 479 480 if (!array_type.fixed_length) { 481 return base.copy_value (value, node); 482 } 483 484 var temp_value = create_temp_value (type, false, node); 485 486 var copy_call = new CCodeFunctionCall (new CCodeIdentifier (generate_array_copy_wrapper (array_type))); 487 copy_call.add_argument (cexpr); 488 copy_call.add_argument (get_cvalue_ (temp_value)); 489 ccode.add_expression (copy_call); 490 491 return temp_value; 492 } else { 493 return base.copy_value (value, node); 494 } 495 } 496 497 public override CCodeExpression? get_dup_func_expression (DataType type, SourceReference? source_reference, bool is_chainup) { 498 if (type is ArrayType) { 499 var array_type = (ArrayType) type; 500 // fixed length arrays use different code 501 // generated by overridden get_ref_cexpression method 502 assert (!array_type.fixed_length); 503 return new CCodeIdentifier (generate_array_dup_wrapper (array_type)); 504 } else { 505 return base.get_dup_func_expression (type, source_reference, is_chainup); 506 } 507 } 508 509 public override CCodeExpression destroy_value (TargetValue value, bool is_macro_definition = false) { 510 unowned ArrayType? array_type = value.value_type as ArrayType; 511 512 if (array_type != null && array_type.fixed_length) { 513 unowned Struct? st = array_type.element_type.type_symbol as Struct; 514 if (st != null && !array_type.element_type.nullable) { 515 var ccall = new CCodeFunctionCall (new CCodeIdentifier (append_struct_array_destroy (st))); 516 ccall.add_argument (get_cvalue_ (value)); 517 ccall.add_argument (get_ccodenode (array_type.length)); 518 return ccall; 519 } 520 521 requires_array_free = true; 522 generate_type_declaration (delegate_target_destroy_type, cfile); 523 524 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_destroy")); 525 ccall.add_argument (get_cvalue_ (value)); 526 ccall.add_argument (get_ccodenode (array_type.length)); 527 ccall.add_argument (new CCodeCastExpression (get_destroy_func_expression (array_type.element_type), get_ccode_name (delegate_target_destroy_type))); 528 529 return ccall; 530 } else { 531 return base.destroy_value (value, is_macro_definition); 532 } 533 } 534 535 string generate_array_dup_wrapper (ArrayType array_type) { 536 string dup_func = "_vala_array_dup%d".printf (++next_array_dup_id); 537 538 if (!add_wrapper (dup_func)) { 539 // wrapper already defined 540 return dup_func; 541 } 542 543 // declaration 544 545 var function = new CCodeFunction (dup_func, get_ccode_name (array_type)); 546 function.modifiers = CCodeModifiers.STATIC; 547 548 function.add_parameter (new CCodeParameter ("self", get_ccode_name (array_type))); 549 // total length over all dimensions 550 function.add_parameter (new CCodeParameter ("length", get_ccode_name (int_type))); 551 if (array_type.element_type is GenericType) { 552 // dup function array elements 553 string func_name = "%s_dup_func".printf (((GenericType) array_type.element_type).type_parameter.name.ascii_down ()); 554 function.add_parameter (new CCodeParameter (func_name, "GBoxedCopyFunc")); 555 } 556 557 // definition 558 559 push_context (new EmitContext ()); 560 push_function (function); 561 562 if (requires_copy (array_type.element_type)) { 563 var cvardecl = new CCodeVariableDeclarator ("result"); 564 CCodeFunctionCall gnew; 565 if (context.profile == Profile.POSIX) { 566 cfile.add_include ("stdlib.h"); 567 gnew = new CCodeFunctionCall (new CCodeIdentifier ("calloc")); 568 } else { 569 gnew = new CCodeFunctionCall (new CCodeIdentifier ("g_new0")); 570 gnew.add_argument (new CCodeIdentifier (get_ccode_name (array_type.element_type))); 571 } 572 573 CCodeExpression length_expr = new CCodeIdentifier ("length"); 574 CCodeBinaryOperator length_check_op; 575 // add extra item to have array NULL-terminated for all reference types 576 if (array_type.element_type.type_symbol != null && array_type.element_type.type_symbol.is_reference_type ()) { 577 length_expr = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, length_expr, new CCodeConstant ("1")); 578 length_check_op = CCodeBinaryOperator.GREATER_THAN_OR_EQUAL; 579 } else { 580 length_check_op = CCodeBinaryOperator.GREATER_THAN; 581 } 582 gnew.add_argument (length_expr); 583 584 if (context.profile == Profile.POSIX) { 585 var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof")); 586 csizeof.add_argument (new CCodeIdentifier (get_ccode_name (array_type.element_type))); 587 gnew.add_argument (csizeof); 588 } 589 590 // only attempt to dup if length >=/> 0, this deals with negative lengths and returns NULL 591 var length_check = new CCodeBinaryExpression (length_check_op, new CCodeIdentifier ("length"), new CCodeConstant ("0")); 592 ccode.open_if (length_check); 593 594 ccode.add_declaration (get_ccode_name (array_type), cvardecl); 595 ccode.add_assignment (new CCodeIdentifier ("result"), gnew); 596 597 ccode.add_declaration (get_ccode_name (int_type), new CCodeVariableDeclarator ("i")); 598 599 ccode.open_for (new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0")), 600 new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), new CCodeIdentifier ("length")), 601 new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("i"))); 602 603 ccode.add_assignment (new CCodeElementAccess (new CCodeIdentifier ("result"), new CCodeIdentifier ("i")), get_cvalue_ (copy_value (new GLibValue (array_type.element_type, new CCodeElementAccess (new CCodeIdentifier ("self"), new CCodeIdentifier ("i")), true), array_type))); 604 ccode.close (); 605 606 ccode.add_return (new CCodeIdentifier ("result")); 607 608 ccode.close (); 609 ccode.add_return (new CCodeConstant ("NULL")); 610 } else { 611 // only dup if length > 0, this deals with negative lengths and returns NULL 612 var length_check = new CCodeBinaryExpression (CCodeBinaryOperator.GREATER_THAN, new CCodeIdentifier ("length"), new CCodeConstant ("0")); 613 ccode.open_if (length_check); 614 615 var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof")); 616 sizeof_call.add_argument (new CCodeIdentifier (get_ccode_name (array_type.element_type))); 617 var length_expr = new CCodeIdentifier ("length"); 618 619 if (context.profile == Profile.POSIX) { 620 cfile.add_include ("stdlib.h"); 621 cfile.add_include ("string.h"); 622 623 var alloc = new CCodeFunctionCall (new CCodeIdentifier ("calloc")); 624 alloc.add_argument (length_expr); 625 alloc.add_argument (sizeof_call); 626 627 var cvardecl = new CCodeVariableDeclarator ("result"); 628 ccode.add_declaration (get_ccode_name (array_type), cvardecl); 629 ccode.add_assignment (new CCodeIdentifier ("result"), alloc); 630 631 var dup_call = new CCodeFunctionCall (new CCodeIdentifier ("memcpy")); 632 dup_call.add_argument (new CCodeIdentifier ("result")); 633 dup_call.add_argument (new CCodeIdentifier ("self")); 634 dup_call.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, length_expr, sizeof_call)); 635 ccode.add_expression (dup_call); 636 637 ccode.add_return (new CCodeIdentifier ("result")); 638 } else { 639 var dup_call = new CCodeFunctionCall (new CCodeIdentifier ("g_memdup")); 640 dup_call.add_argument (new CCodeIdentifier ("self")); 641 dup_call.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, length_expr, sizeof_call)); 642 643 ccode.add_return (dup_call); 644 } 645 646 ccode.close (); 647 ccode.add_return (new CCodeConstant ("NULL")); 648 } 649 650 // append to file 651 652 cfile.add_function_declaration (function); 653 cfile.add_function (function); 654 655 pop_context (); 656 657 return dup_func; 658 } 659 660 string generate_array_copy_wrapper (ArrayType array_type) { 661 string dup_func = "_vala_array_copy%d".printf (++next_array_dup_id); 662 663 if (!add_wrapper (dup_func)) { 664 // wrapper already defined 665 return dup_func; 666 } 667 668 // declaration 669 670 var function = new CCodeFunction (dup_func, "void"); 671 function.modifiers = CCodeModifiers.STATIC; 672 673 function.add_parameter (new CCodeParameter ("self", "%s *".printf (get_ccode_name (array_type)))); 674 function.add_parameter (new CCodeParameter ("dest", "%s *".printf (get_ccode_name (array_type)))); 675 676 // definition 677 678 push_context (new EmitContext ()); 679 push_function (function); 680 681 if (requires_copy (array_type.element_type)) { 682 ccode.add_declaration (get_ccode_name (int_type), new CCodeVariableDeclarator ("i")); 683 684 ccode.open_for (new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0")), 685 new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), get_ccodenode (array_type.length)), 686 new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("i"))); 687 688 689 ccode.add_assignment (new CCodeElementAccess (new CCodeIdentifier ("dest"), new CCodeIdentifier ("i")), get_cvalue_ (copy_value (new GLibValue (array_type.element_type, new CCodeElementAccess (new CCodeIdentifier ("self"), new CCodeIdentifier ("i")), true), array_type))); 690 } else { 691 cfile.add_include ("string.h"); 692 693 var dup_call = new CCodeFunctionCall (new CCodeIdentifier ("memcpy")); 694 dup_call.add_argument (new CCodeIdentifier ("dest")); 695 dup_call.add_argument (new CCodeIdentifier ("self")); 696 697 var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof")); 698 sizeof_call.add_argument (new CCodeIdentifier (get_ccode_name (array_type.element_type))); 699 dup_call.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, get_ccodenode (array_type.length), sizeof_call)); 700 701 ccode.add_expression (dup_call); 702 } 703 704 // append to file 705 706 cfile.add_function_declaration (function); 707 cfile.add_function (function); 708 709 pop_context (); 710 711 return dup_func; 712 } 713 714 string generate_array_add_wrapper (ArrayType array_type) { 715 string add_func = "_vala_array_add%d".printf (++next_array_add_id); 716 717 if (!add_wrapper (add_func)) { 718 // wrapper already defined 719 return add_func; 720 } 721 722 var function = new CCodeFunction (add_func, "void"); 723 function.modifiers = CCodeModifiers.STATIC; 724 725 function.add_parameter (new CCodeParameter ("array", "%s *".printf (get_ccode_name (array_type)))); 726 function.add_parameter (new CCodeParameter ("length", "%s*".printf (get_ccode_name (int_type)))); 727 function.add_parameter (new CCodeParameter ("size", "%s*".printf (get_ccode_name (int_type)))); 728 729 push_function (function); 730 731 string typename = get_ccode_name (array_type.element_type); 732 CCodeExpression value = new CCodeIdentifier ("value"); 733 if (array_type.element_type.is_real_struct_type ()) { 734 if (!array_type.element_type.nullable || !array_type.element_type.value_owned) { 735 typename = "const " + typename; 736 } 737 if (!array_type.element_type.nullable) { 738 typename += "*"; 739 value = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, value); 740 } 741 } 742 function.add_parameter (new CCodeParameter ("value", typename)); 743 744 var array = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("array")); 745 var length = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("length")); 746 var size = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("size")); 747 748 CCodeFunctionCall renew_call; 749 if (context.profile == Profile.POSIX) { 750 cfile.add_include ("stdlib.h"); 751 renew_call = new CCodeFunctionCall (new CCodeIdentifier ("realloc")); 752 renew_call.add_argument (array); 753 } else { 754 renew_call = new CCodeFunctionCall (new CCodeIdentifier ("g_renew")); 755 renew_call.add_argument (new CCodeIdentifier (get_ccode_name (array_type.element_type))); 756 renew_call.add_argument (array); 757 } 758 CCodeExpression renew_call_size; 759 if (array_type.element_type.is_reference_type_or_type_parameter ()) { 760 // NULL terminate array 761 renew_call_size = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, size, new CCodeConstant ("1")); 762 } else { 763 renew_call_size = size; 764 } 765 if (context.profile == Profile.POSIX) { 766 var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof")); 767 csizeof.add_argument (new CCodeIdentifier (get_ccode_name (array_type.element_type))); 768 renew_call_size = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, size, csizeof); 769 } 770 renew_call.add_argument (renew_call_size); 771 772 var csizecheck = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, length, size); 773 ccode.open_if (csizecheck); 774 ccode.add_assignment (size, new CCodeConditionalExpression (size, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeConstant ("2"), size), new CCodeConstant ("4"))); 775 ccode.add_assignment (array, renew_call); 776 ccode.close (); 777 778 ccode.add_assignment (new CCodeElementAccess (array, new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, length)), value); 779 780 if (array_type.element_type.is_reference_type_or_type_parameter ()) { 781 // NULL terminate array 782 ccode.add_assignment (new CCodeElementAccess (array, length), new CCodeConstant ("NULL")); 783 } 784 785 pop_function (); 786 787 cfile.add_function_declaration (function); 788 cfile.add_function (function); 789 790 return add_func; 791 } 792 793 bool is_array_add (Assignment assignment) { 794 var binary = assignment.right as BinaryExpression; 795 if (binary != null && binary.left.value_type is ArrayType) { 796 if (binary.operator == BinaryOperator.PLUS) { 797 if (assignment.left.symbol_reference == binary.left.symbol_reference) { 798 return true; 799 } 800 } 801 } 802 803 return false; 804 } 805 806 public override void visit_assignment (Assignment assignment) { 807 if (!is_array_add (assignment)) { 808 base.visit_assignment (assignment); 809 return; 810 } 811 812 var binary = (BinaryExpression) assignment.right; 813 814 var array = assignment.left; 815 var array_type = (ArrayType) array.value_type; 816 var element = binary.right; 817 818 var array_var = array.symbol_reference; 819 if (array_type.rank == 1 && array_var != null && array_var.is_internal_symbol () 820 && (array_var is LocalVariable || array_var is Field)) { 821 // valid array add 822 } else { 823 Report.error (assignment.source_reference, "Array concatenation not supported for public array variables and parameters"); 824 return; 825 } 826 827 var value_param = new Parameter ("value", element.target_type); 828 829 var ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_array_add_wrapper (array_type))); 830 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue (array))); 831 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_array_length_cexpression (array))); 832 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_array_size_cvalue (array.target_value))); 833 ccall.add_argument (handle_struct_argument (value_param, element, get_cvalue (element))); 834 835 ccode.add_expression (ccall); 836 } 837 838 public override CCodeParameter generate_parameter (Parameter param, CCodeFile decl_space, Map<int,CCodeParameter> cparam_map, Map<int,CCodeExpression>? carg_map) { 839 if (param.params_array || !(param.variable_type is ArrayType)) { 840 return base.generate_parameter (param, decl_space, cparam_map, carg_map); 841 } 842 843 string ctypename = get_ccode_name (param.variable_type); 844 string name = get_ccode_name (param); 845 var array_type = (ArrayType) param.variable_type; 846 847 if (array_type.fixed_length) { 848 ctypename += "*"; 849 } 850 851 if (param.direction != ParameterDirection.IN) { 852 ctypename += "*"; 853 } 854 855 var main_cparam = new CCodeParameter (name, ctypename); 856 857 generate_type_declaration (array_type.element_type, decl_space); 858 859 cparam_map.set (get_param_pos (get_ccode_pos (param)), main_cparam); 860 if (carg_map != null) { 861 carg_map.set (get_param_pos (get_ccode_pos (param)), get_parameter_cexpression (param)); 862 } 863 864 if (!array_type.fixed_length && get_ccode_array_length (param)) { 865 var length_ctype = get_ccode_array_length_type (param); 866 if (param.direction != ParameterDirection.IN) { 867 length_ctype = "%s*".printf (length_ctype); 868 } 869 870 for (int dim = 1; dim <= array_type.rank; dim++) { 871 var cparam = new CCodeParameter (get_variable_array_length_cname (param, dim), length_ctype); 872 cparam_map.set (get_param_pos (get_ccode_array_length_pos (param) + 0.01 * dim), cparam); 873 if (carg_map != null) { 874 carg_map.set (get_param_pos (get_ccode_array_length_pos (param) + 0.01 * dim), get_cexpression (cparam.name)); 875 } 876 } 877 } 878 879 return main_cparam; 880 } 881 882 public override void append_params_array (Method m) { 883 var local = m.params_array_var; 884 var array_type = (ArrayType) local.variable_type; 885 886 var local_length = new LocalVariable (array_type.length_type.copy (), get_array_length_cname (local.name, 1), null, local.source_reference); 887 var local_size = new LocalVariable (array_type.length_type.copy (), get_array_size_cname (get_local_cname (local))); 888 889 CCodeFunctionCall gnew; 890 if (context.profile == Profile.POSIX) { 891 cfile.add_include ("stdlib.h"); 892 gnew = new CCodeFunctionCall (new CCodeIdentifier ("calloc")); 893 } else { 894 gnew = new CCodeFunctionCall (new CCodeIdentifier ("g_new0")); 895 gnew.add_argument (new CCodeIdentifier (get_ccode_name (array_type.element_type))); 896 } 897 898 CCodeExpression length_expr = get_local_cexpression (local_length); 899 // add extra item to have array NULL-terminated for all reference types 900 if (array_type.element_type.type_symbol != null && array_type.element_type.type_symbol.is_reference_type ()) { 901 length_expr = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, length_expr, new CCodeConstant ("1")); 902 } 903 gnew.add_argument (length_expr); 904 if (context.profile == Profile.POSIX) { 905 var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof")); 906 csizeof.add_argument (new CCodeIdentifier (get_ccode_name (array_type.element_type))); 907 gnew.add_argument (csizeof); 908 } 909 ccode.add_assignment (get_local_cexpression (local), gnew); 910 911 var element = new LocalVariable (array_type.element_type.copy (), "_%s_element".printf (get_ccode_name (local)), null, local.source_reference); 912 emit_temp_var (element); 913 914 if (context.profile == Profile.POSIX) { 915 cfile.add_include ("stdarg.h"); 916 } 917 918 if (!(m is CreationMethod)) { 919 ccode.add_declaration ("va_list", new CCodeVariableDeclarator ("_va_list_%s".printf (get_ccode_name (local)))); 920 var vastart = new CCodeFunctionCall (new CCodeIdentifier ("va_start")); 921 vastart.add_argument (new CCodeIdentifier ("_va_list_%s".printf (get_ccode_name (local)))); 922 vastart.add_argument (new CCodeIdentifier ("_first_%s".printf (get_ccode_name (local)))); 923 ccode.add_expression (vastart); 924 } 925 926 ccode.add_assignment (get_local_cexpression (element), new CCodeIdentifier ("_first_%s".printf (get_ccode_name (local)))); 927 ccode.open_while (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, get_local_cexpression (element), new CCodeConstant ("NULL"))); 928 929 var vaarg = new CCodeFunctionCall (new CCodeIdentifier ("va_arg")); 930 vaarg.add_argument (new CCodeIdentifier ("_va_list_%s".printf (get_ccode_name (local)))); 931 vaarg.add_argument (new CCodeIdentifier (get_ccode_name (array_type.element_type))); 932 933 var ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_array_add_wrapper (array_type))); 934 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_local_cexpression (local))); 935 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_local_cexpression (local_length))); 936 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_local_cexpression (local_size))); 937 ccall.add_argument (get_local_cexpression (element)); 938 939 ccode.add_expression (ccall); 940 ccode.add_assignment (get_local_cexpression (element), vaarg); 941 942 ccode.close (); 943 944 var vaend = new CCodeFunctionCall (new CCodeIdentifier ("va_end")); 945 vaend.add_argument (new CCodeIdentifier ("_va_list_%s".printf (get_ccode_name (local)))); 946 ccode.add_expression (vaend); 947 } 948} 949