Commit 00ff9bc4 authored by Jürg Billeter's avatar Jürg Billeter Committed by Jürg Billeter
Browse files

add dup_func parameter to generic classes, fix some memory management

2007-07-25  Juerg Billeter  <j@bitron.ch>

	* vala/valainvokable.vala, vala/valamemorymanager.vala,
	  vala/valasymbolresolver.vala, gobject/valacodegenerator.vala,
	  gobject/valacodegeneratorassignment.vala,
	  gobject/valacodegeneratorclass.vala,
	  gobject/valacodegeneratormethod.vala: add dup_func parameter to
	  generic classes, fix some memory management issues with generic types

svn path=/trunk/; revision=387
parent 02f7d056
2007-07-25 Jürg Billeter <j@bitron.ch>
* vala/valainvokable.vala, vala/valamemorymanager.vala,
vala/valasymbolresolver.vala, gobject/valacodegenerator.vala,
gobject/valacodegeneratorassignment.vala,
gobject/valacodegeneratorclass.vala,
gobject/valacodegeneratormethod.vala: add dup_func parameter to
generic classes, fix some memory management issues with generic types
2007-07-25 Jürg Billeter <j@bitron.ch>
* gobject/valacodegenerator.vala, gobject/valacodegeneratorclass.vala,
......
......@@ -879,6 +879,27 @@ public class Vala.CodeGenerator : CodeVisitor {
return decl;
}
private CCodeExpression get_dup_func_expression (TypeReference! type) {
if (type.data_type != null) {
string dup_function;
if (type.data_type.is_reference_counting ()) {
dup_function = type.data_type.get_ref_function ();
} else {
if (type.data_type != string_type.data_type) {
// duplicating non-reference counted structs may cause side-effects (and performance issues)
Report.warning (type.source_reference, "duplicating %s instance, use weak variable or explicitly invoke copy method".printf (type.data_type.name));
}
dup_function = type.data_type.get_dup_function ();
}
return new CCodeIdentifier (dup_function);
} else if (type.type_parameter != null && current_type_symbol is Class) {
string func_name = "%s_dup_func".printf (type.type_parameter.name.down ());
return new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
} else {
return new CCodeConstant ("NULL");
}
}
private CCodeExpression get_destroy_func_expression (TypeReference! type) {
if (type.data_type != null) {
string unref_function;
......@@ -2008,26 +2029,9 @@ public class Vala.CodeGenerator : CodeVisitor {
* if static type of expr is non-null
*/
if (expr.static_type.data_type == null &&
expr.static_type.type_parameter != null) {
Report.warning (expr.source_reference, "Missing generics support for memory management");
return (CCodeExpression) expr.ccodenode;
}
string ref_function;
if (expr.static_type.data_type.is_reference_counting ()) {
ref_function = expr.static_type.data_type.get_ref_function ();
} else {
if (expr.static_type.data_type != string_type.data_type) {
// duplicating non-reference counted structs may cause side-effects (and performance issues)
Report.warning (expr.source_reference, "duplicating %s instance, use weak variable or explicitly invoke copy method".printf (expr.static_type.data_type.name));
}
ref_function = expr.static_type.data_type.get_dup_function ();
}
var ccall = new CCodeFunctionCall (new CCodeIdentifier (ref_function));
var ccall = new CCodeFunctionCall (get_dup_func_expression (expr.static_type));
if (expr.static_type.non_null) {
if (expr.static_type.non_null && expr.static_type.type_parameter == null) {
ccall.add_argument ((CCodeExpression) expr.ccodenode);
return ccall;
......@@ -2038,13 +2042,22 @@ public class Vala.CodeGenerator : CodeVisitor {
var ctemp = new CCodeIdentifier (decl.name);
var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ctemp, new CCodeConstant ("NULL"));
if (expr.static_type.data_type == null) {
if (!(current_type_symbol is Class)) {
return (CCodeExpression) expr.ccodenode;
}
// dup functions are optional for type parameters
var cdupisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, get_dup_func_expression (expr.static_type), new CCodeConstant ("NULL"));
cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cisnull, cdupisnull);
}
ccall.add_argument (ctemp);
var ccomma = new CCodeCommaExpression ();
ccomma.append_expression (new CCodeAssignment (ctemp, (CCodeExpression) expr.ccodenode));
if (ref_function == "g_list_copy") {
if (expr.static_type.data_type == list_type) {
bool is_ref = false;
bool is_class = false;
bool is_interface = false;
......@@ -2066,7 +2079,15 @@ public class Vala.CodeGenerator : CodeVisitor {
}
}
ccomma.append_expression (new CCodeConditionalExpression (cisnull, new CCodeConstant ("NULL"), ccall));
CCodeExpression cifnull;
if (expr.static_type.data_type != null) {
cifnull = new CCodeConstant ("NULL");
} else {
// the value might be non-null even when the dup function is null,
// so we may not just use NULL for type parameters
cifnull = ctemp;
}
ccomma.append_expression (new CCodeConditionalExpression (cisnull, cifnull, ccall));
return ccomma;
}
......@@ -2129,9 +2150,11 @@ public class Vala.CodeGenerator : CodeVisitor {
if (expr.type_reference.data_type is Class) {
foreach (TypeReference type_arg in expr.type_reference.get_type_arguments ()) {
if (type_arg.takes_ownership) {
ccall.add_argument (get_dup_func_expression (type_arg));
ccall.add_argument (get_destroy_func_expression (type_arg));
} else {
ccall.add_argument (new CCodeConstant ("NULL"));
ccall.add_argument (new CCodeConstant ("NULL"));
}
}
}
......@@ -2141,9 +2164,6 @@ public class Vala.CodeGenerator : CodeVisitor {
int i = 1;
weak List<weak FormalParameter> params_it = params;
foreach (Expression arg in expr.get_argument_list ()) {
/* explicitly use strong reference as ccall gets
* unrefed at end of inner block
*/
CCodeExpression cexpr = (CCodeExpression) arg.ccodenode;
if (params_it != null) {
var param = (FormalParameter) params_it.data;
......
......@@ -192,9 +192,6 @@ public class Vala.CodeGenerator {
a.ccodenode = ccall;
} else {
/* explicitly use strong reference as ccast gets
* unrefed at end of inner block
*/
CCodeExpression rhs = (CCodeExpression) a.right.ccodenode;
if (a.left.static_type.data_type != null
......
......@@ -221,15 +221,37 @@ public class Vala.CodeGenerator {
init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ccast, m.name), new CCodeIdentifier (m.get_real_cname ()))));
}
/* create destroy_func properties for generic types */
/* create dup_func and destroy_func properties for generic types */
foreach (TypeParameter type_param in cl.get_type_parameters ()) {
string func_name = "%s_destroy_func".printf (type_param.name.down ());
var func_name_constant = new CCodeConstant ("\"%s-destroy-func\"".printf (type_param.name.down ()));
string enum_value = "%s_%s".printf (cl.get_lower_case_cname (null), func_name).up ();
var cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_install_property"));
string func_name, enum_value;
CCodeConstant func_name_constant;
CCodeFunctionCall cinst, cspec;
func_name = "%s_dup_func".printf (type_param.name.down ());
func_name_constant = new CCodeConstant ("\"%s-dup-func\"".printf (type_param.name.down ()));
enum_value = "%s_%s".printf (cl.get_lower_case_cname (null), func_name).up ();
cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_install_property"));
cinst.add_argument (ccall);
cinst.add_argument (new CCodeConstant (enum_value));
cspec = new CCodeFunctionCall (new CCodeIdentifier ("g_param_spec_pointer"));
cspec.add_argument (func_name_constant);
cspec.add_argument (new CCodeConstant ("\"dup func\""));
cspec.add_argument (new CCodeConstant ("\"dup func\""));
cspec.add_argument (new CCodeConstant ("G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_WRITABLE"));
cinst.add_argument (cspec);
init_block.add_statement (new CCodeExpressionStatement (cinst));
prop_enum.add_value (enum_value, null);
instance_priv_struct.add_field ("GBoxedCopyFunc", func_name);
func_name = "%s_destroy_func".printf (type_param.name.down ());
func_name_constant = new CCodeConstant ("\"%s-destroy-func\"".printf (type_param.name.down ()));
enum_value = "%s_%s".printf (cl.get_lower_case_cname (null), func_name).up ();
cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_install_property"));
cinst.add_argument (ccall);
cinst.add_argument (new CCodeConstant (enum_value));
var cspec = new CCodeFunctionCall (new CCodeIdentifier ("g_param_spec_pointer"));
cspec = new CCodeFunctionCall (new CCodeIdentifier ("g_param_spec_pointer"));
cspec.add_argument (func_name_constant);
cspec.add_argument (new CCodeConstant ("\"destroy func\""));
cspec.add_argument (new CCodeConstant ("\"destroy func\""));
......
......@@ -129,8 +129,8 @@ public class Vala.CodeGenerator {
if (m is CreationMethod && current_type_symbol is Class) {
// memory management for generic types
foreach (TypeParameter type_param in current_class.get_type_parameters ()) {
var cparam = new CCodeFormalParameter ("%s_destroy_func".printf (type_param.name.down ()), "GDestroyNotify");
function.add_parameter (cparam);
function.add_parameter (new CCodeFormalParameter ("%s_dup_func".printf (type_param.name.down ()), "GBoxedCopyFunc"));
function.add_parameter (new CCodeFormalParameter ("%s_destroy_func".printf (type_param.name.down ()), "GDestroyNotify"));
}
}
......@@ -275,11 +275,20 @@ public class Vala.CodeGenerator {
cinit.append (cdecl);
}
/* destroy func properties for generic types */
/* dup and destroy func properties for generic types */
foreach (TypeParameter type_param in current_class.get_type_parameters ()) {
string func_name = "%s_destroy_func".printf (type_param.name.down ());
var cmember = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
var cassign = new CCodeAssignment (cmember, new CCodeIdentifier (func_name));
string func_name;
CCodeMemberAccess cmember;
CCodeAssignment cassign;
func_name = "%s_dup_func".printf (type_param.name.down ());
cmember = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
cassign = new CCodeAssignment (cmember, new CCodeIdentifier (func_name));
function.block.add_statement (new CCodeExpressionStatement (cassign));
func_name = "%s_destroy_func".printf (type_param.name.down ());
cmember = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
cassign = new CCodeAssignment (cmember, new CCodeIdentifier (func_name));
function.block.add_statement (new CCodeExpressionStatement (cassign));
}
} else {
......
......@@ -25,7 +25,7 @@ using GLib;
/**
* Represents a possibly invokable code object.
*/
public interface Vala.Invokable /* : CodeNode */ {
public interface Vala.Invokable : Symbol {
/**
* Returns whether this code object is invokable.
*
......
......@@ -171,28 +171,9 @@ public class Vala.MemoryManager : CodeVisitor {
}
public override void visit_end_invocation_expression (InvocationExpression! expr) {
List<weak FormalParameter> params;
var msym = expr.call.symbol_reference;
if (msym is VariableDeclarator) {
var decl = (VariableDeclarator) msym;
var cb = (Callback) decl.type_reference.data_type;
params = cb.get_parameters ();
} else if (msym is FormalParameter) {
var param = (FormalParameter) msym;
var cb = (Callback) param.type_reference.data_type;
params = cb.get_parameters ();
} else if (msym is Field) {
var f = (Field) msym;
var cb = (Callback) f.type_reference.data_type;
params = cb.get_parameters ();
} else if (msym is Method) {
var m = (Method) msym;
params = m.get_parameters ();
} else if (msym is Signal) {
var sig = (Signal) msym;
params = sig.get_parameters ();
}
var msym = (Invokable) expr.call.symbol_reference;
List<weak FormalParameter> params = msym.get_parameters ();
weak List<weak FormalParameter> params_it = params;
foreach (Expression arg in expr.get_argument_list ()) {
if (params_it != null) {
......@@ -203,63 +184,51 @@ public class Vala.MemoryManager : CodeVisitor {
|| param.type_reference.type_parameter != null)) {
bool is_ref = param.type_reference.takes_ownership;
if (is_ref && param.type_reference.type_parameter != null) {
// TODO move this to semantic analyzer
if (expr.call is MemberAccess) {
var ma = (MemberAccess) expr.call;
TypeReference instance_type = ma.inner.static_type;
// trace type arguments back to the datatype where the method has been declared
while (instance_type.data_type != msym.parent_symbol) {
List<weak TypeReference> base_types = null;
if (instance_type.data_type is Class) {
var cl = (Class) instance_type.data_type;
base_types = cl.get_base_types ();
} else if (instance_type.data_type is Interface) {
var iface = (Interface) instance_type.data_type;
base_types = iface.get_prerequisites ();
} else {
Report.error (expr.source_reference, "internal error: unsupported generic type");
expr.error = true;
return;
}
foreach (TypeReference base_type in base_types) {
if (SemanticAnalyzer.symbol_lookup_inherited (base_type.data_type, msym.name) != null) {
// construct a new type reference for the base type with correctly linked type arguments
var instance_base_type = new TypeReference ();
instance_base_type.data_type = base_type.data_type;
foreach (TypeReference type_arg in base_type.get_type_arguments ()) {
if (type_arg.type_parameter != null) {
// link to type argument of derived type
int param_index = instance_type.data_type.get_type_parameter_index (type_arg.type_parameter.name);
if (param_index == -1) {
Report.error (expr.source_reference, "internal error: unknown type parameter %s".printf (type_arg.type_parameter.name));
expr.error = true;
return;
}
type_arg = instance_type.get_type_arguments ().nth_data (param_index);
}
instance_base_type.add_type_argument (type_arg);
}
instance_type = instance_base_type;
}
}
}
if (instance_type.data_type != msym.parent_symbol) {
Report.error (expr.source_reference, "internal error: generic type parameter tracing not supported yet");
expr.error = true;
return;
}
int param_index = instance_type.data_type.get_type_parameter_index (param.type_reference.type_parameter.name);
if (param_index == -1) {
Report.error (expr.source_reference, "internal error: unknown type parameter %s".printf (param.type_reference.type_parameter.name));
expr.error = true;
return;
}
var param_type = (TypeReference) instance_type.get_type_arguments ().nth_data (param_index);
if (param_type == null) {
Report.error (expr.source_reference, "internal error: no actual argument found for type parameter %s".printf (param.type_reference.type_parameter.name));
expr.error = true;
return;
var param_type = get_actual_type (ma.inner.static_type, msym, param.type_reference.type_parameter, expr);
if (param_type != null) {
is_ref = param_type.takes_ownership;
}
}
}
if (is_ref) {
visit_possibly_missing_copy_expression (arg);
} else {
visit_possibly_leaked_expression (arg);
}
} else {
visit_possibly_leaked_expression (arg);
}
params_it = params_it.next;
} else {
visit_possibly_leaked_expression (arg);
}
}
}
public override void visit_end_object_creation_expression (ObjectCreationExpression! expr) {
if (!(expr.symbol_reference is Invokable)) {
return;
}
var msym = (Invokable) expr.symbol_reference;
List<weak FormalParameter> params = msym.get_parameters ();
weak List<weak FormalParameter> params_it = params;
foreach (Expression arg in expr.get_argument_list ()) {
if (params_it != null) {
var param = (FormalParameter) params_it.data;
if (!param.ellipsis
&& ((param.type_reference.data_type != null
&& param.type_reference.data_type.is_reference_type ())
|| param.type_reference.type_parameter != null)) {
bool is_ref = param.type_reference.takes_ownership;
if (is_ref && param.type_reference.type_parameter != null) {
var param_type = get_actual_type (expr.type_reference, msym, param.type_reference.type_parameter, expr);
if (param_type != null) {
is_ref = param_type.takes_ownership;
}
}
......@@ -280,6 +249,64 @@ public class Vala.MemoryManager : CodeVisitor {
}
}
private TypeReference get_actual_type (TypeReference instance_type, Symbol generic_member, TypeParameter type_parameter, CodeNode node_reference) {
// trace type arguments back to the datatype where the method has been declared
// TODO move this to semantic analyzer
while (instance_type.data_type != generic_member.parent_symbol) {
List<weak TypeReference> base_types = null;
if (instance_type.data_type is Class) {
var cl = (Class) instance_type.data_type;
base_types = cl.get_base_types ();
} else if (instance_type.data_type is Interface) {
var iface = (Interface) instance_type.data_type;
base_types = iface.get_prerequisites ();
} else {
Report.error (node_reference.source_reference, "internal error: unsupported generic type");
node_reference.error = true;
return null;
}
foreach (TypeReference base_type in base_types) {
if (SemanticAnalyzer.symbol_lookup_inherited (base_type.data_type, generic_member.name) != null) {
// construct a new type reference for the base type with correctly linked type arguments
var instance_base_type = new TypeReference ();
instance_base_type.data_type = base_type.data_type;
foreach (TypeReference type_arg in base_type.get_type_arguments ()) {
if (type_arg.type_parameter != null) {
// link to type argument of derived type
int param_index = instance_type.data_type.get_type_parameter_index (type_arg.type_parameter.name);
if (param_index == -1) {
Report.error (node_reference.source_reference, "internal error: unknown type parameter %s".printf (type_arg.type_parameter.name));
node_reference.error = true;
return null;
}
type_arg = instance_type.get_type_arguments ().nth_data (param_index);
}
instance_base_type.add_type_argument (type_arg);
}
instance_type = instance_base_type;
}
}
}
if (instance_type.data_type != generic_member.parent_symbol) {
Report.error (node_reference.source_reference, "internal error: generic type parameter tracing not supported yet");
node_reference.error = true;
return null;
}
int param_index = instance_type.data_type.get_type_parameter_index (type_parameter.name);
if (param_index == -1) {
Report.error (node_reference.source_reference, "internal error: unknown type parameter %s".printf (type_parameter.name));
node_reference.error = true;
return null;
}
var param_type = (TypeReference) instance_type.get_type_arguments ().nth_data (param_index);
if (param_type == null) {
Report.error (node_reference.source_reference, "internal error: no actual argument found for type parameter %s".printf (type_parameter.name));
node_reference.error = true;
return null;
}
return param_type;
}
public override void visit_binary_expression (BinaryExpression! expr) {
visit_possibly_leaked_expression (expr.left);
visit_possibly_leaked_expression (expr.right);
......
......@@ -268,6 +268,7 @@ public class Vala.SymbolResolver : CodeVisitor {
}
type.data_type = element_type.data_type.get_array (type.array_rank);
} else {
element_type.takes_ownership = type.takes_ownership;
type.data_type = element_type.type_parameter.get_array (type.array_rank);
type.type_parameter = null;
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment