[vala] Fix handling of owned delegates
- From: Jürg Billeter <juergbi src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [vala] Fix handling of owned delegates
- Date: Sat, 19 Sep 2009 10:12:28 +0000 (UTC)
commit da66e781f50698939544098c8efc00ee5fe817dd
Author: Jürg Billeter <j bitron ch>
Date: Sat Sep 19 11:15:27 2009 +0200
Fix handling of owned delegates
Fixes bug 595639.
codegen/valaccodebasemodule.vala | 37 +++++++++++++++++++++++-
codegen/valaccodedelegatemodule.vala | 43 +++++++++++++++++++++++-----
codegen/valaccodemethodcallmodule.vala | 2 +-
codegen/valagtypemodule.vala | 6 ++++
vala/valadelegatetype.vala | 4 +++
vala/valamemberaccess.vala | 8 +++++
vala/valareferencetransferexpression.vala | 8 +++++
7 files changed, 97 insertions(+), 11 deletions(-)
---
diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala
index d3caef8..2b804c4 100644
--- a/codegen/valaccodebasemodule.vala
+++ b/codegen/valaccodebasemodule.vala
@@ -1033,6 +1033,7 @@ internal class Vala.CCodeBaseModule : CCodeModule {
var ma = new MemberAccess (this_access, f.name);
ma.symbol_reference = f;
+ ma.value_type = f.field_type.copy ();
instance_finalize_fragment.append (new CCodeExpressionStatement (get_unref_expression (lhs, f.field_type, ma)));
}
} else if (f.binding == MemberBinding.CLASS) {
@@ -1676,6 +1677,7 @@ internal class Vala.CCodeBaseModule : CCodeModule {
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)));
}
}
@@ -1722,11 +1724,14 @@ internal class Vala.CCodeBaseModule : CCodeModule {
param_type.value_owned = true;
data.add_field (param_type.get_cname (), get_variable_cname (param.name));
+ bool is_unowned_delegate = param.parameter_type is DelegateType && !param.parameter_type.value_owned;
+
// 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) {
+ if (requires_copy (param_type) && !param.parameter_type.value_owned && !is_unowned_delegate) {
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);
@@ -1750,9 +1755,10 @@ internal class Vala.CCodeBaseModule : CCodeModule {
}
}
- if (requires_destroy (param_type)) {
+ if (requires_destroy (param_type) && !is_unowned_delegate) {
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)));
}
}
@@ -1807,6 +1813,7 @@ internal class Vala.CCodeBaseModule : CCodeModule {
if (!local.floating && !local.captured && requires_destroy (local.variable_type)) {
var ma = new MemberAccess.simple (local.name);
ma.symbol_reference = local;
+ ma.value_type = local.variable_type.copy ();
cblock.add_statement (new CCodeExpressionStatement (get_unref_expression (get_variable_cexpression (local.name), local.variable_type, ma)));
}
}
@@ -1817,6 +1824,7 @@ internal class Vala.CCodeBaseModule : CCodeModule {
if (!param.captured && requires_destroy (param.parameter_type) && param.direction == ParameterDirection.IN) {
var ma = new MemberAccess.simple (param.name);
ma.symbol_reference = param;
+ ma.value_type = param.parameter_type.copy ();
cblock.add_statement (new CCodeExpressionStatement (get_unref_expression (get_variable_cexpression (param.name), param.parameter_type, ma)));
}
}
@@ -2425,6 +2433,24 @@ internal class Vala.CCodeBaseModule : CCodeModule {
}
public virtual CCodeExpression get_unref_expression (CCodeExpression cvar, DataType type, Expression expr, bool is_macro_definition = false) {
+ if (type is DelegateType) {
+ CCodeExpression delegate_target_destroy_notify;
+ var delegate_target = get_delegate_target_cexpression (expr, out delegate_target_destroy_notify);
+
+ var ccall = new CCodeFunctionCall (delegate_target_destroy_notify);
+ ccall.add_argument (delegate_target);
+
+ var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, delegate_target_destroy_notify, new CCodeConstant ("NULL"));
+
+ var ccomma = new CCodeCommaExpression ();
+ ccomma.append_expression (new CCodeConditionalExpression (cisnull, new CCodeConstant ("NULL"), ccall));
+ ccomma.append_expression (new CCodeAssignment (cvar, new CCodeConstant ("NULL")));
+ ccomma.append_expression (new CCodeAssignment (delegate_target, new CCodeConstant ("NULL")));
+ ccomma.append_expression (new CCodeAssignment (delegate_target_destroy_notify, new CCodeConstant ("NULL")));
+
+ return ccomma;
+ }
+
var ccall = new CCodeFunctionCall (get_destroy_func_expression (type));
if (type is ValueType && !type.nullable) {
@@ -2573,6 +2599,7 @@ internal class Vala.CCodeBaseModule : CCodeModule {
foreach (LocalVariable local in temp_ref_vars) {
var ma = new MemberAccess.simple (local.name);
ma.symbol_reference = local;
+ ma.value_type = local.variable_type.copy ();
expr_list.append_expression (get_unref_expression (get_variable_cexpression (local.name), local.variable_type, ma));
}
@@ -2702,6 +2729,7 @@ internal class Vala.CCodeBaseModule : CCodeModule {
if (local.active && !local.floating && !local.captured && requires_destroy (local.variable_type)) {
var ma = new MemberAccess.simple (local.name);
ma.symbol_reference = local;
+ ma.value_type = local.variable_type.copy ();
cfrag.append (new CCodeExpressionStatement (get_unref_expression (get_variable_cexpression (local.name), local.variable_type, ma)));
}
}
@@ -2757,6 +2785,7 @@ internal class Vala.CCodeBaseModule : CCodeModule {
if (requires_destroy (param.parameter_type) && param.direction == ParameterDirection.IN) {
var ma = new MemberAccess.simple (param.name);
ma.symbol_reference = param;
+ ma.value_type = param.parameter_type.copy ();
cfrag.append (new CCodeExpressionStatement (get_unref_expression (get_variable_cexpression (param.name), param.parameter_type, ma)));
}
}
@@ -3184,6 +3213,10 @@ internal class Vala.CCodeBaseModule : CCodeModule {
}
public virtual CCodeExpression? get_ref_cexpression (DataType expression_type, CCodeExpression cexpr, Expression? expr, CodeNode node) {
+ if (expression_type is DelegateType) {
+ return cexpr;
+ }
+
if (expression_type is ValueType && !expression_type.nullable) {
// normal value type, no null check
// (copy (&expr, &temp), temp)
diff --git a/codegen/valaccodedelegatemodule.vala b/codegen/valaccodedelegatemodule.vala
index 8611b0a..eb91e2d 100644
--- a/codegen/valaccodedelegatemodule.vala
+++ b/codegen/valaccodedelegatemodule.vala
@@ -135,6 +135,13 @@ internal class Vala.CCodeDelegateModule : CCodeArrayModule {
is_out = true;
}
}
+
+ bool expr_owned = delegate_expr.value_type.value_owned;
+
+ if (delegate_expr is ReferenceTransferExpression) {
+ var reftransfer_expr = (ReferenceTransferExpression) delegate_expr;
+ delegate_expr = reftransfer_expr.inner;
+ }
if (delegate_expr is MethodCall) {
var invocation_expr = (MethodCall) delegate_expr;
@@ -147,7 +154,7 @@ internal class Vala.CCodeDelegateModule : CCodeArrayModule {
if (closure_block != null) {
int block_id = get_block_id (closure_block);
var delegate_target = get_variable_cexpression ("_data%d_".printf (block_id));
- if (delegate_expr.value_type.value_owned) {
+ if (expr_owned) {
var ref_call = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_ref".printf (block_id)));
ref_call.add_argument (delegate_target);
delegate_target = ref_call;
@@ -156,7 +163,7 @@ internal class Vala.CCodeDelegateModule : CCodeArrayModule {
return delegate_target;
} else if (get_this_type () != null || in_constructor) {
CCodeExpression delegate_target = new CCodeIdentifier ("self");
- if (delegate_expr.value_type.value_owned) {
+ if (expr_owned) {
if (get_this_type () != null) {
var ref_call = new CCodeFunctionCall (get_dup_func_expression (get_this_type (), delegate_expr.source_reference));
ref_call.add_argument (delegate_target);
@@ -187,15 +194,21 @@ internal class Vala.CCodeDelegateModule : CCodeArrayModule {
return new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), get_delegate_target_cname (get_variable_cname (param.name)));
} else {
CCodeExpression target_expr = new CCodeIdentifier (get_delegate_target_cname (get_variable_cname (param.name)));
- delegate_target_destroy_notify = new CCodeIdentifier (get_delegate_target_destroy_notify_cname (get_variable_cname (param.name)));
+ if (expr_owned) {
+ delegate_target_destroy_notify = new CCodeIdentifier (get_delegate_target_destroy_notify_cname (get_variable_cname (param.name)));
+ }
if (param.direction != ParameterDirection.IN) {
// accessing argument of out/ref param
target_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, target_expr);
- delegate_target_destroy_notify = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, delegate_target_destroy_notify);
+ if (expr_owned) {
+ delegate_target_destroy_notify = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, delegate_target_destroy_notify);
+ }
}
if (is_out) {
// passing delegate as out/ref
- delegate_target_destroy_notify = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, delegate_target_destroy_notify);
+ if (expr_owned) {
+ delegate_target_destroy_notify = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, delegate_target_destroy_notify);
+ }
return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, target_expr);
} else {
return target_expr;
@@ -213,9 +226,13 @@ internal class Vala.CCodeDelegateModule : CCodeArrayModule {
return new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), get_delegate_target_cname (get_variable_cname (local.name)));
} else {
var target_expr = new CCodeIdentifier (get_delegate_target_cname (get_variable_cname (local.name)));
- delegate_target_destroy_notify = new CCodeIdentifier (get_delegate_target_destroy_notify_cname (get_variable_cname (local.name)));
+ if (expr_owned) {
+ delegate_target_destroy_notify = new CCodeIdentifier (get_delegate_target_destroy_notify_cname (get_variable_cname (local.name)));
+ }
if (is_out) {
- delegate_target_destroy_notify = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, delegate_target_destroy_notify);
+ if (expr_owned) {
+ delegate_target_destroy_notify = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, delegate_target_destroy_notify);
+ }
return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, target_expr);
} else {
return target_expr;
@@ -223,7 +240,8 @@ internal class Vala.CCodeDelegateModule : CCodeArrayModule {
}
} else if (delegate_expr.symbol_reference is Field) {
var field = (Field) delegate_expr.symbol_reference;
- var target_cname = get_delegate_target_cname (field.get_cname ());
+ string target_cname = get_delegate_target_cname (field.get_cname ());
+ string target_destroy_notify_cname = get_delegate_target_destroy_notify_cname (field.get_cname ());
var ma = (MemberAccess) delegate_expr;
@@ -244,11 +262,20 @@ internal class Vala.CCodeDelegateModule : CCodeArrayModule {
}
if (((TypeSymbol) field.parent_symbol).is_reference_type ()) {
target_expr = new CCodeMemberAccess.pointer (inst, target_cname);
+ if (expr_owned) {
+ delegate_target_destroy_notify = new CCodeMemberAccess.pointer (inst, target_destroy_notify_cname);
+ }
} else {
target_expr = new CCodeMemberAccess (inst, target_cname);
+ if (expr_owned) {
+ delegate_target_destroy_notify = new CCodeMemberAccess (inst, target_destroy_notify_cname);
+ }
}
} else {
target_expr = new CCodeIdentifier (target_cname);
+ if (expr_owned) {
+ delegate_target_destroy_notify = new CCodeIdentifier (target_destroy_notify_cname);
+ }
}
if (is_out) {
diff --git a/codegen/valaccodemethodcallmodule.vala b/codegen/valaccodemethodcallmodule.vala
index 31d145e..70483ef 100644
--- a/codegen/valaccodemethodcallmodule.vala
+++ b/codegen/valaccodemethodcallmodule.vala
@@ -330,7 +330,7 @@ internal class Vala.CCodeMethodCallModule : CCodeAssignmentModule {
// (ret_tmp = call (&tmp), var1 = (assign_tmp = dup (tmp), free (var1), assign_tmp), ret_tmp)
if (param.direction != ParameterDirection.IN && requires_destroy (arg.value_type)
&& (param.direction == ParameterDirection.OUT || !param.parameter_type.value_owned)
- && !(param.parameter_type is ArrayType)) {
+ && !(param.parameter_type is ArrayType) && !(param.parameter_type is DelegateType)) {
var unary = (UnaryExpression) arg;
var ccomma = new CCodeCommaExpression ();
diff --git a/codegen/valagtypemodule.vala b/codegen/valagtypemodule.vala
index 417d29a..beda1c4 100644
--- a/codegen/valagtypemodule.vala
+++ b/codegen/valagtypemodule.vala
@@ -301,6 +301,9 @@ internal class Vala.GTypeModule : GErrorModule {
if (delegate_type.delegate_symbol.has_target) {
// create field to store delegate target
instance_struct.add_field ("gpointer", get_delegate_target_cname (f.name));
+ if (delegate_type.value_owned) {
+ instance_struct.add_field ("GDestroyNotify", get_delegate_target_destroy_notify_cname (f.name));
+ }
}
}
} else if (f.binding == MemberBinding.CLASS) {
@@ -391,6 +394,9 @@ internal class Vala.GTypeModule : GErrorModule {
if (delegate_type.delegate_symbol.has_target) {
// create field to store delegate target
instance_priv_struct.add_field ("gpointer", get_delegate_target_cname (f.name));
+ if (delegate_type.value_owned) {
+ instance_priv_struct.add_field ("GDestroyNotify", get_delegate_target_destroy_notify_cname (f.name));
+ }
}
}
}
diff --git a/vala/valadelegatetype.vala b/vala/valadelegatetype.vala
index 1f32a7e..3761380 100644
--- a/vala/valadelegatetype.vala
+++ b/vala/valadelegatetype.vala
@@ -83,4 +83,8 @@ public class Vala.DelegateType : DataType {
public override bool check (SemanticAnalyzer analyzer) {
return delegate_symbol.check (analyzer);
}
+
+ public override bool is_disposable () {
+ return delegate_symbol.has_target && value_owned;
+ }
}
diff --git a/vala/valamemberaccess.vala b/vala/valamemberaccess.vala
index 80e0b00..8833d80 100644
--- a/vala/valamemberaccess.vala
+++ b/vala/valamemberaccess.vala
@@ -575,6 +575,10 @@ public class Vala.MemberAccess : Expression {
} else {
value_type = new InvalidType ();
}
+
+ if (target_type != null) {
+ value_type.value_owned = target_type.value_owned;
+ }
} else {
// implicit this access
if (instance && inner == null) {
@@ -593,6 +597,10 @@ public class Vala.MemberAccess : Expression {
if (symbol_reference is Method) {
var m = (Method) symbol_reference;
+ if (target_type != null) {
+ value_type.value_owned = target_type.value_owned;
+ }
+
Method base_method;
if (m.base_method != null) {
base_method = m.base_method;
diff --git a/vala/valareferencetransferexpression.vala b/vala/valareferencetransferexpression.vala
index dcf2e53..0cb89ce 100644
--- a/vala/valareferencetransferexpression.vala
+++ b/vala/valareferencetransferexpression.vala
@@ -102,6 +102,14 @@ public class Vala.ReferenceTransferExpression : Expression {
return false;
}
+ if (inner.value_type is DelegateType) {
+ // would require fixing code generator to ensure _target_destroy_notify
+ // is set to NULL as well after reference transfer, leads to double free otherwise
+ error = true;
+ Report.error (source_reference, "Reference transfer not supported for delegates");
+ return false;
+ }
+
value_type = inner.value_type.copy ();
value_type.value_owned = true;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]