[vala/0.36] codegen: Fix finally blocks with async yields
- From: Rico Tzschichholz <ricotz src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [vala/0.36] codegen: Fix finally blocks with async yields
- Date: Thu, 15 Jun 2017 06:33:09 +0000 (UTC)
commit f4a591b27c5f436b1c4645131a9cf004dd8cf969
Author: Luca Bruno <lucabru src gnome org>
Date: Wed Dec 24 23:20:58 2014 +0100
codegen: Fix finally blocks with async yields
The Method.yield_count is not correct because in C the finally blocks may
be emitted twice.
Preserve API/ABI for this backport to 0.36.x
https://bugzilla.gnome.org/show_bug.cgi?id=741929
ccode/valaccodefunction.vala | 6 +++-
codegen/valaccodebasemodule.vala | 6 ++-
codegen/valaccodemethodcallmodule.vala | 2 +-
codegen/valaccodemethodmodule.vala | 34 +++++++++++++--------
codegen/valagasyncmodule.vala | 2 +-
codegen/valagdbusclientmodule.vala | 2 +-
tests/Makefile.am | 1 +
tests/asynchronous/bug741929.vala | 50 ++++++++++++++++++++++++++++++++
vala/valamethod.vala | 1 +
vala/valamethodcall.vala | 1 -
vala/valaobjectcreationexpression.vala | 1 -
vala/valayieldstatement.vala | 2 -
12 files changed, 85 insertions(+), 23 deletions(-)
---
diff --git a/ccode/valaccodefunction.vala b/ccode/valaccodefunction.vala
index 08d3876..ef8dad6 100644
--- a/ccode/valaccodefunction.vala
+++ b/ccode/valaccodefunction.vala
@@ -48,9 +48,13 @@ public class Vala.CCodeFunction : CCodeNode {
*/
public CCodeLineDirective current_line { get; set; }
+ /**
+ * The current block to be written into.
+ */
+ public CCodeBlock current_block { get; set; }
+
private List<CCodeParameter> parameters = new ArrayList<CCodeParameter> ();
- CCodeBlock current_block;
List<CCodeStatement> statement_stack = new ArrayList<CCodeStatement> ();
public CCodeFunction (string name, string return_type = "void") {
diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala
index a9f3e63..53b4229 100644
--- a/codegen/valaccodebasemodule.vala
+++ b/codegen/valaccodebasemodule.vala
@@ -41,6 +41,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
public Map<string,string> variable_name_map = new HashMap<string,string> (str_hash,
str_equal);
public Map<string,int> closure_variable_count_map = new HashMap<string,int> (str_hash,
str_equal);
public Map<LocalVariable,int> closure_variable_clash_map = new HashMap<LocalVariable,int> ();
+ public int next_coroutine_state = 1;
public EmitContext (Symbol? symbol = null) {
current_symbol = symbol;
@@ -270,7 +271,8 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
set { emit_context.current_method_return = value; }
}
- public int next_coroutine_state = 1;
+ [Version (deprecated = true)]
+ public int next_coroutine_state;
int next_block_id = 0;
Map<Block,int> block_map = new HashMap<Block,int> ();
@@ -4796,7 +4798,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
if (expr.is_yield_expression) {
// set state before calling async function to support immediate callbacks
- int state = next_coroutine_state++;
+ int state = emit_context.next_coroutine_state++;
ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier
("_data_"), "_state_"), new CCodeConstant (state.to_string ()));
ccode.add_expression (async_call);
diff --git a/codegen/valaccodemethodcallmodule.vala b/codegen/valaccodemethodcallmodule.vala
index 6202f31..69d6802 100644
--- a/codegen/valaccodemethodcallmodule.vala
+++ b/codegen/valaccodemethodcallmodule.vala
@@ -704,7 +704,7 @@ public class Vala.CCodeMethodCallModule : CCodeAssignmentModule {
if (expr.is_yield_expression) {
// set state before calling async function to support immediate callbacks
- int state = next_coroutine_state++;
+ int state = emit_context.next_coroutine_state++;
ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"),
"_state_"), new CCodeConstant (state.to_string ()));
ccode.add_expression (async_call);
diff --git a/codegen/valaccodemethodmodule.vala b/codegen/valaccodemethodmodule.vala
index 700c7af..4d0d5fb 100644
--- a/codegen/valaccodemethodmodule.vala
+++ b/codegen/valaccodemethodmodule.vala
@@ -361,10 +361,6 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule {
}
}
- if (m.coroutine) {
- next_coroutine_state = 1;
- }
-
var creturn_type = m.return_type;
if (m.return_type.is_real_non_null_struct_type ()) {
// structs are returned via out parameter
@@ -489,6 +485,8 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule {
push_function (function);
+ unowned CCodeBlock? co_switch_block = null;
+
// generate *_real_* functions for virtual methods
// also generate them for abstract methods of classes to prevent faulty subclassing
if (!m.is_abstract || (m.is_abstract && current_type_symbol is Class)) {
@@ -500,15 +498,7 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule {
ccode.add_case (new CCodeConstant ("0"));
ccode.add_goto ("_state_0");
- for (int state = 1; state <= m.yield_count; state++) {
- ccode.add_case (new CCodeConstant (state.to_string ()));
- ccode.add_goto ("_state_%d".printf (state));
- }
-
-
- // let gcc know that this can't happen
- ccode.add_default ();
- ccode.add_expression (new CCodeFunctionCall (new CCodeIdentifier
("g_assert_not_reached")));
+ co_switch_block = ccode.current_block;
ccode.close ();
@@ -732,6 +722,24 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule {
if (m.body != null) {
m.body.emit (this);
+
+ if (co_switch_block != null) {
+ // after counting the number of yields for coroutines, append the case
statements to the switch
+ var old_block = ccode.current_block;
+ ccode.current_block = co_switch_block;
+
+ for (int state = 1; state < emit_context.next_coroutine_state; state++) {
+ ccode.add_case (new CCodeConstant (state.to_string ()));
+ ccode.add_goto ("_state_%d".printf (state));
+ }
+
+ // let gcc know that this can't happen
+ ccode.add_default ();
+ ccode.add_expression (new CCodeFunctionCall (new CCodeIdentifier
("g_assert_not_reached")));
+
+ ccode.current_block = old_block;
+ co_switch_block = null;
+ }
}
// we generate the same code if we see a return statement, this handles the case without
returns
diff --git a/codegen/valagasyncmodule.vala b/codegen/valagasyncmodule.vala
index 1cc074b..bfae24a 100644
--- a/codegen/valagasyncmodule.vala
+++ b/codegen/valagasyncmodule.vala
@@ -816,7 +816,7 @@ public class Vala.GAsyncModule : GtkModule {
}
if (stmt.yield_expression == null) {
- int state = next_coroutine_state++;
+ int state = emit_context.next_coroutine_state++;
ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"),
"_state_"), new CCodeConstant (state.to_string ()));
ccode.add_return (new CCodeConstant ("FALSE"));
diff --git a/codegen/valagdbusclientmodule.vala b/codegen/valagdbusclientmodule.vala
index 31cd12e..d986b24 100644
--- a/codegen/valagdbusclientmodule.vala
+++ b/codegen/valagdbusclientmodule.vala
@@ -407,7 +407,7 @@ public class Vala.GDBusClientModule : GDBusModule {
if (bus_get_proxy_async || conn_get_proxy_async) {
if (expr.is_yield_expression) {
- int state = next_coroutine_state++;
+ int state = emit_context.next_coroutine_state++;
ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier
("_data_"), "_state_"), new CCodeConstant (state.to_string ()));
ccode.add_expression (ccall);
diff --git a/tests/Makefile.am b/tests/Makefile.am
index d279144..01713f7 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -259,6 +259,7 @@ TESTS = \
asynchronous/bug659886.vala \
asynchronous/bug661961.vala \
asynchronous/bug710103.vala \
+ asynchronous/bug741929.vala \
asynchronous/bug742621.vala \
asynchronous/bug762819.vala \
asynchronous/bug777242.vala \
diff --git a/tests/asynchronous/bug741929.vala b/tests/asynchronous/bug741929.vala
new file mode 100644
index 0000000..b781823
--- /dev/null
+++ b/tests/asynchronous/bug741929.vala
@@ -0,0 +1,50 @@
+MainLoop? loop = null;
+
+class Foo : Object {
+ bool running = false;
+
+ public Foo () {
+ }
+
+ public async void query_async () throws Error {
+ running = true;
+
+ try {
+ if (!yield internal_query_async ()) {
+ return;
+ }
+ } finally {
+ try {
+ yield close_query_async ();
+ } catch (Error e) {
+ // ignored
+ }
+
+ running = false;
+ }
+ }
+
+ async bool internal_query_async () throws Error {
+ return true;
+ }
+
+ async void close_query_async () throws Error {
+ }
+}
+
+async void go_async () {
+ Foo foo = new Foo ();
+ try {
+ yield foo.query_async ();
+ } catch (Error e) {
+ }
+
+ loop.quit ();
+}
+
+void main () {
+ loop = new MainLoop ();
+ go_async.begin ();
+ loop.run ();
+}
+
diff --git a/vala/valamethod.vala b/vala/valamethod.vala
index 9988c66..2533389 100644
--- a/vala/valamethod.vala
+++ b/vala/valamethod.vala
@@ -183,6 +183,7 @@ public class Vala.Method : Subroutine, Callable {
public bool is_async_callback { get; set; }
+ [Version (deprecated = true)]
public int yield_count { get; set; }
private List<Parameter> parameters = new ArrayList<Parameter> ();
diff --git a/vala/valamethodcall.vala b/vala/valamethodcall.vala
index cefc651..444395a 100644
--- a/vala/valamethodcall.vala
+++ b/vala/valamethodcall.vala
@@ -478,7 +478,6 @@ public class Vala.MethodCall : Expression {
error = true;
Report.error (source_reference, "yield expression not available
outside async method");
}
- context.analyzer.current_method.yield_count++;
}
if (m != null && m.coroutine && !is_yield_expression && ((MemberAccess)
call).member_name != "end") {
// .begin call of async method, no error can happen here
diff --git a/vala/valaobjectcreationexpression.vala b/vala/valaobjectcreationexpression.vala
index c4b119a..4e5a9b9 100644
--- a/vala/valaobjectcreationexpression.vala
+++ b/vala/valaobjectcreationexpression.vala
@@ -358,7 +358,6 @@ public class Vala.ObjectCreationExpression : Expression {
error = true;
Report.error (source_reference, "yield expression not available
outside async method");
}
- context.analyzer.current_method.yield_count++;
}
// FIXME partial code duplication of MethodCall.check
diff --git a/vala/valayieldstatement.vala b/vala/valayieldstatement.vala
index 8b2069f..5b5a6f3 100644
--- a/vala/valayieldstatement.vala
+++ b/vala/valayieldstatement.vala
@@ -75,8 +75,6 @@ public class Vala.YieldStatement : CodeNode, Statement {
error = yield_expression.error;
}
- context.analyzer.current_method.yield_count++;
-
return !error;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]