Add support for personality function and try/catch
diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c
index 096c899..b4e6566 100644
--- a/gcc/jit/jit-playback.c
+++ b/gcc/jit/jit-playback.c
@@ -491,7 +491,8 @@
const char *name,
const auto_vec<param *> *params,
int is_variadic,
- enum built_in_function builtin_id)
+ enum built_in_function builtin_id,
+ function *personality_function)
{
int i;
param *param;
@@ -515,6 +516,11 @@
/* FIXME: this uses input_location: */
tree fndecl = build_fn_decl (name, fn_type);
+ if (personality_function)
+ {
+ DECL_FUNCTION_PERSONALITY (fndecl) = personality_function->as_fndecl ();
+ }
+
if (loc)
set_tree_location (fndecl, loc);
@@ -1742,6 +1748,10 @@
int j;
tree stmt;
+ if (b->m_is_try_or_finally) {
+ continue;
+ }
+
b->m_label_expr = build1 (LABEL_EXPR,
void_type_node,
b->as_label_decl ());
@@ -1752,6 +1762,42 @@
}
}
+void
+playback::block::
+add_try_finally (location *loc,
+ block *try_block,
+ block *finally_block)
+{
+ gcc_assert (try_block);
+ gcc_assert (finally_block);
+
+ try_block->m_is_try_or_finally = true;
+ finally_block->m_is_try_or_finally = true;
+
+ if (loc)
+ {
+ set_tree_location (try_block->as_label_decl (), loc);
+ set_tree_location (finally_block->as_label_decl (), loc);
+ }
+
+ tree try_body = alloc_stmt_list ();
+ int i;
+ tree stmt;
+ FOR_EACH_VEC_ELT (try_block->m_stmts, i, stmt) {
+ append_to_statement_list (stmt, &try_body);
+ }
+
+ tree finally_body = alloc_stmt_list ();
+ int j;
+ tree finally_stmt;
+ FOR_EACH_VEC_ELT (finally_block->m_stmts, j, finally_stmt) {
+ append_to_statement_list (finally_stmt, &finally_body);
+ }
+
+ add_stmt (build2 (TRY_FINALLY_EXPR, void_type_node,
+ try_body, finally_body));
+}
+
/* Finish compiling the given function, potentially running the
garbage-collector.
The function will have a statement list by now.
diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h
index 25e0d5c..d8b86a2 100644
--- a/gcc/jit/jit-playback.h
+++ b/gcc/jit/jit-playback.h
@@ -107,7 +107,8 @@
const char *name,
const auto_vec<param *> *params,
int is_variadic,
- enum built_in_function builtin_id);
+ enum built_in_function builtin_id,
+ function *personality_function);
lvalue *
new_global (location *loc,
@@ -578,6 +579,11 @@
rvalue *rvalue);
void
+ add_try_finally (location *loc,
+ block *try_block,
+ block *finally_block);
+
+ void
add_assignment (location *loc,
lvalue *lvalue,
rvalue *rvalue);
@@ -640,6 +646,7 @@
public: // for now
tree m_label_expr;
+ bool m_is_try_or_finally = false;
friend class function;
};
diff --git a/gcc/jit/jit-recording.c b/gcc/jit/jit-recording.c
index 5ea2320..9e18b4e 100644
--- a/gcc/jit/jit-recording.c
+++ b/gcc/jit/jit-recording.c
@@ -4091,7 +4091,8 @@
m_builtin_id (builtin_id),
m_locals (),
m_blocks (),
- m_fn_ptr_type (NULL)
+ m_fn_ptr_type (NULL),
+ m_personality_function (NULL)
{
for (int i = 0; i< num_params; i++)
{
@@ -4144,13 +4145,20 @@
FOR_EACH_VEC_ELT (m_params, i, param)
params.safe_push (param->playback_param ());
+ playback::function *personality_function = NULL;
+ if (m_personality_function)
+ {
+ personality_function = m_personality_function->playback_function ();
+ }
+
set_playback_obj (r->new_function (playback_location (r, m_loc),
m_kind,
m_return_type->playback_type (),
m_name->c_str (),
¶ms,
m_is_variadic,
- m_builtin_id));
+ m_builtin_id,
+ personality_function));
}
/* Create a recording::local instance and add it to
@@ -4295,6 +4303,13 @@
/* Iteratively walk the graph of blocks, marking their "m_is_reachable"
flag, starting at the initial block. */
auto_vec<block *> worklist (m_blocks.length ());
+ int j;
+ block *func_block;
+ /* Push the blocks used in try/finally because they're not successors of
+ other blocks. */
+ FOR_EACH_VEC_ELT (m_blocks, j, func_block)
+ if (func_block->m_is_reachable)
+ worklist.safe_push (func_block);
worklist.safe_push (m_blocks[0]);
while (worklist.length () > 0)
{
@@ -4393,6 +4408,12 @@
return result;
}
+void
+recording::function::set_personality_function (function *function)
+{
+ m_personality_function = function;
+}
+
/* Implementation of recording::memento::make_debug_string for
functions. */
@@ -4477,6 +4498,29 @@
return result;
}
+/* The implementation of class gcc::jit::recording::block. */
+
+/* Create a recording::try_finally instance and add it to
+ the block's context's list of mementos, and to the block's
+ list of statements.
+
+ Implements the heart of gcc_jit_block_add_try_finally. */
+
+recording::statement *
+recording::block::add_try_finally (location *loc,
+ block *try_block,
+ block *finally_block)
+{
+ statement *result = new try_finally (this, loc, try_block, finally_block);
+ try_block->m_has_been_terminated = true;
+ finally_block->m_has_been_terminated = true;
+ try_block->m_is_reachable = true;
+ finally_block->m_is_reachable = true;
+ m_ctxt->record (result);
+ m_statements.safe_push (result);
+ return result;
+}
+
/* Create a recording::assignment instance and add it to
the block's context's list of mementos, and to the block's
list of statements.
@@ -6719,6 +6763,48 @@
r.get_identifier_as_rvalue (m_rvalue));
}
+/* The implementation of class gcc::jit::recording::try_finally. */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::try_finally. */
+
+void
+recording::try_finally::replay_into (replayer *r)
+{
+ playback_block (get_block ())
+ ->add_try_finally (playback_location (r),
+ m_try_block->playback_block (),
+ m_finally_block->playback_block ());
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ an eval statement. */
+
+recording::string *
+recording::try_finally::make_debug_string ()
+{
+ return string::from_printf (m_ctxt,
+ "try { %s } finally { %s };",
+ m_try_block->get_debug_string (),
+ m_finally_block->get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for
+ eval statements. */
+
+void
+recording::try_finally::write_reproducer (reproducer &r)
+{
+ r.write (" gcc_jit_block_add_try_finally (%s, /*gcc_jit_block *block */\n"
+ " %s, /* gcc_jit_location *loc */\n"
+ " %s, /* gcc_jit_block *try_block */\n"
+ " %s); /* gcc_jit_block *finally_block */\n",
+ r.get_identifier (get_block ()),
+ r.get_identifier (get_loc ()),
+ r.get_identifier (m_try_block),
+ r.get_identifier (m_finally_block));
+}
+
/* The implementation of class gcc::jit::recording::assignment. */
/* Implementation of pure virtual hook recording::memento::replay_into
diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h
index 343cd6c..fec82c0 100644
--- a/gcc/jit/jit-recording.h
+++ b/gcc/jit/jit-recording.h
@@ -1324,6 +1324,7 @@
void dump_to_dot (const char *path);
rvalue *get_address (location *loc);
+ void set_personality_function (function *function);
private:
string * make_debug_string () FINAL OVERRIDE;
@@ -1340,6 +1341,7 @@
auto_vec<local *> m_locals;
auto_vec<block *> m_blocks;
type *m_fn_ptr_type;
+ function *m_personality_function;
};
class block : public memento
@@ -1369,6 +1371,11 @@
rvalue *rvalue);
statement *
+ add_try_finally (location *loc,
+ block *try_block,
+ block *finally_block);
+
+ statement *
add_assignment (location *loc,
lvalue *lvalue,
rvalue *rvalue);
@@ -2170,6 +2177,28 @@
location *m_loc;
};
+class try_finally : public statement
+{
+public:
+ try_finally (block *b,
+ location *loc,
+ block *try_block,
+ block *finally_block)
+ : statement (b, loc),
+ m_try_block (try_block),
+ m_finally_block (finally_block) {}
+
+ void replay_into (replayer *r) FINAL OVERRIDE;
+
+private:
+ string * make_debug_string () FINAL OVERRIDE;
+ void write_reproducer (reproducer &r) FINAL OVERRIDE;
+
+private:
+ block *m_try_block;
+ block *m_finally_block;
+};
+
class eval : public statement
{
public:
diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c
index 8712e73..2c1a288 100644
--- a/gcc/jit/libgccjit.c
+++ b/gcc/jit/libgccjit.c
@@ -2512,6 +2512,35 @@
/* Public entrypoint. See description in libgccjit.h.
After error-checking, the real work is done by the
+ gcc::jit::recording::block::add_try_finally method in jit-recording.c. */
+
+void
+gcc_jit_block_add_try_finally (gcc_jit_block *block,
+ gcc_jit_location *loc,
+ gcc_jit_block *try_block,
+ gcc_jit_block *finally_block)
+{
+ RETURN_IF_NOT_VALID_BLOCK (block, loc);
+ gcc::jit::recording::context *ctxt = block->get_context ();
+ JIT_LOG_FUNC (ctxt->get_logger ());
+ /* LOC can be NULL. */
+ RETURN_IF_FAIL (try_block, ctxt, loc, "NULL rvalue");
+ RETURN_IF_FAIL (finally_block, ctxt, loc, "NULL rvalue");
+
+ gcc::jit::recording::statement *stmt = block->add_try_finally (loc, try_block, finally_block);
+
+ /* "stmt" should be good enough to be usable in error-messages,
+ but might still not be compilable; perform some more
+ error-checking here. We do this here so that the error messages
+ can contain a stringified version of "stmt", whilst appearing
+ as close as possible to the point of failure. */
+ /*try_block->verify_valid_within_stmt (__func__, stmt);
+ finally_block->verify_valid_within_stmt (__func__, stmt);*/
+}
+
+/* Public entrypoint. See description in libgccjit.h.
+
+ After error-checking, the real work is done by the
gcc::jit::recording::block::add_assignment method in
jit-recording.c. */
@@ -3692,6 +3721,21 @@
/* Public entrypoint. See description in libgccjit.h.
After error-checking, the real work is done by the
+ gcc::jit::recording::function::set_personality_function method, in
+ jit-recording.c. */
+
+void
+gcc_jit_function_set_personality_function (gcc_jit_function *fn,
+ gcc_jit_function *personality_func)
+{
+ RETURN_IF_FAIL (fn, NULL, NULL, "NULL function");
+
+ fn->set_personality_function (personality_func);
+}
+
+/* Public entrypoint. See description in libgccjit.h.
+
+ After error-checking, the real work is done by the
gcc::jit::recording::context::new_rvalue_from_vector method, in
jit-recording.c. */
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
index 732ca58..5e15da7 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -1206,6 +1206,24 @@
gcc_jit_location *loc,
gcc_jit_rvalue *rvalue);
+/* Add a try/finally statement.
+
+ This is equivalent to this C++ code:
+
+ try {
+ try_block
+ }
+ finally {
+ finally_block
+ }
+*/
+
+void
+gcc_jit_block_add_try_finally (gcc_jit_block *block,
+ gcc_jit_location *loc,
+ gcc_jit_block *try_block,
+ gcc_jit_block *finally_block);
+
/* Add evaluation of an rvalue, assigning the result to the given
lvalue.
@@ -1603,6 +1621,9 @@
gcc_jit_function_get_address (gcc_jit_function *fn,
gcc_jit_location *loc);
+void
+gcc_jit_function_set_personality_function (gcc_jit_function *fn,
+ gcc_jit_function *personality_func);
#define LIBGCCJIT_HAVE_gcc_jit_context_new_rvalue_from_vector
diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
index abe6ea0..9ee8af1 100644
--- a/gcc/jit/libgccjit.map
+++ b/gcc/jit/libgccjit.map
@@ -258,3 +258,9 @@
gcc_jit_type_get_size;
gcc_jit_compatible_types;
} LIBGCCJIT_ABI_21;
+
+LIBGCCJIT_ABI_23 {
+ global:
+ gcc_jit_block_add_try_finally;
+ gcc_jit_function_set_personality_function;
+} LIBGCCJIT_ABI_22;