From: Rico Tzschichholz Date: Sun, 17 Mar 2019 11:38:35 +0000 (+0100) Subject: codegen: Make every co-routine state its own CodeBlock and bump state early X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=20202fd45455c944426fe3565e954c849f79a87b;p=thirdparty%2Fvala.git codegen: Make every co-routine state its own CodeBlock and bump state early Fixes https://gitlab.gnome.org/GNOME/vala/issues/601 --- diff --git a/ccode/valaccodefunction.vala b/ccode/valaccodefunction.vala index 395ffdc8b..d346f5665 100644 --- a/ccode/valaccodefunction.vala +++ b/ccode/valaccodefunction.vala @@ -327,10 +327,31 @@ public class Vala.CCodeFunction : CCodeNode { add_statement (stmt); } - public void close () { + public void prepend_statement (CCodeNode stmt) { + stmt.line = current_line; + current_block.prepend_statement (stmt); + } + + public void prepend_expression (CCodeExpression expression) { + prepend_statement (new CCodeExpressionStatement (expression)); + } + + public void prepend_assignment (CCodeExpression left, CCodeExpression right) { + prepend_expression (new CCodeAssignment (left, right)); + } + + public void close (CCodeBlock? block = null) { + //FIXME Don't ignore this invalid close without further action + if (block != null && statement_stack.index_of (block) >= 0) { + return; + } + do { var top = statement_stack.remove_at (statement_stack.size - 1); current_block = top as CCodeBlock; + if (current_block == block) { + current_block = null; + } } while (current_block == null); } } diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala index db9a498cc..e4ad92883 100644 --- a/codegen/valaccodebasemodule.vala +++ b/codegen/valaccodebasemodule.vala @@ -46,6 +46,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator { public Map closure_variable_count_map = new HashMap (str_hash, str_equal); public Map closure_variable_clash_map = new HashMap (); public bool is_in_method_precondition; + public CCodeBlock? current_co_state_block; public EmitContext (Symbol? symbol = null) { current_symbol = symbol; @@ -5241,10 +5242,17 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator { // set state before calling async function to support immediate callbacks int state = emit_context.next_coroutine_state++; - ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_state_"), new CCodeConstant (state.to_string ())); + ccode.prepend_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_state_"), new CCodeConstant (state.to_string ())); ccode.add_expression (async_call); ccode.add_return (new CCodeConstant ("FALSE")); + + if (state > 0) { + ccode.close (emit_context.current_co_state_block); + emit_context.current_co_state_block = null; + } ccode.add_label ("_state_%d".printf (state)); + ccode.open_block (); + emit_context.current_co_state_block = ccode.current_block; } creation_expr = creation_call; diff --git a/codegen/valaccodemethodcallmodule.vala b/codegen/valaccodemethodcallmodule.vala index d7ac3f4b0..284c54de7 100644 --- a/codegen/valaccodemethodcallmodule.vala +++ b/codegen/valaccodemethodcallmodule.vala @@ -802,10 +802,17 @@ public class Vala.CCodeMethodCallModule : CCodeAssignmentModule { // set state before calling async function to support immediate callbacks int state = emit_context.next_coroutine_state++; - ccode.add_assignment (get_variable_cexpression ("_state_"), new CCodeConstant (state.to_string ())); + ccode.prepend_assignment (get_variable_cexpression ("_state_"), new CCodeConstant (state.to_string ())); ccode.add_expression (async_call); ccode.add_return (new CCodeConstant ("FALSE")); + + if (state > 0) { + ccode.close (emit_context.current_co_state_block); + emit_context.current_co_state_block = null; + } ccode.add_label ("_state_%d".printf (state)); + ccode.open_block (); + emit_context.current_co_state_block = ccode.current_block; } if (expr.is_assert) { diff --git a/codegen/valaccodemethodmodule.vala b/codegen/valaccodemethodmodule.vala index ff6d679ac..cf5b0e996 100644 --- a/codegen/valaccodemethodmodule.vala +++ b/codegen/valaccodemethodmodule.vala @@ -492,6 +492,8 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule { // coroutine body ccode.add_label ("_state_0"); + ccode.open_block (); + emit_context.current_co_state_block = ccode.current_block; } if (m.closure) { diff --git a/codegen/valagasyncmodule.vala b/codegen/valagasyncmodule.vala index 4f130946e..4515d1dd0 100644 --- a/codegen/valagasyncmodule.vala +++ b/codegen/valagasyncmodule.vala @@ -735,11 +735,19 @@ public class Vala.GAsyncModule : GtkModule { return; } + // set state early to support immediate callbacks int state = emit_context.next_coroutine_state++; - ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_state_"), new CCodeConstant (state.to_string ())); + ccode.prepend_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_state_"), new CCodeConstant (state.to_string ())); ccode.add_return (new CCodeConstant ("FALSE")); + + if (state > 0) { + ccode.close (emit_context.current_co_state_block); + emit_context.current_co_state_block = null; + } ccode.add_label ("_state_%d".printf (state)); + ccode.open_block (); + emit_context.current_co_state_block = ccode.current_block; ccode.add_statement (new CCodeEmptyStatement ()); } diff --git a/codegen/valagdbusclientmodule.vala b/codegen/valagdbusclientmodule.vala index 697b08758..367f0b660 100644 --- a/codegen/valagdbusclientmodule.vala +++ b/codegen/valagdbusclientmodule.vala @@ -412,7 +412,13 @@ public class Vala.GDBusClientModule : GDBusModule { ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_state_"), new CCodeConstant (state.to_string ())); ccode.add_expression (ccall); ccode.add_return (new CCodeConstant ("FALSE")); + if (state > 0) { + ccode.close (emit_context.current_co_state_block); + emit_context.current_co_state_block = null; + } ccode.add_label ("_state_%d".printf (state)); + ccode.open_block (); + emit_context.current_co_state_block = ccode.current_block; ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_async_initable_new_finish")); ccall.add_argument (new CCodeCastExpression (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_source_object_"), "GAsyncInitable *")); diff --git a/tests/Makefile.am b/tests/Makefile.am index 1a5605dea..60a41b4a5 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -719,6 +719,7 @@ TESTS = \ asynchronous/bug762819.vala \ asynchronous/bug777242.vala \ asynchronous/bug783543.vala \ + asynchronous/bug789249.vala \ asynchronous/bug792660.vala \ asynchronous/bug792942.vala \ asynchronous/bug793158.vala \ diff --git a/tests/asynchronous/bug789249.vala b/tests/asynchronous/bug789249.vala new file mode 100644 index 000000000..7e854d6c2 --- /dev/null +++ b/tests/asynchronous/bug789249.vala @@ -0,0 +1,16 @@ +static int counter = 0; + +static async void foo () { + counter++; + assert (counter <= 1); + + // This is the simplest way to trigger the issue, + // it may happen due to GTask/ThreadPool/threads + // getting to call the callback before yield, too. + foo.callback (); + yield; +} + +void main () { + foo.begin (); +}