about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorAntoni Boucher <bouanto@zoho.com>2022-10-19 09:23:23 -0400
committerAntoni Boucher <bouanto@zoho.com>2023-01-02 14:57:38 -0500
commit889a33a500982cfc2c79ceff1b2caf86c0adbeaa (patch)
treedcdab7a7f2867436474ab1dfcd08e1640d956fb1 /src
parent0a54f243f61cc44034af3c483dbe8bd99b76ce15 (diff)
downloadrust-889a33a500982cfc2c79ceff1b2caf86c0adbeaa.tar.gz
rust-889a33a500982cfc2c79ceff1b2caf86c0adbeaa.zip
WIP: Implement unwinding
Diffstat (limited to 'src')
-rw-r--r--src/asm.rs5
-rw-r--r--src/base.rs11
-rw-r--r--src/builder.rs104
-rw-r--r--src/callee.rs32
-rw-r--r--src/context.rs108
-rw-r--r--src/declare.rs32
-rw-r--r--src/intrinsic/mod.rs153
-rw-r--r--src/mono_item.rs11
8 files changed, 371 insertions, 85 deletions
diff --git a/src/asm.rs b/src/asm.rs
index 0d5c343ffe3..b937f7e69ac 100644
--- a/src/asm.rs
+++ b/src/asm.rs
@@ -352,8 +352,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
                     inputs.push(AsmInOperand {
                         constraint: "X".into(),
                         rust_idx,
-                        val: self.cx.rvalue_as_function(get_fn(self.cx, instance))
-                            .get_address(None),
+                        val: get_fn(self.cx, instance, false).get_address(None),
                     });
                 }
 
@@ -739,7 +738,7 @@ impl<'gcc, 'tcx> AsmMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
                         }
 
                         GlobalAsmOperandRef::SymFn { instance } => {
-                            let function = self.rvalue_as_function(get_fn(self, instance));
+                            let function = get_fn(self, instance, false);
                             self.add_used_function(function);
                             // TODO(@Amanieu): Additional mangling is needed on
                             // some targets to add a leading underscore (Mach-O)
diff --git a/src/base.rs b/src/base.rs
index ed3daddf43e..0e98166a7cc 100644
--- a/src/base.rs
+++ b/src/base.rs
@@ -87,6 +87,16 @@ pub fn compile_codegen_unit<'tcx>(tcx: TyCtxt<'tcx>, cgu_name: Symbol, supports_
         // Instantiate monomorphizations without filling out definitions yet...
         //let llvm_module = ModuleLlvm::new(tcx, &cgu_name.as_str());
         let context = Context::default();
+
+        context.add_command_line_option("-fexceptions");
+        context.add_driver_option("-fexceptions");
+
+        /*context.add_command_line_option("-fasynchronous-unwind-tables");
+        context.add_driver_option("-fasynchronous-unwind-tables");
+
+        context.add_command_line_option("-funwind-tables");
+        context.add_driver_option("-funwind-tables");*/
+
         // TODO(antoyo): only set on x86 platforms.
         context.add_command_line_option("-masm=intel");
         // TODO(antoyo): only add the following cli argument if the feature is supported.
@@ -147,6 +157,7 @@ pub fn compile_codegen_unit<'tcx>(tcx: TyCtxt<'tcx>, cgu_name: Symbol, supports_
         }
 
         // TODO(bjorn3): Remove once unwinding is properly implemented
+        // TODO: remove.
         context.set_allow_unreachable_blocks(true);
 
         {
diff --git a/src/builder.rs b/src/builder.rs
index b7342f50716..68b664a3ba2 100644
--- a/src/builder.rs
+++ b/src/builder.rs
@@ -13,7 +13,7 @@ use gccjit::{
     RValue,
     ToRValue,
     Type,
-    UnaryOp,
+    UnaryOp, FunctionType,
 };
 use rustc_codegen_ssa::MemFlags;
 use rustc_codegen_ssa::common::{AtomicOrdering, AtomicRmwBinOp, IntPredicate, RealPredicate, SynchronizationScope};
@@ -372,10 +372,11 @@ impl<'tcx> FnAbiOfHelpers<'tcx> for Builder<'_, '_, 'tcx> {
     }
 }
 
-impl<'gcc, 'tcx> Deref for Builder<'_, 'gcc, 'tcx> {
+impl<'a, 'gcc, 'tcx> Deref for Builder<'a, 'gcc, 'tcx> {
     type Target = CodegenCx<'gcc, 'tcx>;
 
-    fn deref(&self) -> &Self::Target {
+    fn deref<'b>(&'b self) -> &'a Self::Target
+    {
         self.cx
     }
 }
@@ -393,7 +394,7 @@ impl<'gcc, 'tcx> BackendTypes for Builder<'_, 'gcc, 'tcx> {
 }
 
 impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
-    fn build(cx: &'a CodegenCx<'gcc, 'tcx>, block: Block<'gcc>) -> Self {
+    fn build(cx: &'a CodegenCx<'gcc, 'tcx>, block: Block<'gcc>) -> Builder<'a, 'gcc, 'tcx> {
         Builder::with_cx(cx, block)
     }
 
@@ -450,8 +451,36 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
         self.block.end_with_switch(None, value, default_block, &gcc_cases);
     }
 
+    #[cfg(feature="master")]
+    fn invoke(&mut self, typ: Type<'gcc>, func: RValue<'gcc>, args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, _funclet: Option<&Funclet>) -> RValue<'gcc> {
+        let try_block = self.current_func().new_block("try");
+
+        let current_block = self.block.clone();
+        self.block = try_block;
+        let call = self.call(typ, func, args, None); // TODO: use funclet here?
+        self.block = current_block;
+
+        let return_value = self.current_func()
+            .new_local(None, call.get_type(), "invokeResult");
+
+        try_block.add_assignment(None, return_value, call);
+
+        try_block.end_with_jump(None, then);
+
+        self.block.add_try_catch(None, try_block, catch);
+
+        self.block.end_with_jump(None, then);
+
+        // NOTE: since jumps were added in a place rustc does not expect, the current blocks in the
+        // state need to be updated.
+        // FIXME: not sure it's actually needed.
+        self.switch_to_block(then);
+
+        return_value.to_rvalue()
+    }
+
+    #[cfg(not(feature="master"))]
     fn invoke(&mut self, typ: Type<'gcc>, func: RValue<'gcc>, args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, _funclet: Option<&Funclet>) -> RValue<'gcc> {
-        // TODO(bjorn3): Properly implement unwinding.
         let call_site = self.call(typ, func, args, None);
         let condition = self.context.new_rvalue_from_int(self.bool_type, 1);
         self.llbb().end_with_conditional(None, condition, then, catch);
@@ -1160,23 +1189,56 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
         aggregate_value
     }
 
-    fn set_personality_fn(&mut self, _personality: RValue<'gcc>) {
-        // TODO(antoyo)
-    }
-
-    fn cleanup_landing_pad(&mut self, _ty: Type<'gcc>, _pers_fn: RValue<'gcc>) -> RValue<'gcc> {
-        let field1 = self.context.new_field(None, self.u8_type.make_pointer(), "landing_pad_field_1");
-        let field2 = self.context.new_field(None, self.i32_type, "landing_pad_field_1");
+    fn set_personality_fn(&mut self, personality: RValue<'gcc>) {
+        let personality = self.rvalue_as_function(personality); // FIXME: why calling
+        //rvalue_as_function doesn't work?
+        //let personality = unsafe { std::mem::transmute(personality) };
+        #[cfg(feature="master")]
+        self.current_func().set_personality_function(personality);
+        // FIXME: rustc manages to generate the symbol DW.ref.rust_eh_personality multiple times
+        // for the same asm file, which causes an assembler error.
+    }
+
+    fn cleanup_landing_pad(&mut self, _ty: Type<'gcc>, pers_fn: RValue<'gcc>) -> RValue<'gcc> {
+        self.set_personality_fn(pers_fn);
+
+        // FIXME: we're probably not creating a real cleanup pad here.
+        // FIXME: FIXME: FIXME: It seems to be the actual problem:
+        // libunwind finds a catch, so returns _URC_HANDLER_FOUND instead of _URC_CONTINUE_UNWIND.
+        // TODO: can we generate a goto from the finally to the cleanup landing pad?
+        // TODO: TODO: TODO: add this block to a cleanup_blocks variable and generate a try/finally instead if
+        // the catch block for it is a cleanup block.
+        //
+        // TODO: look at TRY_CATCH_IS_CLEANUP, CLEANUP_POINT_EXPR, WITH_CLEANUP_EXPR, CLEANUP_EH_ONLY.
+        let eh_pointer_builtin = self.cx.context.get_target_builtin_function("__builtin_eh_pointer");
+        let zero = self.cx.context.new_rvalue_zero(self.int_type);
+        let ptr = self.cx.context.new_call(None, eh_pointer_builtin, &[zero]);
+
+        let field1_type = self.u8_type.make_pointer();
+        let field1 = self.context.new_field(None, field1_type, "landing_pad_field_1");
+        let field2 = self.context.new_field(None, self.i32_type, "landing_pad_field_2");
         let struct_type = self.context.new_struct_type(None, "landing_pad", &[field1, field2]);
-        self.current_func().new_local(None, struct_type.as_type(), "landing_pad")
-            .to_rvalue()
-        // TODO(antoyo): Properly implement unwinding.
-        // the above is just to make the compilation work as it seems
-        // rustc_codegen_ssa now calls the unwinding builder methods even on panic=abort.
-    }
-
-    fn resume(&mut self, _exn: RValue<'gcc>) {
-        // TODO(bjorn3): Properly implement unwinding.
+        let value = self.current_func().new_local(None, struct_type.as_type(), "landing_pad");
+        let ptr = self.cx.context.new_cast(None, ptr, field1_type);
+        self.block.add_assignment(None, value.access_field(None, field1), ptr);
+        self.block.add_assignment(None, value.access_field(None, field2), zero); // TODO: set the proper value here (the type of exception?).
+
+        // Resume.
+        let param = self.context.new_parameter(None, ptr.get_type(), "exn");
+        // TODO: should we call __builtin_unwind_resume instead?
+        // FIXME: should probably not called resume because it could be executed (I believe) in
+        // normal (no exception) cases
+        let unwind_resume = self.context.new_function(None, FunctionType::Extern, self.type_void(), &[param], "_Unwind_Resume", false);
+        self.block.add_eval(None, self.context.new_call(None, unwind_resume, &[ptr]));
+
+        value.to_rvalue()
+    }
+
+    fn resume(&mut self, exn: RValue<'gcc>) {
+        let param = self.context.new_parameter(None, exn.get_type(), "exn");
+        // TODO: should we call __builtin_unwind_resume instead?
+        let unwind_resume = self.context.new_function(None, FunctionType::Extern, self.type_void(), &[param], "_Unwind_Resume", false);
+        self.llbb().add_eval(None, self.context.new_call(None, unwind_resume, &[exn]));
         self.unreachable();
     }
 
diff --git a/src/callee.rs b/src/callee.rs
index be7d48b2279..fea5df9b9b0 100644
--- a/src/callee.rs
+++ b/src/callee.rs
@@ -1,6 +1,6 @@
 #[cfg(feature="master")]
 use gccjit::{FnAttribute, Visibility};
-use gccjit::{FunctionType, RValue};
+use gccjit::{FunctionType, RValue, Function};
 use rustc_codegen_ssa::traits::BaseTypeMethods;
 use rustc_middle::ty::{self, Instance, TypeVisitable};
 use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt};
@@ -16,22 +16,31 @@ use crate::context::CodegenCx;
 ///
 /// - `cx`: the crate context
 /// - `instance`: the instance to be instantiated
-pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>) -> RValue<'gcc> {
+pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>, dont_cache: bool) -> Function<'gcc> {
     let tcx = cx.tcx();
 
     assert!(!instance.substs.needs_infer());
     assert!(!instance.substs.has_escaping_bound_vars());
 
+    let sym = tcx.symbol_name(instance).name;
+
     if let Some(&func) = cx.function_instances.borrow().get(&instance) {
+        if sym == "rust_eh_personality" {
+            println!("Cached");
+        }
         return func;
     }
 
-    let sym = tcx.symbol_name(instance).name;
+    if sym == "rust_eh_personality" {
+        println!("Not cached");
+    }
 
     let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty());
 
     let func =
         if let Some(func) = cx.get_declared_value(&sym) {
+            unreachable!();
+            /*
             // Create a fn pointer with the new signature.
             let ptrty = fn_abi.ptr_to_gcc_type(cx);
 
@@ -64,11 +73,14 @@ pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>)
             }
             else {
                 func
-            }
+            }*/
         }
         else {
             cx.linkage.set(FunctionType::Extern);
-            let func = cx.declare_fn(&sym, &fn_abi);
+            /*if sym == "rust_eh_personality" {
+                panic!();
+            }*/
+            let func = cx.declare_fn(&sym, &fn_abi, dont_cache);
 
             attributes::from_fn_attrs(cx, func, instance);
 
@@ -163,11 +175,15 @@ pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>)
                 }
             }
 
-            // FIXME(antoyo): this is a wrong cast. That requires changing the compiler API.
-            unsafe { std::mem::transmute(func) }
+            func
         };
 
-    cx.function_instances.borrow_mut().insert(instance, func);
+    //if !dont_cache {
+    if sym == "rust_eh_personality" {
+        println!("Caching here");
+    }
+        cx.function_instances.borrow_mut().insert(instance, func);
+    //}
 
     func
 }
diff --git a/src/context.rs b/src/context.rs
index 5f34ddd92ba..04371048380 100644
--- a/src/context.rs
+++ b/src/context.rs
@@ -1,9 +1,10 @@
 use std::cell::{Cell, RefCell};
 
-use gccjit::{Block, CType, Context, Function, FunctionPtrType, FunctionType, LValue, RValue, Type};
+use gccjit::{Block, CType, Context, Function, FunctionPtrType, FunctionType, LValue, RValue, Type, FnAttribute};
 use rustc_codegen_ssa::base::wants_msvc_seh;
 use rustc_codegen_ssa::traits::{
     BackendTypes,
+    BaseTypeMethods,
     MiscMethods,
 };
 use rustc_data_structures::base_n;
@@ -11,7 +12,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_middle::span_bug;
 use rustc_middle::mir::mono::CodegenUnit;
 use rustc_middle::ty::{self, Instance, ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt};
-use rustc_middle::ty::layout::{FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, TyAndLayout, LayoutOfHelpers};
+use rustc_middle::ty::layout::{FnAbiError, FnAbiOf, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, TyAndLayout, LayoutOfHelpers};
 use rustc_session::Session;
 use rustc_span::Span;
 use rustc_target::abi::{call::FnAbi, HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx};
@@ -82,7 +83,7 @@ pub struct CodegenCx<'gcc, 'tcx> {
     /// Cache instances of monomorphic and polymorphic items
     pub instances: RefCell<FxHashMap<Instance<'tcx>, LValue<'gcc>>>,
     /// Cache function instances of monomorphic and polymorphic items
-    pub function_instances: RefCell<FxHashMap<Instance<'tcx>, RValue<'gcc>>>,
+    pub function_instances: RefCell<FxHashMap<Instance<'tcx>, Function<'gcc>>>,
     /// Cache generated vtables
     pub vtables: RefCell<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), RValue<'gcc>>>,
 
@@ -109,6 +110,7 @@ pub struct CodegenCx<'gcc, 'tcx> {
     local_gen_sym_counter: Cell<usize>,
 
     eh_personality: Cell<Option<RValue<'gcc>>>,
+    pub rust_try_fn: Cell<Option<(Type<'gcc>, Function<'gcc>)>>,
 
     pub pointee_infos: RefCell<FxHashMap<(Ty<'tcx>, Size), Option<PointeeInfo>>>,
 
@@ -245,6 +247,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
             struct_types: Default::default(),
             local_gen_sym_counter: Cell::new(0),
             eh_personality: Cell::new(None),
+            rust_try_fn: Cell::new(None),
             pointee_infos: Default::default(),
             structs_as_pointer: Default::default(),
         }
@@ -252,8 +255,9 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
 
     pub fn rvalue_as_function(&self, value: RValue<'gcc>) -> Function<'gcc> {
         let function: Function<'gcc> = unsafe { std::mem::transmute(value) };
-        debug_assert!(self.functions.borrow().values().find(|value| **value == function).is_some(),
-            "{:?} ({:?}) is not a function", value, value.get_type());
+        // FIXME: seems like self.functions get overwritten for rust_eh_personality.
+        /*debug_assert!(self.functions.borrow().values().find(|value| **value == function).is_some(),
+            "{:?} is not a function", function);*/
         function
     }
 
@@ -325,9 +329,9 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
     }
 
     fn get_fn(&self, instance: Instance<'tcx>) -> RValue<'gcc> {
-        let func = get_fn(self, instance);
-        *self.current_func.borrow_mut() = Some(self.rvalue_as_function(func));
-        func
+        let func = get_fn(self, instance, false);
+        *self.current_func.borrow_mut() = Some(func);
+        unsafe { std::mem::transmute(func) }
     }
 
     fn get_fn_addr(&self, instance: Instance<'tcx>) -> RValue<'gcc> {
@@ -338,8 +342,7 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
                 self.intrinsics.borrow()[func_name].clone()
             }
             else {
-                let func = get_fn(self, instance);
-                self.rvalue_as_function(func)
+                get_fn(self, instance, false)
             };
         let ptr = func.get_address(None);
 
@@ -377,31 +380,68 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
             return llpersonality;
         }
         let tcx = self.tcx;
-        let llfn = match tcx.lang_items().eh_personality() {
-            Some(def_id) if !wants_msvc_seh(self.sess()) => self.get_fn_addr(
-                ty::Instance::resolve(
-                    tcx,
-                    ty::ParamEnv::reveal_all(),
-                    def_id,
-                    tcx.intern_substs(&[]),
-                )
-                .unwrap().unwrap(),
-            ),
-            _ => {
-                let _name = if wants_msvc_seh(self.sess()) {
-                    "__CxxFrameHandler3"
-                } else {
-                    "rust_eh_personality"
-                };
-                //let func = self.declare_func(name, self.type_i32(), &[], true);
-                // FIXME(antoyo): this hack should not be needed. That will probably be removed when
-                // unwinding support is added.
-                self.context.new_rvalue_from_int(self.int_type, 0)
-            }
-        };
+        let func =
+            match tcx.lang_items().eh_personality() {
+                Some(def_id) if !wants_msvc_seh(self.sess()) => {
+                    // FIXME: this create an instance into self.functions and prevent the creating
+                    // of the function defined in std.
+                    let instance =
+                        ty::Instance::resolve(
+                            tcx,
+                            ty::ParamEnv::reveal_all(),
+                            def_id,
+                            tcx.intern_substs(&[]),
+                        )
+                        .unwrap().unwrap();
+
+                    let symbol_name = tcx.symbol_name(instance).name;
+                    let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty());
+                    self.linkage.set(FunctionType::Extern);
+                    let func = self.declare_fn(symbol_name, &fn_abi, false);
+                    //func.add_attribute(FnAttribute::Weak);
+
+                    /*let block = func.new_block("eh_personality_block");
+                    // NOTE: it seems this function is overwritten by the standard library, so just
+                    // return a dummy value in this version.
+                    let zero = self.context.new_rvalue_zero(self.type_u32());
+                    block.end_with_return(None, zero);*/
+
+                    //*self.current_func.borrow_mut() = Some(func);
+                    let func: RValue<'gcc> = unsafe { std::mem::transmute(func) };
+                    func
+                    /*self.get_fn(
+                        ty::Instance::resolve(
+                            tcx,
+                            ty::ParamEnv::reveal_all(),
+                            def_id,
+                            tcx.intern_substs(&[]),
+                        )
+                        .unwrap().unwrap(),
+                    )*/
+                },
+                _ => {
+                    let name = if wants_msvc_seh(self.sess()) {
+                        "__CxxFrameHandler3"
+                    } else {
+                        "rust_eh_personality"
+                    };
+                    let func = self.declare_func(name, self.type_i32(), &[], true);
+                    //*self.current_func.borrow_mut() = Some(func);
+                    // NOTE: this function is created multiple times and is overwritten by the
+                    // standard library, so mark it as weak.
+                    //func.add_attribute(FnAttribute::Weak);
+                    //self.functions.borrow_mut().insert(name.to_string(), func);
+                    /*let block = func.new_block("eh_personality_block");
+                    // NOTE: it seems this function is overwritten by the standard library, so just
+                    // return a dummy value in this version.
+                    let zero = self.context.new_rvalue_zero(self.type_i32());
+                    block.end_with_return(None, zero);*/
+                    unsafe { std::mem::transmute(func) }
+                }
+            };
         // TODO(antoyo): apply target cpu attributes.
-        self.eh_personality.set(Some(llfn));
-        llfn
+        self.eh_personality.set(Some(func));
+        func
     }
 
     fn sess(&self) -> &Session {
diff --git a/src/declare.rs b/src/declare.rs
index 5f6360a7da5..fdde82e8df7 100644
--- a/src/declare.rs
+++ b/src/declare.rs
@@ -38,12 +38,10 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
         global
     }
 
-    /*pub fn declare_func(&self, name: &str, return_type: Type<'gcc>, params: &[Type<'gcc>], variadic: bool) -> RValue<'gcc> {
-        self.linkage.set(FunctionType::Exported);
-        let func = declare_raw_fn(self, name, () /*llvm::CCallConv*/, return_type, params, variadic);
-        // FIXME(antoyo): this is a wrong cast. That requires changing the compiler API.
-        unsafe { std::mem::transmute(func) }
-    }*/
+    pub fn declare_func(&self, name: &str, return_type: Type<'gcc>, params: &[Type<'gcc>], variadic: bool) -> Function<'gcc> {
+        self.linkage.set(FunctionType::Extern);
+        declare_raw_fn(self, name, () /*llvm::CCallConv*/, return_type, params, variadic, true)
+    }
 
     pub fn declare_global(&self, name: &str, ty: Type<'gcc>, global_kind: GlobalKind, is_tls: bool, link_section: Option<Symbol>) -> LValue<'gcc> {
         let global = self.context.new_global(None, global_kind, ty, name);
@@ -71,7 +69,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
         let return_type = self.type_i32();
         let variadic = false;
         self.linkage.set(FunctionType::Exported);
-        let func = declare_raw_fn(self, name, () /*llvm::CCallConv*/, return_type, &[self.type_i32(), const_string], variadic);
+        let func = declare_raw_fn(self, name, () /*llvm::CCallConv*/, return_type, &[self.type_i32(), const_string], variadic, false);
         // NOTE: it is needed to set the current_func here as well, because get_fn() is not called
         // for the main function.
         *self.current_func.borrow_mut() = Some(func);
@@ -79,9 +77,19 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
         unsafe { std::mem::transmute(func) }
     }
 
-    pub fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Function<'gcc> {
+    pub fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, dont_cache: bool) -> Function<'gcc> {
         let (return_type, params, variadic, on_stack_param_indices) = fn_abi.gcc_type(self);
-        let func = declare_raw_fn(self, name, () /*fn_abi.llvm_cconv()*/, return_type, &params, variadic);
+        /*static mut COUNTER: i32 = 0;
+        if name.contains("personality") {
+            println!("{}: {}", name, skip_cache);
+            unsafe {
+                COUNTER += 1;
+                if COUNTER == 6 {
+                    panic!("{}", name);
+                }
+            }
+        }*/
+        let func = declare_raw_fn(self, name, () /*fn_abi.llvm_cconv()*/, return_type, &params, variadic, dont_cache);
         self.on_stack_function_params.borrow_mut().insert(func, on_stack_param_indices);
         func
     }
@@ -100,7 +108,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
 ///
 /// If there’s a value with the same name already declared, the function will
 /// update the declaration and return existing Value instead.
-fn declare_raw_fn<'gcc>(cx: &CodegenCx<'gcc, '_>, name: &str, _callconv: () /*llvm::CallConv*/, return_type: Type<'gcc>, param_types: &[Type<'gcc>], variadic: bool) -> Function<'gcc> {
+fn declare_raw_fn<'gcc>(cx: &CodegenCx<'gcc, '_>, name: &str, _callconv: () /*llvm::CallConv*/, return_type: Type<'gcc>, param_types: &[Type<'gcc>], variadic: bool, dont_cache: bool) -> Function<'gcc> {
     if name.starts_with("llvm.") {
         let intrinsic = llvm::intrinsic(name, cx);
         cx.intrinsics.borrow_mut().insert(name.to_string(), intrinsic);
@@ -115,7 +123,9 @@ fn declare_raw_fn<'gcc>(cx: &CodegenCx<'gcc, '_>, name: &str, _callconv: () /*ll
                 .map(|(index, param)| cx.context.new_parameter(None, *param, &format!("param{}", index))) // TODO(antoyo): set name.
                 .collect();
             let func = cx.context.new_function(None, cx.linkage.get(), return_type, &params, mangle_name(name), variadic);
-            cx.functions.borrow_mut().insert(name.to_string(), func);
+            //if !dont_cache {
+                cx.functions.borrow_mut().insert(name.to_string(), func);
+            //}
             func
         };
 
diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs
index e3461b97973..511256e45a3 100644
--- a/src/intrinsic/mod.rs
+++ b/src/intrinsic/mod.rs
@@ -1,22 +1,24 @@
 pub mod llvm;
 mod simd;
 
+use std::iter;
+
 use gccjit::{ComparisonOp, Function, RValue, ToRValue, Type, UnaryOp, FunctionType};
 use rustc_codegen_ssa::MemFlags;
 use rustc_codegen_ssa::base::wants_msvc_seh;
 use rustc_codegen_ssa::common::{IntPredicate, span_invalid_monomorphization_error};
 use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
 use rustc_codegen_ssa::mir::place::PlaceRef;
-use rustc_codegen_ssa::traits::{ArgAbiMethods, BaseTypeMethods, BuilderMethods, ConstMethods, IntrinsicCallMethods};
+use rustc_codegen_ssa::traits::{ArgAbiMethods, BaseTypeMethods, BuilderMethods, ConstMethods, DerivedTypeMethods, IntrinsicCallMethods, MiscMethods};
 use rustc_middle::bug;
 use rustc_middle::ty::{self, Instance, Ty};
-use rustc_middle::ty::layout::LayoutOf;
+use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, LayoutOf};
 use rustc_span::{Span, Symbol, symbol::kw, sym};
 use rustc_target::abi::HasDataLayout;
 use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode};
-use rustc_target::spec::PanicStrategy;
+use rustc_target::spec::{abi::Abi, PanicStrategy};
 
-use crate::abi::GccType;
+use crate::abi::{FnAbiGccExt, GccType};
 use crate::builder::Builder;
 use crate::common::{SignType, TypeReflection};
 use crate::context::CodegenCx;
@@ -1115,9 +1117,9 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
     }
 }
 
-fn try_intrinsic<'gcc, 'tcx>(bx: &mut Builder<'_, 'gcc, 'tcx>, try_func: RValue<'gcc>, data: RValue<'gcc>, _catch_func: RValue<'gcc>, dest: RValue<'gcc>) {
+fn try_intrinsic<'a, 'b, 'gcc, 'tcx>(bx: &'b mut Builder<'a, 'gcc, 'tcx>, try_func: RValue<'gcc>, data: RValue<'gcc>, catch_func: RValue<'gcc>, dest: RValue<'gcc>) {
     // NOTE: the `|| true` here is to use the panic=abort strategy with panic=unwind too
-    if bx.sess().panic_strategy() == PanicStrategy::Abort || true {
+    if bx.sess().panic_strategy() == PanicStrategy::Abort {
         // TODO(bjorn3): Properly implement unwinding and remove the `|| true` once this is done.
         bx.call(bx.type_void(), try_func, &[data], None);
         // Return 0 unconditionally from the intrinsic call;
@@ -1129,6 +1131,143 @@ fn try_intrinsic<'gcc, 'tcx>(bx: &mut Builder<'_, 'gcc, 'tcx>, try_func: RValue<
         unimplemented!();
     }
     else {
-        unimplemented!();
+        codegen_gnu_try(bx, try_func, data, catch_func, dest);
     }
 }
+
+// Definition of the standard `try` function for Rust using the GNU-like model
+// of exceptions (e.g., the normal semantics of LLVM's `landingpad` and `invoke`
+// instructions).
+//
+// This codegen is a little surprising because we always call a shim
+// function instead of inlining the call to `invoke` manually here. This is done
+// because in LLVM we're only allowed to have one personality per function
+// definition. The call to the `try` intrinsic is being inlined into the
+// function calling it, and that function may already have other personality
+// functions in play. By calling a shim we're guaranteed that our shim will have
+// the right personality function.
+fn codegen_gnu_try<'gcc>(bx: &mut Builder<'_, 'gcc, '_>, try_func: RValue<'gcc>, data: RValue<'gcc>, catch_func: RValue<'gcc>, dest: RValue<'gcc>) {
+    //use std::ops::Deref;
+    //let cx: &CodegenCx<'gcc, '_> = bx.deref();
+    let cx: &CodegenCx<'gcc, '_> = bx.cx;
+    let (llty, func) = get_rust_try_fn(cx, &mut |mut bx| {
+        // Codegens the shims described above:
+        //
+        //   bx:
+        //      invoke %try_func(%data) normal %normal unwind %catch
+        //
+        //   normal:
+        //      ret 0
+        //
+        //   catch:
+        //      (%ptr, _) = landingpad
+        //      call %catch_func(%data, %ptr)
+        //      ret 1
+        let then = bx.append_sibling_block("then");
+        let catch = bx.append_sibling_block("catch");
+
+        let func = bx.current_func();
+        let try_func = func.get_param(0).to_rvalue();
+        let data = func.get_param(1).to_rvalue();
+        let catch_func = func.get_param(2).to_rvalue();
+        let try_func_ty = bx.type_func(&[bx.type_i8p()], bx.type_void());
+
+        let current_block = bx.block.clone();
+
+        bx.switch_to_block(then);
+        bx.ret(bx.const_i32(0));
+
+        // Type indicator for the exception being thrown.
+        //
+        // The first value in this tuple is a pointer to the exception object
+        // being thrown.  The second value is a "selector" indicating which of
+        // the landing pad clauses the exception's type had been matched to.
+        // rust_try ignores the selector.
+        bx.switch_to_block(catch);
+        /*let lpad_ty = bx.type_struct(&[bx.type_i8p(), bx.type_i32()], false);
+        let vals = bx.landing_pad(lpad_ty, bx.eh_personality(), 1);
+        let tydesc = bx.const_null(bx.type_i8p());
+        bx.add_clause(vals, tydesc);
+        let ptr = bx.extract_value(vals, 0);*/
+
+        let eh_pointer_builtin = bx.cx.context.get_target_builtin_function("__builtin_eh_pointer");
+        let zero = bx.cx.context.new_rvalue_zero(bx.int_type);
+        let ptr = bx.cx.context.new_call(None, eh_pointer_builtin, &[zero]);
+        let catch_ty = bx.type_func(&[bx.type_i8p(), bx.type_i8p()], bx.type_void());
+        bx.call(catch_ty, catch_func, &[data, ptr], None);
+        bx.ret(bx.const_i32(1));
+
+        // NOTE: the blocks must be filled before adding the try/catch, otherwise gcc will not
+        // generate a try/catch.
+        // FIXME: add a check in the libgccjit API to prevent this.
+        bx.switch_to_block(current_block);
+        bx.invoke(try_func_ty, try_func, &[data], then, catch, None);
+    });
+
+    let func = unsafe { std::mem::transmute(func) };
+
+    // Note that no invoke is used here because by definition this function
+    // can't panic (that's what it's catching).
+    let ret = bx.call(llty, func, &[try_func, data, catch_func], None);
+    let i32_align = bx.tcx().data_layout.i32_align.abi;
+    bx.store(ret, dest, i32_align);
+}
+
+
+// Helper function used to get a handle to the `__rust_try` function used to
+// catch exceptions.
+//
+// This function is only generated once and is then cached.
+fn get_rust_try_fn<'a, 'gcc, 'tcx>(cx: &'a CodegenCx<'gcc, 'tcx>, codegen: &mut dyn FnMut(Builder<'a, 'gcc, 'tcx>)) -> (Type<'gcc>, Function<'gcc>) {
+    if let Some(llfn) = cx.rust_try_fn.get() {
+        return llfn;
+    }
+
+    // Define the type up front for the signature of the rust_try function.
+    let tcx = cx.tcx;
+    let i8p = tcx.mk_mut_ptr(tcx.types.i8);
+    // `unsafe fn(*mut i8) -> ()`
+    let try_fn_ty = tcx.mk_fn_ptr(ty::Binder::dummy(tcx.mk_fn_sig(
+        iter::once(i8p),
+        tcx.mk_unit(),
+        false,
+        rustc_hir::Unsafety::Unsafe,
+        Abi::Rust,
+    )));
+    // `unsafe fn(*mut i8, *mut i8) -> ()`
+    let catch_fn_ty = tcx.mk_fn_ptr(ty::Binder::dummy(tcx.mk_fn_sig(
+        [i8p, i8p].iter().cloned(),
+        tcx.mk_unit(),
+        false,
+        rustc_hir::Unsafety::Unsafe,
+        Abi::Rust,
+    )));
+    // `unsafe fn(unsafe fn(*mut i8) -> (), *mut i8, unsafe fn(*mut i8, *mut i8) -> ()) -> i32`
+    let rust_fn_sig = ty::Binder::dummy(cx.tcx.mk_fn_sig(
+        [try_fn_ty, i8p, catch_fn_ty].into_iter(),
+        &tcx.types.i32,
+        false,
+        rustc_hir::Unsafety::Unsafe,
+        Abi::Rust,
+    ));
+    let rust_try = gen_fn(cx, "__rust_try", rust_fn_sig, codegen);
+    cx.rust_try_fn.set(Some(rust_try));
+    rust_try
+}
+
+// Helper function to give a Block to a closure to codegen a shim function.
+// This is currently primarily used for the `try` intrinsic functions above.
+fn gen_fn<'a, 'gcc, 'tcx>(cx: &'a CodegenCx<'gcc, 'tcx>, name: &str, rust_fn_sig: ty::PolyFnSig<'tcx>, codegen: &mut dyn FnMut(Builder<'a, 'gcc, 'tcx>)) -> (Type<'gcc>, Function<'gcc>) {
+    let fn_abi = cx.fn_abi_of_fn_ptr(rust_fn_sig, ty::List::empty());
+    let (typ, _, _, _) = fn_abi.gcc_type(cx);
+    // FIXME(eddyb) find a nicer way to do this.
+    cx.linkage.set(FunctionType::Internal);
+    let func = cx.declare_fn(name, fn_abi, false);
+    let func_val = unsafe { std::mem::transmute(func) };
+    cx.set_frame_pointer_type(func_val);
+    cx.apply_target_cpu_attr(func_val);
+    let block = Builder::append_block(cx, func_val, "entry-block");
+    let bx = Builder::build(cx, block);
+    codegen(bx);
+    (typ, func)
+}
diff --git a/src/mono_item.rs b/src/mono_item.rs
index ce439d339b6..09ffd8dc798 100644
--- a/src/mono_item.rs
+++ b/src/mono_item.rs
@@ -35,7 +35,10 @@ impl<'gcc, 'tcx> PreDefineMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
 
         let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty());
         self.linkage.set(base::linkage_to_gcc(linkage));
-        let decl = self.declare_fn(symbol_name, &fn_abi);
+        if symbol_name == "rust_eh_personality" {
+            println!("********************* Generating real rust_eh_personality: {:?}", base::linkage_to_gcc(linkage));
+        }
+        let decl = self.declare_fn(symbol_name, &fn_abi, false);
         //let attrs = self.tcx.codegen_fn_attrs(instance.def_id());
 
         attributes::from_fn_attrs(self, decl, instance);
@@ -59,5 +62,11 @@ impl<'gcc, 'tcx> PreDefineMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
         // TODO(antoyo): call set_link_section() to allow initializing argc/argv.
         // TODO(antoyo): set unique comdat.
         // TODO(antoyo): use inline attribute from there in linkage.set() above.
+
+        self.functions.borrow_mut().insert(symbol_name.to_string(), decl);
+        if symbol_name == "rust_eh_personality" {
+            println!("Caching here 2");
+        }
+        self.function_instances.borrow_mut().insert(instance, unsafe { std::mem::transmute(decl) });
     }
 }