From: Jürg Billeter Date: Thu, 4 Feb 2010 18:02:44 +0000 (+0100) Subject: GAsync: Support async callback from closure X-Git-Tag: 0.7.10~7 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2ae8cd1509f3489277f621440a8902b8eecf9e79;p=thirdparty%2Fvala.git GAsync: Support async callback from closure Fixes bug 608184. --- diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala index ca5af4a4a..7b29aed08 100644 --- a/codegen/valaccodebasemodule.vala +++ b/codegen/valaccodebasemodule.vala @@ -1,6 +1,6 @@ /* valaccodebasemodule.vala * - * Copyright (C) 2006-2009 Jürg Billeter + * Copyright (C) 2006-2010 Jürg Billeter * Copyright (C) 2006-2008 Raffaele Sandrini * * This library is free software; you can redistribute it and/or @@ -1802,8 +1802,10 @@ internal class Vala.CCodeBaseModule : CCodeModule { } 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 ((Method) b.parent_symbol).get_parameters ()) { + foreach (var param in m.get_parameters ()) { if (param.captured) { var param_type = param.parameter_type.copy (); param_type.value_owned = true; @@ -1859,6 +1861,15 @@ internal class Vala.CCodeBaseModule : CCodeModule { } } + if (m.coroutine) { + // capture async data to allow invoking callback from inside closure + data.add_field ("gpointer", "_async_data_"); + + // async method is suspended while waiting for callback, + // so we never need to care about memory management of async data + cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), "_async_data_"), new CCodeIdentifier ("data")))); + } + var cfrag = new CCodeFragment (); append_temp_decl (cfrag, temp_vars); temp_vars.clear (); diff --git a/codegen/valaccodedelegatemodule.vala b/codegen/valaccodedelegatemodule.vala index 5e4dd46cf..721370775 100644 --- a/codegen/valaccodedelegatemodule.vala +++ b/codegen/valaccodedelegatemodule.vala @@ -1,6 +1,6 @@ /* valaccodedelegatemodule.vala * - * Copyright (C) 2006-2009 Jürg Billeter + * Copyright (C) 2006-2010 Jürg Billeter * Copyright (C) 2006-2008 Raffaele Sandrini * * This library is free software; you can redistribute it and/or @@ -296,7 +296,12 @@ internal class Vala.CCodeDelegateModule : CCodeArrayModule { if (m.binding == MemberBinding.STATIC) { return new CCodeConstant ("NULL"); } else if (m.is_async_callback) { - return new CCodeIdentifier ("data"); + if (current_method.closure) { + var block = ((Method) m.parent_symbol).body; + return new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), "_async_data_"); + } else { + return new CCodeIdentifier ("data"); + } } else { var delegate_target = (CCodeExpression) get_ccodenode (ma.inner); if (expr_owned && ma.inner.value_type.data_type != null && ma.inner.value_type.data_type.is_reference_counting ()) { diff --git a/codegen/valaccodemethodcallmodule.vala b/codegen/valaccodemethodcallmodule.vala index 5c9e3c6ea..f42117ee0 100644 --- a/codegen/valaccodemethodcallmodule.vala +++ b/codegen/valaccodemethodcallmodule.vala @@ -1,6 +1,6 @@ /* valaccodemethodcallmodule.vala * - * Copyright (C) 2006-2009 Jürg Billeter + * Copyright (C) 2006-2010 Jürg Billeter * Copyright (C) 2006-2008 Raffaele Sandrini * * This library is free software; you can redistribute it and/or @@ -153,7 +153,17 @@ internal class Vala.CCodeMethodCallModule : CCodeAssignmentModule { } CCodeExpression instance = null; - if (m != null && m.binding == MemberBinding.INSTANCE && !(m is CreationMethod)) { + if (m != null && m.is_async_callback) { + if (current_method.closure) { + var block = ((Method) m.parent_symbol).body; + instance = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), "_async_data_"); + } else { + instance = new CCodeIdentifier ("data"); + } + + in_arg_map.set (get_param_pos (m.cinstance_parameter_position), instance); + out_arg_map.set (get_param_pos (m.cinstance_parameter_position), instance); + } else if (m != null && m.binding == MemberBinding.INSTANCE && !(m is CreationMethod)) { instance = (CCodeExpression) ma.inner.ccodenode; if ((ma.member_name == "begin" || ma.member_name == "end") && ma.inner.symbol_reference == ma.symbol_reference) { diff --git a/vala/valamemberaccess.vala b/vala/valamemberaccess.vala index 6f7f51034..5e95a98ca 100644 --- a/vala/valamemberaccess.vala +++ b/vala/valamemberaccess.vala @@ -1,6 +1,6 @@ /* valamemberaccess.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 @@ -471,7 +471,22 @@ public class Vala.MemberAccess : Expression { var m = (Method) member; if (m.is_async_callback) { // ensure to use right callback method for virtual/abstract async methods - m = analyzer.current_method.get_callback_method (); + // and also for lambda expressions within async methods + var async_method = analyzer.current_async_method; + + if (async_method != analyzer.current_method) { + Symbol sym = analyzer.current_method; + while (sym != async_method) { + var method = sym as Method; + if (method != null) { + method.closure = true; + } + sym = sym.parent_symbol; + } + async_method.body.captured = true; + } + + m = async_method.get_callback_method (); symbol_reference = m; member = symbol_reference; } else if (m.base_method != null) { diff --git a/vala/valasemanticanalyzer.vala b/vala/valasemanticanalyzer.vala index b18fe9663..8d6c77f4f 100644 --- a/vala/valasemanticanalyzer.vala +++ b/vala/valasemanticanalyzer.vala @@ -1,6 +1,6 @@ /* valasemanticanalyzer.vala * - * Copyright (C) 2006-2009 Jürg Billeter + * Copyright (C) 2006-2010 Jürg Billeter * Copyright (C) 2006-2008 Raffaele Sandrini * * This library is free software; you can redistribute it and/or @@ -66,6 +66,21 @@ public class Vala.SemanticAnalyzer : CodeVisitor { } } + public Method? current_async_method { + get { + var sym = current_symbol; + while (sym is Block || sym is Method) { + var m = sym as Method; + if (m != null && m.coroutine) { + break; + } + + sym = sym.parent_symbol; + } + return sym as Method; + } + } + public PropertyAccessor? current_property_accessor { get { var sym = current_symbol;