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 (),
 				     &params,
 				     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;