WIP: add support for try/catch
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index 4be67e3..bfc2573 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -25,6 +25,7 @@
 #include "ipa-ref.h"
 #include "plugin-api.h"
 #include "ipa-param-manipulation.h"
+#include "print-tree.h"
 
 extern void debuginfo_early_init (void);
 extern void debuginfo_init (void);
diff --git a/gcc/cgraphunit.cc b/gcc/cgraphunit.cc
index 7b5be0f..cef7d0b 100644
--- a/gcc/cgraphunit.cc
+++ b/gcc/cgraphunit.cc
@@ -240,9 +240,14 @@
   /* Double check that no one output the function into assembly file
      early.  */
   if (!native_rtl_p ())
+  {
+      if (!(!DECL_ASSEMBLER_NAME_SET_P (decl)
+	 || !TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))))
+          debug_tree (decl);
       gcc_checking_assert
 	(!DECL_ASSEMBLER_NAME_SET_P (decl)
 	 || !TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)));
+  }
 
   if (!definition)
     return false;
@@ -1390,7 +1395,7 @@
 		      || cnode->alias
 		      || gimple_has_body_p (decl)
 		      || cnode->native_rtl_p ());
-	  gcc_assert (cnode->analyzed == cnode->definition);
+          gcc_assert (cnode->analyzed == cnode->definition);
 	}
       node->aux = NULL;
     }
diff --git a/gcc/dwarf2asm.cc b/gcc/dwarf2asm.cc
index 274f574..e640a71 100644
--- a/gcc/dwarf2asm.cc
+++ b/gcc/dwarf2asm.cc
@@ -938,7 +938,7 @@
   /* The strings are always those from IDENTIFIER_NODEs, and,
      therefore, we should never have two copies of the same
      string.  */
-  gcc_assert (ret);
+  //gcc_assert (ret);
 
   return ret;
 }
@@ -1159,4 +1159,14 @@
   va_end (ap);
 }
 
+void dwarf2asm_cc_finalize (void)
+{
+  if (indirect_pool)
+  {
+    indirect_pool->empty();
+    indirect_pool = NULL;
+  }
+  dw2_const_labelno = 0;
+}
+
 #include "gt-dwarf2asm.h"
diff --git a/gcc/dwarf2asm.h b/gcc/dwarf2asm.h
index 871a77b..53720ab 100644
--- a/gcc/dwarf2asm.h
+++ b/gcc/dwarf2asm.h
@@ -86,6 +86,8 @@
 extern rtx dw2_force_const_mem (rtx, bool);
 extern void dw2_output_indirect_constants (void);
 
+void dwarf2asm_cc_finalize (void);
+
 /* These are currently unused.  */
 
 #if 0
diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc
index 28a4ae0..1bf4289 100644
--- a/gcc/dwarf2out.cc
+++ b/gcc/dwarf2out.cc
@@ -1003,6 +1003,9 @@
 	  if (targetm.asm_out.make_eh_symbol_indirect != NULL)
 	    ref = targetm.asm_out.make_eh_symbol_indirect (ref, true);
 	  else
+            // TODO: HERE: should not insert multiple times the same personality function.
+            // If we don't, we segfault later, possibly because we don't generate the info for the duplicates.
+            // I'm not sure why it's attempting to insert multiple times the same personality function.
 	    ref = dw2_force_const_mem (ref, true);
 	}
 
diff --git a/gcc/ipa-visibility.cc b/gcc/ipa-visibility.cc
index 8a27e7b..8b1a0a4 100644
--- a/gcc/ipa-visibility.cc
+++ b/gcc/ipa-visibility.cc
@@ -709,6 +709,15 @@
 	    }
 	  node->dissolve_same_comdat_group_list ();
 	}
+      if (!((!DECL_WEAK (node->decl)
+		  && !DECL_COMDAT (node->decl))
+      	          || TREE_PUBLIC (node->decl)
+		  || node->weakref
+		  || DECL_EXTERNAL (node->decl)))
+      {
+          fprintf (stderr, "%d, %d, %d, %d, %d\n", DECL_WEAK (node->decl), DECL_COMDAT (node->decl), TREE_PUBLIC (node->decl), node->weakref, DECL_EXTERNAL (node->decl));
+          debug_tree (node->decl);
+      }
       gcc_assert ((!DECL_WEAK (node->decl)
 		  && !DECL_COMDAT (node->decl))
       	          || TREE_PUBLIC (node->decl)
diff --git a/gcc/jit/dummy-frontend.cc b/gcc/jit/dummy-frontend.cc
index 1110993..a9330f5 100644
--- a/gcc/jit/dummy-frontend.cc
+++ b/gcc/jit/dummy-frontend.cc
@@ -611,6 +611,10 @@
   target_builtins.empty ();
   build_common_builtin_nodes ();
 
+  /* Initialize EH, if we've been told to do so.  */
+  if (flag_exceptions)
+    using_eh_for_cleanups ();
+
   /* The default precision for floating point numbers.  This is used
      for floating point constants with abstract type.  This may
      eventually be controllable by a command line option.  */
diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc
index 83c8c21..775e08f 100644
--- a/gcc/jit/jit-playback.cc
+++ b/gcc/jit/jit-playback.cc
@@ -547,8 +547,7 @@
 	      enum built_in_function builtin_id,
 	      int is_target_builtin,
 	      const std::vector<gcc_jit_fn_attribute> &attributes,
-	      const std::vector<std::pair<gcc_jit_fn_attribute, std::string>> &string_attributes,
-	      function *personality_function)
+	      const std::vector<std::pair<gcc_jit_fn_attribute, std::string>> &string_attributes)
 {
   int i;
   param *param;
@@ -571,11 +570,7 @@
 
   /* FIXME: this uses input_location: */
   tree fndecl = build_fn_decl (name, fn_type);
-
-  if (personality_function)
-  {
-    DECL_FUNCTION_PERSONALITY (fndecl) = personality_function->as_fndecl ();
-  }
+  TREE_NOTHROW (fndecl) = 0;
 
   if (loc)
     set_tree_location (fndecl, loc);
@@ -659,6 +654,9 @@
           break;
         case GCC_JIT_FN_ATTRIBUTE_WEAK:
           DECL_WEAK (fndecl) = 1;
+          TREE_PUBLIC (fndecl) = 1;
+          //declare_weak (fndecl);
+          //make_decl_one_only(fndecl, DECL_ASSEMBLER_NAME(fndecl));
           break;
     }
 
@@ -2164,6 +2162,16 @@
   return new rvalue (m_ctxt, t_fnptr);
 }
 
+/* Construct a new local within this playback::function.  */
+
+void
+playback::function::
+set_personality_function (function *personality_function)
+{
+  //fprintf (stderr, "************* Setting personality function %s for %s\n", IDENTIFIER_POINTER (DECL_NAME (personality_function->as_fndecl ())), IDENTIFIER_POINTER (DECL_NAME (m_inner_fndecl)));
+  DECL_FUNCTION_PERSONALITY (m_inner_fndecl) = personality_function->as_fndecl ();
+}
+
 /* Build a statement list for the function as a whole out of the
    lists of statements for the individual blocks, building labels
    for each block.  */
@@ -2222,8 +2230,11 @@
   if (m_kind == GCC_JIT_FUNCTION_INTERNAL
       ||m_kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
     {
-      DECL_EXTERNAL (m_inner_fndecl) = 0;
-      TREE_PUBLIC (m_inner_fndecl) = 0;
+        if (!DECL_WEAK (m_inner_fndecl))
+        {
+            DECL_EXTERNAL (m_inner_fndecl) = 0;
+            TREE_PUBLIC (m_inner_fndecl) = 0;
+        }
     }
 
   if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
@@ -2290,7 +2301,8 @@
 playback::block::
 add_try_catch (location *loc,
          block *try_block,
-         block *catch_block)
+         block *catch_block,
+         bool is_finally)
 {
   gcc_assert (try_block);
   gcc_assert (catch_block);
@@ -2318,8 +2330,38 @@
     append_to_statement_list (catch_stmt, &catch_body);
   }
 
-  add_stmt (build2 (TRY_CATCH_EXPR, void_type_node,
+  if (is_finally)
+  {
+    tree noop = build_int_cst (integer_type_node, 0);
+    tree stmt = build1 (NOP_EXPR, void_type_node, size_zero_node);
+    tree success_body = alloc_stmt_list ();
+    //append_to_statement_list (stmt, &success_body);
+
+
+  tree t_string = build_string ("nop");
+  tree asm_stmt
+    = build5 (ASM_EXPR, void_type_node, t_string, NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE);
+
+  // asm statements without outputs, including simple ones, are treated
+  //   as volatile.
+  ASM_VOLATILE_P (asm_stmt) = 1;
+  ASM_INPUT_P (asm_stmt) = 0;
+    append_to_statement_list (asm_stmt, &success_body);
+    //debug_tree (success_body);
+
+    catch_body = build2 (EH_ELSE_EXPR, void_type_node, success_body, catch_body);
+    add_stmt (build2 (TRY_FINALLY_EXPR, void_type_node,
             try_body, catch_body));
+  }
+  else
+  {
+    catch_body = build2(CATCH_EXPR, void_type_node, NULL, catch_body);
+    tree try_catch = build2 (TRY_CATCH_EXPR, void_type_node,
+            try_body, catch_body);
+    //if (is_finally)
+    //  TRY_CATCH_IS_CLEANUP (try_catch) = true;
+    add_stmt (try_catch);
+  }
 }
 
 /* Add an assignment to the function's statement list.  */
diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h
index 75fb21b..83021bb 100644
--- a/gcc/jit/jit-playback.h
+++ b/gcc/jit/jit-playback.h
@@ -113,8 +113,7 @@
 		enum built_in_function builtin_id,
 		int is_target_builtin,
 		const std::vector<gcc_jit_fn_attribute> &attributes,
-		const std::vector<std::pair<gcc_jit_fn_attribute, std::string>> &string_attributes,
-		function *personality_function);
+		const std::vector<std::pair<gcc_jit_fn_attribute, std::string>> &string_attributes);
 
   lvalue *
   new_global (location *loc,
@@ -537,6 +536,9 @@
   get_address (location *loc);
 
   void
+  set_personality_function (function *personality_function);
+
+  void
   build_stmt_list ();
 
   void
@@ -609,7 +611,8 @@
   void
   add_try_catch (location *loc,
 		 block *try_block,
-		 block *catch_block);
+		 block *catch_block,
+		 bool is_finally);
 
   void
   add_assignment (location *loc,
diff --git a/gcc/jit/jit-recording.cc b/gcc/jit/jit-recording.cc
index ba87421..c5420c5 100644
--- a/gcc/jit/jit-recording.cc
+++ b/gcc/jit/jit-recording.cc
@@ -4180,8 +4180,7 @@
   m_fn_ptr_type (NULL),
   m_is_target_builtin (is_target_builtin),
   m_attributes(),
-  m_string_attributes(),
-  m_personality_function (NULL)
+  m_string_attributes()
 {
   for (int i = 0; i< num_params; i++)
     {
@@ -4234,12 +4233,6 @@
   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 (),
@@ -4249,14 +4242,37 @@
 				     m_builtin_id,
 				     m_is_target_builtin,
 				     m_attributes,
-				     m_string_attributes,
-				     personality_function));
+				     m_string_attributes));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   setting a personality function.  */
+
+recording::string *
+recording::memento_of_set_personality_function::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "%s",
+			      m_personality_function->get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for setting the personality function. */
+
+void
+recording::memento_of_set_personality_function::write_reproducer (reproducer &r)
+{
+  r.write ("    gcc_jit_function_set_personality_function (%s,\n"
+	   "                                               %s);\n",
+	   r.get_identifier (m_function),
+	   r.get_identifier (m_personality_function));
 }
 
 void
 recording::function::set_personality_function (function *function)
 {
-  m_personality_function = function;
+  recording::memento_of_set_personality_function *result =
+    new memento_of_set_personality_function (m_ctxt, this, function);
+  m_ctxt->record (result);
 }
 
 /* Create a recording::local instance and add it to
@@ -4613,9 +4629,10 @@
 recording::statement *
 recording::block::add_try_catch (location *loc,
                    block *try_block,
-                   block *catch_block)
+                   block *catch_block,
+                   bool is_finally)
 {
-  statement *result = new try_catch (this, loc, try_block, catch_block);
+  statement *result = new try_catch (this, loc, try_block, catch_block, is_finally);
   //try_block->m_has_been_terminated = true;
   //catch_block->m_has_been_terminated = true;
   try_block->m_is_reachable = true;
@@ -7041,6 +7058,17 @@
     m_loc = d.make_location ();
 }
 
+/* The implementation of class gcc::jit::recording::memento_of_set_personality_function.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::memento_of_set_personality_function.  */
+
+void
+recording::memento_of_set_personality_function::replay_into (replayer *r)
+{
+  m_function->playback_function ()->set_personality_function (m_personality_function->playback_function ());
+}
+
 /* The implementation of class gcc::jit::recording::eval.  */
 
 /* Implementation of pure virtual hook recording::memento::replay_into
@@ -7090,7 +7118,8 @@
   playback_block (get_block ())
     ->add_try_catch (playback_location (r),
         m_try_block->playback_block (),
-        m_catch_block->playback_block ());
+        m_catch_block->playback_block (),
+        m_is_finally);
 }
 
 /* Implementation of recording::memento::make_debug_string for
@@ -7099,6 +7128,7 @@
 recording::string *
 recording::try_catch::make_debug_string ()
 {
+    // TODO: handle m_is_finally.
   return string::from_printf (m_ctxt,
                   "try { %s } catch { %s };",
                   m_try_block->get_debug_string (),
@@ -7111,6 +7141,7 @@
 void
 recording::try_catch::write_reproducer (reproducer &r)
 {
+    // TODO: handle m_is_finally.
   r.write ("  gcc_jit_block_add_try_catch (%s, /*gcc_jit_block *block */\n"
        "                                 %s, /* gcc_jit_location *loc */\n"
        "                                 %s, /* gcc_jit_block *try_block */\n"
diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h
index 246bf3e..547f5de 100644
--- a/gcc/jit/jit-recording.h
+++ b/gcc/jit/jit-recording.h
@@ -1465,7 +1465,6 @@
   int m_is_target_builtin;
   std::vector<gcc_jit_fn_attribute> m_attributes;
   std::vector<std::pair<gcc_jit_fn_attribute, std::string>> m_string_attributes;
-  function *m_personality_function;
 };
 
 class block : public memento
@@ -1497,7 +1496,8 @@
   statement *
   add_try_catch (location *loc,
 		 block *try_block,
-		 block *catch_block);
+		 block *catch_block,
+		 bool is_finally = false);
 
   statement *
   add_assignment (location *loc,
@@ -1714,6 +1714,27 @@
   string *m_value;
 };
 
+class memento_of_set_personality_function : public memento
+{
+public:
+  memento_of_set_personality_function (context *ctx,
+				       function *func,
+				       function *personality_function)
+  : memento(ctx),
+    m_function (func),
+    m_personality_function (personality_function) {}
+
+  void replay_into (replayer *r) final override;
+
+private:
+  string * make_debug_string () final override;
+  void write_reproducer (reproducer &r) final override;
+
+private:
+  function *m_function;
+  function *m_personality_function;
+};
+
 class memento_of_new_rvalue_from_vector : public rvalue
 {
 public:
@@ -2357,10 +2378,12 @@
   try_catch (block *b,
     location *loc,
     block *try_block,
-    block *catch_block)
+    block *catch_block,
+    bool is_finally = false)
   : statement (b, loc),
     m_try_block (try_block),
-    m_catch_block (catch_block) {}
+    m_catch_block (catch_block),
+    m_is_finally (is_finally) {}
 
   void replay_into (replayer *r) final override;
 
@@ -2371,6 +2394,7 @@
 private:
   block *m_try_block;
   block *m_catch_block;
+  bool m_is_finally;
 };
 
 class assignment : public statement
diff --git a/gcc/jit/libgccjit.cc b/gcc/jit/libgccjit.cc
index 16c8208..98cd254 100644
--- a/gcc/jit/libgccjit.cc
+++ b/gcc/jit/libgccjit.cc
@@ -2967,6 +2967,34 @@
 }
 
 /* Public entrypoint.  See description in libgccjit.h.
+   After error-checking, the real work is done by the
+   gcc::jit::recording::block::add_try_catch 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_catch (loc, try_block, finally_block, true);
+
+  /* "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);
+  catch_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
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
index 1fd5c87..399e5c8 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -1427,7 +1427,7 @@
      try {
         try_block
      }
-     catch {
+     catch (...) {
         catch_block
      }
 */
@@ -1438,6 +1438,22 @@
 			     gcc_jit_block *try_block,
 			     gcc_jit_block *catch_block);
 
+/* Add a try/finally statement.
+   This is equivalent to this C++-like 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.
 
diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
index a1fc114..4d6a6ca 100644
--- a/gcc/jit/libgccjit.map
+++ b/gcc/jit/libgccjit.map
@@ -314,5 +314,6 @@
 LIBGCCJIT_ABI_32 {
   global:
     gcc_jit_block_add_try_catch;
+    gcc_jit_block_add_try_finally;
     gcc_jit_function_set_personality_function;
 } LIBGCCJIT_ABI_31;
diff --git a/gcc/toplev.cc b/gcc/toplev.cc
index 61d234a..9456c95 100644
--- a/gcc/toplev.cc
+++ b/gcc/toplev.cc
@@ -2353,6 +2353,7 @@
   cgraphunit_cc_finalize ();
   symtab_thunks_cc_finalize ();
   dwarf2out_cc_finalize ();
+  dwarf2asm_cc_finalize ();
   gcse_cc_finalize ();
   ipa_cp_cc_finalize ();
   ira_costs_cc_finalize ();
diff --git a/gcc/tree-eh.cc b/gcc/tree-eh.cc
index 076ecd3..38b8ea8 100644
--- a/gcc/tree-eh.cc
+++ b/gcc/tree-eh.cc
@@ -4882,7 +4882,11 @@
      and avoids references to a never defined personality routine.  */
   if (DECL_FUNCTION_PERSONALITY (current_function_decl)
       && function_needs_eh_personality (fun) != eh_personality_lang)
-    DECL_FUNCTION_PERSONALITY (current_function_decl) = NULL_TREE;
+  {
+      //fprintf(stderr, "Unset personality function for %s\n", IDENTIFIER_POINTER (DECL_NAME (current_function_decl)));
+      // TODO: uncomment:
+    //DECL_FUNCTION_PERSONALITY (current_function_decl) = NULL_TREE;
+  }
 
   return ret;
 }
diff --git a/gcc/tree.cc b/gcc/tree.cc
index 007c932..0388284 100644
--- a/gcc/tree.cc
+++ b/gcc/tree.cc
@@ -14766,6 +14766,7 @@
 tree_cc_finalize (void)
 {
   clear_nonstandard_integer_type_cache ();
+  gcc_eh_personality_decl = NULL;
 }
 
 #if CHECKING_P