Commit 3904cc10 by Bin Cheng

Use promise in coroutine frame in actor function.

By standard, coroutine body should be encapsulated in try-catch block
as following:
  try {
    // coroutine body
  } catch(...) {
    promise.unhandled_exception();
  }
Given above try-catch block is implemented in the coroutine actor
function called by coroutine ramp function, so the promise should
be accessed via actor function's coroutine frame pointer argument,
rather than the ramp function's coroutine frame variable.

This patch cleans code a bit to make fix easy.

gcc/cp
    * coroutines.cc (act_des_fn): New.
    (morph_fn_to_coro): Call act_des_fn to build actor/destroy decls.
    Access promise via actor function's frame pointer argument.
    (build_actor_fn, build_destroy_fn): Use frame pointer argument.
parent 3b35b3d4
2020-01-30 Bin Cheng <bin.cheng@linux.alibaba.com> 2020-01-30 Bin Cheng <bin.cheng@linux.alibaba.com>
* coroutines.cc (act_des_fn): New.
(morph_fn_to_coro): Call act_des_fn to build actor/destroy decls.
Access promise via actor function's frame pointer argument.
(build_actor_fn, build_destroy_fn): Use frame pointer argument.
2020-01-30 Bin Cheng <bin.cheng@linux.alibaba.com>
* coroutines.cc (co_await_expander): Handle type conversion case. * coroutines.cc (co_await_expander): Handle type conversion case.
2020-01-29 Jason Merrill <jason@redhat.com> 2020-01-29 Jason Merrill <jason@redhat.com>
......
...@@ -1828,11 +1828,7 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, ...@@ -1828,11 +1828,7 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody,
tree act_des_fn_ptr = build_pointer_type (act_des_fn_type); tree act_des_fn_ptr = build_pointer_type (act_des_fn_type);
/* One param, the coro frame pointer. */ /* One param, the coro frame pointer. */
tree actor_fp tree actor_fp = DECL_ARGUMENTS (actor);
= build_lang_decl (PARM_DECL, get_identifier ("frame_ptr"), coro_frame_ptr);
DECL_CONTEXT (actor_fp) = actor;
DECL_ARG_TYPE (actor_fp) = type_passed_as (coro_frame_ptr);
DECL_ARGUMENTS (actor) = actor_fp;
/* A void return. */ /* A void return. */
tree resdecl = build_decl (loc, RESULT_DECL, 0, void_type_node); tree resdecl = build_decl (loc, RESULT_DECL, 0, void_type_node);
...@@ -2219,12 +2215,7 @@ build_destroy_fn (location_t loc, tree coro_frame_type, tree destroy, ...@@ -2219,12 +2215,7 @@ build_destroy_fn (location_t loc, tree coro_frame_type, tree destroy,
tree actor) tree actor)
{ {
/* One param, the coro frame pointer. */ /* One param, the coro frame pointer. */
tree coro_frame_ptr = build_pointer_type (coro_frame_type); tree destr_fp = DECL_ARGUMENTS (destroy);
tree destr_fp
= build_lang_decl (PARM_DECL, get_identifier ("frame_ptr"), coro_frame_ptr);
DECL_CONTEXT (destr_fp) = destroy;
DECL_ARG_TYPE (destr_fp) = type_passed_as (coro_frame_ptr);
DECL_ARGUMENTS (destroy) = destr_fp;
/* A void return. */ /* A void return. */
tree resdecl = build_decl (loc, RESULT_DECL, 0, void_type_node); tree resdecl = build_decl (loc, RESULT_DECL, 0, void_type_node);
...@@ -2865,6 +2856,24 @@ register_local_var_uses (tree *stmt, int *do_subtree, void *d) ...@@ -2865,6 +2856,24 @@ register_local_var_uses (tree *stmt, int *do_subtree, void *d)
return NULL_TREE; return NULL_TREE;
} }
/* Build, return FUNCTION_DECL node with its coroutine frame pointer argument
for either actor or destroy functions. */
static tree
act_des_fn (tree orig, tree fn_type, tree coro_frame_ptr, const char* name)
{
tree fn_name = get_fn_local_identifier (orig, name);
tree fn = build_lang_decl (FUNCTION_DECL, fn_name, fn_type);
DECL_CONTEXT (fn) = DECL_CONTEXT (orig);
DECL_INITIAL (fn) = error_mark_node;
tree id = get_identifier ("frame_ptr");
tree fp = build_lang_decl (PARM_DECL, id, coro_frame_ptr);
DECL_CONTEXT (fp) = fn;
DECL_ARG_TYPE (fp) = type_passed_as (coro_frame_ptr);
DECL_ARGUMENTS (fn) = fp;
return fn;
}
/* Here we: /* Here we:
a) Check that the function and promise type are valid for a a) Check that the function and promise type are valid for a
coroutine. coroutine.
...@@ -2991,17 +3000,9 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) ...@@ -2991,17 +3000,9 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
= build_function_type_list (void_type_node, coro_frame_ptr, NULL_TREE); = build_function_type_list (void_type_node, coro_frame_ptr, NULL_TREE);
tree act_des_fn_ptr = build_pointer_type (act_des_fn_type); tree act_des_fn_ptr = build_pointer_type (act_des_fn_type);
/* Declare the actor function. */ /* Declare the actor and destroyer function. */
tree actor_name = get_fn_local_identifier (orig, "actor"); tree actor = act_des_fn (orig, act_des_fn_type, coro_frame_ptr, "actor");
tree actor = build_lang_decl (FUNCTION_DECL, actor_name, act_des_fn_type); tree destroy = act_des_fn (orig, act_des_fn_type, coro_frame_ptr, "destroy");
DECL_CONTEXT (actor) = DECL_CONTEXT (orig);
DECL_INITIAL (actor) = error_mark_node;
/* Declare the destroyer function. */
tree destr_name = get_fn_local_identifier (orig, "destroy");
tree destroy = build_lang_decl (FUNCTION_DECL, destr_name, act_des_fn_type);
DECL_CONTEXT (destroy) = DECL_CONTEXT (orig);
DECL_INITIAL (destroy) = error_mark_node;
/* Build our dummy coro frame layout. */ /* Build our dummy coro frame layout. */
coro_frame_type = begin_class_definition (coro_frame_type); coro_frame_type = begin_class_definition (coro_frame_type);
...@@ -3598,39 +3599,41 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) ...@@ -3598,39 +3599,41 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
tree ueh_meth tree ueh_meth
= lookup_promise_method (orig, coro_unhandled_exception_identifier, = lookup_promise_method (orig, coro_unhandled_exception_identifier,
fn_start, /*musthave=*/true); fn_start, /*musthave=*/true);
/* actor's version of the promise. */
tree actor_frame = build1_loc (fn_start, INDIRECT_REF, coro_frame_type,
DECL_ARGUMENTS (actor));
tree ap_m = lookup_member (coro_frame_type, get_identifier ("__p"), 1, 0,
tf_warning_or_error);
tree ap = build_class_member_access_expr (actor_frame, ap_m, NULL_TREE,
false, tf_warning_or_error);
/* Build promise.unhandled_exception(); */ /* Build promise.unhandled_exception(); */
tree ueh tree ueh
= build_new_method_call (p, ueh_meth, NULL, NULL_TREE, LOOKUP_NORMAL, = build_new_method_call (ap, ueh_meth, NULL, NULL_TREE, LOOKUP_NORMAL,
NULL, tf_warning_or_error); NULL, tf_warning_or_error);
/* The try block is just the original function, there's no real /* The try block is just the original function, there's no real
need to call any function to do this. */ need to call any function to do this. */
tree tcb = build_stmt (fn_start, TRY_BLOCK, NULL_TREE, NULL_TREE); fnbody = build_stmt (fn_start, TRY_BLOCK, fnbody, NULL_TREE);
TRY_STMTS (tcb) = fnbody; TRY_HANDLERS (fnbody) = push_stmt_list ();
TRY_HANDLERS (tcb) = push_stmt_list ();
/* Mimic what the parser does for the catch. */ /* Mimic what the parser does for the catch. */
tree handler = begin_handler (); tree handler = begin_handler ();
finish_handler_parms (NULL_TREE, handler); /* catch (...) */ finish_handler_parms (NULL_TREE, handler); /* catch (...) */
ueh = maybe_cleanup_point_expr_void (ueh); ueh = maybe_cleanup_point_expr_void (ueh);
add_stmt (ueh); add_stmt (ueh);
finish_handler (handler); finish_handler (handler);
TRY_HANDLERS (tcb) = pop_stmt_list (TRY_HANDLERS (tcb)); TRY_HANDLERS (fnbody) = pop_stmt_list (TRY_HANDLERS (fnbody));
/* If the function starts with a BIND_EXPR, then we need to create /* If the function starts with a BIND_EXPR, then we need to create
one here to contain the try-catch and to link up the scopes. */ one here to contain the try-catch and to link up the scopes. */
if (orig_fn_has_outer_bind) if (orig_fn_has_outer_bind)
{ {
tree tcb_bind = build3 (BIND_EXPR, void_type_node, NULL, NULL, NULL); fnbody = build3 (BIND_EXPR, void_type_node, NULL, fnbody, NULL);
/* Make and connect the scope blocks. */ /* Make and connect the scope blocks. */
tree tcb_block = make_node (BLOCK); tree tcb_block = make_node (BLOCK);
/* .. and connect it here. */ /* .. and connect it here. */
BLOCK_SUPERCONTEXT (replace_blk) = tcb_block; BLOCK_SUPERCONTEXT (replace_blk) = tcb_block;
BLOCK_SUBBLOCKS (tcb_block) = replace_blk; BLOCK_SUBBLOCKS (tcb_block) = replace_blk;
BIND_EXPR_BLOCK (tcb_bind) = tcb_block; BIND_EXPR_BLOCK (fnbody) = tcb_block;
BIND_EXPR_BODY (tcb_bind) = tcb;
fnbody = tcb_bind;
} }
else
fnbody = tcb;
} }
else if (pedantic) else if (pedantic)
{ {
......
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