From: Jürg Billeter Date: Sat, 26 Jun 2010 16:02:37 +0000 (+0200) Subject: dova: Add support for closures X-Git-Tag: 0.9.3~94 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=9d89bd50cff087c209b003cd7dff668bf973f137;p=thirdparty%2Fvala.git dova: Add support for closures --- diff --git a/codegen/valadovabasemodule.vala b/codegen/valadovabasemodule.vala index a0b2641b0..77befcc80 100644 --- a/codegen/valadovabasemodule.vala +++ b/codegen/valadovabasemodule.vala @@ -89,6 +89,29 @@ internal class Vala.DovaBaseModule : CCodeModule { } } + public Block? current_closure_block { + get { + return next_closure_block (current_symbol); + } + } + + public unowned Block? next_closure_block (Symbol sym) { + unowned Block block = null; + while (true) { + block = sym as Block; + if (!(sym is Block || sym is Method)) { + // no closure block + break; + } + if (block != null && block.captured) { + // closure block found + break; + } + sym = sym.parent_symbol; + } + return block; + } + public CCodeDeclarationSpace header_declarations; public CCodeDeclarationSpace internal_header_declarations; public CCodeDeclarationSpace source_declarations; @@ -112,6 +135,8 @@ internal class Vala.DovaBaseModule : CCodeModule { public int next_string_const_id = 0; public bool in_creation_method { get { return current_method is CreationMethod; } } public bool current_method_inner_error = false; + int next_block_id = 0; + Map block_map = new HashMap (); public DataType void_type = new VoidType (); public DataType bool_type; @@ -643,6 +668,44 @@ internal class Vala.DovaBaseModule : CCodeModule { current_method_inner_error = old_method_inner_error; } + public int get_block_id (Block b) { + int result = block_map[b]; + if (result == 0) { + result = ++next_block_id; + block_map[b] = result; + } + return result; + } + + void capture_parameter (FormalParameter param, CCodeStruct data, CCodeBlock cblock, int block_id, CCodeBlock free_block) { + generate_type_declaration (param.parameter_type, source_declarations); + + var param_type = param.parameter_type.copy (); + param_type.value_owned = true; + data.add_field (param_type.get_cname (), get_variable_cname (param.name)); + + // create copy if necessary as captured variables may need to be kept alive + CCodeExpression cparam = get_variable_cexpression (param.name); + if (requires_copy (param_type) && !param.parameter_type.value_owned) { + var ma = new MemberAccess.simple (param.name); + ma.symbol_reference = param; + ma.value_type = param.parameter_type.copy (); + // directly access parameters in ref expressions + param.captured = false; + cparam = get_ref_cexpression (param.parameter_type, cparam, ma, param); + param.captured = true; + } + + cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), get_variable_cname (param.name)), cparam))); + + if (requires_destroy (param_type)) { + var ma = new MemberAccess.simple (param.name); + ma.symbol_reference = param; + ma.value_type = param_type.copy (); + free_block.add_statement (new CCodeExpressionStatement (get_unref_expression (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), get_variable_cname (param.name)), param.parameter_type, ma))); + } + } + public override void visit_block (Block b) { var old_symbol = current_symbol; current_symbol = b; @@ -656,6 +719,154 @@ internal class Vala.DovaBaseModule : CCodeModule { var cblock = new CCodeBlock (); + + if (b.captured) { + var parent_block = next_closure_block (b.parent_symbol); + + int block_id = get_block_id (b); + string struct_name = "Block%dData".printf (block_id); + + var free_block = new CCodeBlock (); + + var data = new CCodeStruct ("_" + struct_name); + data.add_field ("DovaType*", "type"); + data.add_field ("int", "_ref_count_"); + if (parent_block != null) { + int parent_block_id = get_block_id (parent_block); + + data.add_field ("Block%dData *".printf (parent_block_id), "_data%d_".printf (parent_block_id)); + + var unref_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_object_unref")); + unref_call.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_data%d_".printf (parent_block_id))); + free_block.add_statement (new CCodeExpressionStatement (unref_call)); + } else if ((current_method != null && current_method.binding == MemberBinding.INSTANCE) || + (current_property_accessor != null && current_property_accessor.prop.binding == MemberBinding.INSTANCE)) { + data.add_field ("%s *".printf (current_class.get_cname ()), "this"); + + var ma = new MemberAccess.simple ("this"); + ma.symbol_reference = current_class; + free_block.add_statement (new CCodeExpressionStatement (get_unref_expression (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "this"), new ObjectType (current_class), ma))); + } + foreach (var local in local_vars) { + if (local.captured) { + generate_type_declaration (local.variable_type, source_declarations); + + data.add_field (local.variable_type.get_cname (), get_variable_cname (local.name) + local.variable_type.get_cdeclarator_suffix ()); + + if (requires_destroy (local.variable_type)) { + var ma = new MemberAccess.simple (local.name); + ma.symbol_reference = local; + ma.value_type = local.variable_type.copy (); + free_block.add_statement (new CCodeExpressionStatement (get_unref_expression (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), get_variable_cname (local.name)), local.variable_type, ma))); + } + } + } + + var data_alloc = new CCodeFunctionCall (new CCodeIdentifier ("dova_object_alloc")); + data_alloc.add_argument (new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_type_get".printf (block_id)))); + + var data_decl = new CCodeDeclaration (struct_name + "*"); + data_decl.add_declarator (new CCodeVariableDeclarator ("_data%d_".printf (block_id), data_alloc)); + cblock.add_statement (data_decl); + + if (parent_block != null) { + int parent_block_id = get_block_id (parent_block); + + var ref_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_object_ref")); + ref_call.add_argument (get_variable_cexpression ("_data%d_".printf (parent_block_id))); + + cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), "_data%d_".printf (parent_block_id)), ref_call))); + } else if ((current_method != null && current_method.binding == MemberBinding.INSTANCE && + (!(current_method is CreationMethod) || current_method.body != b)) || + (current_property_accessor != null && current_property_accessor.prop.binding == MemberBinding.INSTANCE)) { + var ref_call = new CCodeFunctionCall (get_dup_func_expression (new ObjectType (current_class), b.source_reference)); + ref_call.add_argument (new CCodeIdentifier ("this")); + + cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), "this"), ref_call))); + } + + if (b.parent_symbol is Method) { + var m = (Method) b.parent_symbol; + + // parameters are captured with the top-level block of the method + foreach (var param in m.get_parameters ()) { + if (param.captured) { + capture_parameter (param, data, cblock, block_id, free_block); + } + } + + var cfrag = new CCodeFragment (); + append_temp_decl (cfrag, temp_vars); + temp_vars.clear (); + cblock.add_statement (cfrag); + } else if (b.parent_symbol is PropertyAccessor) { + var acc = (PropertyAccessor) b.parent_symbol; + + if (!acc.readable && acc.value_parameter.captured) { + capture_parameter (acc.value_parameter, data, cblock, block_id, free_block); + } + + var cfrag = new CCodeFragment (); + append_temp_decl (cfrag, temp_vars); + temp_vars.clear (); + cblock.add_statement (cfrag); + } + + var typedef = new CCodeTypeDefinition ("struct _" + struct_name, new CCodeVariableDeclarator (struct_name)); + source_declarations.add_type_declaration (typedef); + source_declarations.add_type_definition (data); + + var data_free = new CCodeFunctionCall (new CCodeIdentifier ("free")); + data_free.add_argument (new CCodeIdentifier ("_data%d_".printf (block_id))); + free_block.add_statement (new CCodeExpressionStatement (data_free)); + + // create type_get/finalize functions + var type_get_fun = new CCodeFunction ("block%d_data_type_get".printf (block_id), "DovaType*"); + type_get_fun.modifiers = CCodeModifiers.STATIC; + source_declarations.add_type_member_declaration (type_get_fun.copy ()); + type_get_fun.block = new CCodeBlock (); + + var cdecl = new CCodeDeclaration ("int"); + cdecl.add_declarator (new CCodeVariableDeclarator ("_block%d_data_object_offset".printf (block_id), new CCodeConstant ("0"))); + cdecl.modifiers = CCodeModifiers.STATIC; + source_declarations.add_type_member_declaration (cdecl); + + cdecl = new CCodeDeclaration ("int"); + cdecl.add_declarator (new CCodeVariableDeclarator ("_block%d_data_type_offset".printf (block_id), new CCodeConstant ("0"))); + cdecl.modifiers = CCodeModifiers.STATIC; + source_declarations.add_type_member_declaration (cdecl); + + cdecl = new CCodeDeclaration ("DovaType *"); + cdecl.add_declarator (new CCodeVariableDeclarator ("block%d_data_type".printf (block_id), new CCodeConstant ("NULL"))); + cdecl.modifiers = CCodeModifiers.STATIC; + source_declarations.add_type_member_declaration (cdecl); + + var type_init_block = new CCodeBlock (); + var alloc_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_alloc")); + alloc_call.add_argument (new CCodeFunctionCall (new CCodeIdentifier ("dova_object_type_get"))); + alloc_call.add_argument (new CCodeConstant ("sizeof (%s)".printf (struct_name))); + alloc_call.add_argument (new CCodeConstant ("0")); + alloc_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("block%d_data_type".printf (block_id)))); + alloc_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_block%d_data_object_offset".printf (block_id)))); + alloc_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_block%d_data_type_offset".printf (block_id)))); + type_init_block.add_statement (new CCodeExpressionStatement (alloc_call)); + var type_init_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_object_type_init")); + type_init_call.add_argument (new CCodeIdentifier ("block%d_data_type".printf (block_id))); + type_init_block.add_statement (new CCodeExpressionStatement (type_init_call)); + type_get_fun.block.add_statement (new CCodeIfStatement (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("block%d_data_type".printf (block_id))), type_init_block)); + type_get_fun.block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("block%d_data_type".printf (block_id)))); + + source_type_member_definition.append (type_get_fun); + + var unref_fun = new CCodeFunction ("block%d_data_finalize".printf (block_id), "void"); + unref_fun.add_parameter (new CCodeFormalParameter ("_data%d_".printf (block_id), struct_name + "*")); + unref_fun.modifiers = CCodeModifiers.STATIC; + source_declarations.add_type_member_declaration (unref_fun.copy ()); + unref_fun.block = free_block; + + source_type_member_definition.append (unref_fun); + } + foreach (CodeNode stmt in b.get_statements ()) { if (stmt.error) { continue; @@ -671,7 +882,7 @@ internal class Vala.DovaBaseModule : CCodeModule { } foreach (LocalVariable local in local_vars) { - if (!local.floating && requires_destroy (local.variable_type)) { + if (!local.floating && !local.captured && requires_destroy (local.variable_type)) { var ma = new MemberAccess.simple (local.name); ma.symbol_reference = local; cblock.add_statement (new CCodeExpressionStatement (get_unref_expression (get_variable_cexpression (local.name), local.variable_type, ma))); @@ -681,7 +892,7 @@ internal class Vala.DovaBaseModule : CCodeModule { if (b.parent_symbol is Method) { var m = (Method) b.parent_symbol; foreach (FormalParameter param in m.get_parameters ()) { - if (requires_destroy (param.parameter_type) && param.direction == ParameterDirection.IN) { + if (!param.captured && requires_destroy (param.parameter_type) && param.direction == ParameterDirection.IN) { var ma = new MemberAccess.simple (param.name); ma.symbol_reference = param; cblock.add_statement (new CCodeExpressionStatement (get_unref_expression (get_variable_cexpression (param.name), param.parameter_type, ma))); @@ -689,6 +900,14 @@ internal class Vala.DovaBaseModule : CCodeModule { } } + if (b.captured) { + int block_id = get_block_id (b); + + var data_unref = new CCodeFunctionCall (new CCodeIdentifier ("dova_object_unref")); + data_unref.add_argument (get_variable_cexpression ("_data%d_".printf (block_id))); + cblock.add_statement (new CCodeExpressionStatement (data_unref)); + } + b.ccodenode = cblock; current_symbol = old_symbol; @@ -748,17 +967,23 @@ internal class Vala.DovaBaseModule : CCodeModule { pre_statement_fragment = null; } - var cvar = new CCodeVariableDeclarator (get_variable_cname (local.name), rhs, local.variable_type.get_cdeclarator_suffix ()); + if (local.captured) { + if (local.initializer != null) { + cfrag.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id ((Block) local.parent_symbol))), get_variable_cname (local.name)), rhs))); + } + } else { + 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); - cfrag.append (cdecl); + var cdecl = new CCodeDeclaration (local.variable_type.get_cname ()); + cdecl.add_declarator (cvar); + cfrag.append (cdecl); - // try to initialize uninitialized variables - // initialization not necessary for variables stored in closure - if (cvar.initializer == null) { - cvar.initializer = default_value_for_type (local.variable_type, true); - cvar.init0 = true; + // try to initialize uninitialized variables + // initialization not necessary for variables stored in closure + if (cvar.initializer == null) { + cvar.initializer = default_value_for_type (local.variable_type, true); + cvar.init0 = true; + } } if (local.initializer != null && local.initializer.tree_can_fail) { @@ -1162,13 +1387,21 @@ internal class Vala.DovaBaseModule : CCodeModule { var local_vars = b.get_local_variables (); foreach (LocalVariable local in local_vars) { - if (local.active && !local.floating && requires_destroy (local.variable_type)) { + if (local.active && !local.floating && !local.captured && requires_destroy (local.variable_type)) { var ma = new MemberAccess.simple (local.name); ma.symbol_reference = local; cfrag.append (new CCodeExpressionStatement (get_unref_expression (get_variable_cexpression (local.name), local.variable_type, ma))); } } + if (b.captured) { + int block_id = get_block_id (b); + + var data_unref = new CCodeFunctionCall (new CCodeIdentifier ("dova_object_unref")); + data_unref.add_argument (get_variable_cexpression ("_data%d_".printf (block_id))); + cfrag.append (new CCodeExpressionStatement (data_unref)); + } + if (stop_at_loop) { if (b.parent_node is Loop || b.parent_node is ForeachStatement || @@ -1189,13 +1422,21 @@ internal class Vala.DovaBaseModule : CCodeModule { var local_vars = b.get_local_variables (); foreach (LocalVariable local in local_vars) { - if (local.active && !local.floating && requires_destroy (local.variable_type)) { + if (local.active && !local.floating && !local.captured && requires_destroy (local.variable_type)) { var ma = new MemberAccess.simple (local.name); ma.symbol_reference = local; cfrag.append (new CCodeExpressionStatement (get_unref_expression (get_variable_cexpression (local.name), local.variable_type, ma))); } } + if (b.captured) { + int block_id = get_block_id (b); + + var data_unref = new CCodeFunctionCall (new CCodeIdentifier ("dova_object_unref")); + data_unref.add_argument (get_variable_cexpression ("_data%d_".printf (block_id))); + cfrag.append (new CCodeExpressionStatement (data_unref)); + } + if (sym == current_try.body) { return; } @@ -1995,8 +2236,20 @@ internal class Vala.DovaBaseModule : CCodeModule { var method_type = (MethodType) expression_type; CCodeExpression delegate_target = new CCodeConstant ("NULL"); if (method_type.method_symbol.binding == MemberBinding.INSTANCE) { - var ma = (MemberAccess) expr; - delegate_target = (CCodeExpression) get_ccodenode (ma.inner); + if (expr is LambdaExpression) { + var lambda = (LambdaExpression) expr; + if (lambda.method.closure) { + int block_id = get_block_id (current_closure_block); + delegate_target = get_variable_cexpression ("_data%d_".printf (block_id)); + } else if (get_this_type () != null) { + delegate_target = new CCodeIdentifier ("this"); + } else { + delegate_target = new CCodeConstant ("NULL"); + } + } else { + var ma = (MemberAccess) expr; + delegate_target = (CCodeExpression) get_ccodenode (ma.inner); + } } var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_new".printf (deleg_type.delegate_symbol.get_lower_case_cname ()))); ccall.add_argument (delegate_target); @@ -2132,6 +2385,15 @@ internal class Vala.DovaBaseModule : CCodeModule { public override void visit_class (Class cl) { } + public DataType? get_this_type () { + if (current_method != null && current_method.binding == MemberBinding.INSTANCE) { + return current_method.this_parameter.parameter_type; + } else if (current_property_accessor != null && current_property_accessor.prop.binding == MemberBinding.INSTANCE) { + return current_property_accessor.prop.this_parameter.parameter_type; + } + return null; + } + public CCodeFunctionCall generate_instance_cast (CCodeExpression expr, TypeSymbol type) { var result = new CCodeFunctionCall (new CCodeIdentifier (type.get_upper_case_cname (null))); result.add_argument (expr); diff --git a/codegen/valadovamemberaccessmodule.vala b/codegen/valadovamemberaccessmodule.vala index 8bc36c7e5..8a3ade78a 100644 --- a/codegen/valadovamemberaccessmodule.vala +++ b/codegen/valadovamemberaccessmodule.vala @@ -1,6 +1,6 @@ /* valadovamemberaccessmodule.vala * - * Copyright (C) 2006-2009 Jürg Billeter + * Copyright (C) 2006-2010 Jürg Billeter * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -204,6 +204,10 @@ internal class Vala.DovaMemberAccessModule : DovaControlFlowModule { if (local.is_result) { // used in postconditions expr.ccodenode = new CCodeIdentifier ("result"); + } else if (local.captured) { + // captured variables are stored on the heap + var block = (Block) local.parent_symbol; + expr.ccodenode = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_variable_cname (local.name)); } else { expr.ccodenode = get_variable_cexpression (local.name); } @@ -222,29 +226,38 @@ internal class Vala.DovaMemberAccessModule : DovaControlFlowModule { } } } else { - if (current_method != null && current_method.coroutine) { - // use closure - expr.ccodenode = get_variable_cexpression (p.name); + if (p.captured) { + // captured variables are stored on the heap + var block = p.parent_symbol as Block; + if (block == null) { + block = ((Method) p.parent_symbol).body; + } + expr.ccodenode = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_variable_cname (p.name)); } else { - var type_as_struct = p.parameter_type.data_type as Struct; - if (p.direction != ParameterDirection.IN - || (type_as_struct != null && !type_as_struct.is_simple_type () && !p.parameter_type.nullable)) { - if (p.parameter_type is GenericType) { - expr.ccodenode = get_variable_cexpression (p.name); - } else { - expr.ccodenode = new CCodeIdentifier ("(*%s)".printf (get_variable_cname (p.name))); - } + if (current_method != null && current_method.coroutine) { + // use closure + expr.ccodenode = get_variable_cexpression (p.name); } else { - // Property setters of non simple structs shall replace all occurences - // of the "value" formal parameter with a dereferencing version of that - // parameter. - if (current_property_accessor != null && - current_property_accessor.writable && - current_property_accessor.value_parameter == p && - current_property_accessor.prop.property_type.is_real_struct_type ()) { - expr.ccodenode = new CCodeIdentifier ("(*value)"); + var type_as_struct = p.parameter_type.data_type as Struct; + if (p.direction != ParameterDirection.IN + || (type_as_struct != null && !type_as_struct.is_simple_type () && !p.parameter_type.nullable)) { + if (p.parameter_type is GenericType) { + expr.ccodenode = get_variable_cexpression (p.name); + } else { + expr.ccodenode = new CCodeIdentifier ("(*%s)".printf (get_variable_cname (p.name))); + } } else { - expr.ccodenode = get_variable_cexpression (p.name); + // Property setters of non simple structs shall replace all occurences + // of the "value" formal parameter with a dereferencing version of that + // parameter. + if (current_property_accessor != null && + current_property_accessor.writable && + current_property_accessor.value_parameter == p && + current_property_accessor.prop.property_type.is_real_struct_type ()) { + expr.ccodenode = new CCodeIdentifier ("(*value)"); + } else { + expr.ccodenode = get_variable_cexpression (p.name); + } } } } diff --git a/codegen/valadovaobjectmodule.vala b/codegen/valadovaobjectmodule.vala index f6bf31373..8c8edfe5b 100644 --- a/codegen/valadovaobjectmodule.vala +++ b/codegen/valadovaobjectmodule.vala @@ -1153,6 +1153,38 @@ internal class Vala.DovaObjectModule : DovaArrayModule { var cinit = new CCodeFragment (); function.block.prepend_statement (cinit); + if (m.closure) { + // add variables for parent closure blocks + // as closures only have one parameter for the innermost closure block + var closure_block = current_closure_block; + int block_id = get_block_id (closure_block); + while (true) { + var parent_closure_block = next_closure_block (closure_block.parent_symbol); + if (parent_closure_block == null) { + break; + } + int parent_block_id = get_block_id (parent_closure_block); + + var parent_data = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_data%d_".printf (parent_block_id)); + var cdecl = new CCodeDeclaration ("Block%dData*".printf (parent_block_id)); + cdecl.add_declarator (new CCodeVariableDeclarator ("_data%d_".printf (parent_block_id), parent_data)); + + cinit.append (cdecl); + + closure_block = parent_closure_block; + block_id = parent_block_id; + } + + // add self variable for closures + // as closures have block data parameter + if (m.binding == MemberBinding.INSTANCE) { + var cself = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "this"); + var cdecl = new CCodeDeclaration ("%s *".printf (current_class.get_cname ())); + cdecl.add_declarator (new CCodeVariableDeclarator ("this", cself)); + + cinit.append (cdecl); + } + } foreach (FormalParameter param in m.get_parameters ()) { if (param.ellipsis) { break; @@ -1462,7 +1494,11 @@ internal class Vala.DovaObjectModule : DovaArrayModule { public override void generate_cparameters (Method m, CCodeDeclarationSpace decl_space, CCodeFunction func, CCodeFunctionDeclarator? vdeclarator = null, CCodeFunctionCall? vcall = null) { CCodeFormalParameter instance_param = null; - if (m.parent_symbol is Class && m is CreationMethod) { + if (m.closure) { + var closure_block = current_closure_block; + int block_id = get_block_id (closure_block); + instance_param = new CCodeFormalParameter ("_data%d_".printf (block_id), "Block%dData*".printf (block_id)); + } else if (m.parent_symbol is Class && m is CreationMethod) { if (vcall == null) { instance_param = new CCodeFormalParameter ("this", ((Class) m.parent_symbol).get_cname () + "*"); }