[llvm] Generate code at the start of exception clauses to branch to the proper nestin...
authorZoltan Varga <vargaz@gmail.com>
Mon, 30 Mar 2015 02:22:29 +0000 (22:22 -0400)
committerZoltan Varga <vargaz@gmail.com>
Mon, 30 Mar 2015 02:26:58 +0000 (22:26 -0400)
mono/mini/mini-amd64.h
mono/mini/mini-exceptions.c
mono/mini/mini-llvm.c

index 7f8f8ace1c58da3d473599c5f77fcb54dead7bec..f6eb5f1aeed781a3d8a52d0b1ca326795ce6fbdb 100644 (file)
@@ -233,6 +233,7 @@ typedef struct {
 
 
 #define MONO_CONTEXT_SET_LLVM_EXC_REG(ctx, exc) do { (ctx)->rax = (gsize)exc; } while (0)
+#define MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG(ctx, sel) do { (ctx)->rdx = (gsize)(sel); } while (0)
 
 #define MONO_ARCH_INIT_TOP_LMF_ENTRY(lmf)
 
index 9f21cd5b3ed05a9c9d9026bdf7fb0fc14bdbab18..1be5fe77516b8a667af4adba26450052299ebf68 100644 (file)
@@ -1494,6 +1494,11 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, gpointer obj, gint3
                                                *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = ex_obj;
                                        }
 
+#ifdef MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG
+                                       if (ji->from_llvm)
+                                               MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG (ctx, i);
+#endif
+
                                        mono_debugger_agent_begin_exception_filter (mono_ex, ctx, &initial_ctx);
                                        filtered = call_filter (ctx, ei->data.filter);
                                        mono_debugger_agent_end_exception_filter (mono_ex, ctx, &initial_ctx);
@@ -1789,6 +1794,11 @@ mono_handle_exception_internal (MonoContext *ctx, gpointer obj, gboolean resume,
                                        }
                                }
 
+#ifdef MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG
+                               if (ji->from_llvm)
+                                       MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG (ctx, i);
+#endif
+
                                if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
                                        /* 
                                         * Filter clauses should only be run in the 
index 21d697690a8d9374c2496cef19762a74f65d68ff..3085591fac47a48ad57d72886fddfe483461d2be 100644 (file)
@@ -2465,6 +2465,7 @@ emit_handler_start (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef builder
        BBInfo *bblocks = ctx->bblocks;
        LLVMTypeRef i8ptr;
        LLVMValueRef personality;
+       LLVMValueRef landing_pad;
        LLVMBasicBlockRef target_bb;
        MonoInst *exvar;
        static gint32 mapping_inited;
@@ -2473,6 +2474,7 @@ emit_handler_start (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef builder
        MonoClass **ti;
        LLVMValueRef type_info;
        int clause_index;
+       GSList *l;
 
        // <resultval> = landingpad <somety> personality <type> <pers_fn> <clause>+
 
@@ -2526,7 +2528,6 @@ emit_handler_start (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef builder
 
        {
                LLVMTypeRef members [2], ret_type;
-               LLVMValueRef landing_pad;
 
                members [0] = i8ptr;
                members [1] = LLVMInt32Type ();
@@ -2548,11 +2549,69 @@ emit_handler_start (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef builder
                }
        }
 
+#ifdef MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG
+       /*
+        * LLVM throw sites are associated with a one landing pad, and LLVM generated
+        * code expects control to be transferred to this landing pad even in the
+        * presence of nested clauses. The landing pad needs to branch to the landing
+        * pads belonging to nested clauses based on the selector value returned by
+        * the landing pad instruction, which is passed to the landing pad in a
+        * register by the EH code.
+        */
+       /* Store the exception object into the eh variable of nested clauses. */
+       for (l = ctx->nested_in [clause_index]; l; l = l->next) {
+               int nesting_clause_index = GPOINTER_TO_INT (l->data);
+               MonoBasicBlock *handler_bb;
+
+               handler_bb = g_hash_table_lookup (ctx->clause_to_handler, GINT_TO_POINTER (nesting_clause_index));
+               g_assert (handler_bb);
+
+               if (handler_bb->in_scount == 1) {
+                       LLVMValueRef ex_obj = LLVMBuildExtractValue (builder, landing_pad, 0, "ex_obj");
+                       MonoInst *var;
+                       int vreg;
+
+                       exvar = handler_bb->in_stack [0];
+                       vreg = exvar->dreg;
+
+                       /*
+                        * Can't assign to exvar directly, because of SSA, so store into
+                        * the location where the (volatile) exvar is stored.
+                        */
+
+                       /* From emit_volatile_store () */
+                       var = get_vreg_to_inst (ctx->cfg, vreg);
+
+                       g_assert (var && var->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT));
+                       g_assert (ctx->addresses [vreg]);
+                       LLVMBuildStore (ctx->builder, convert (ctx, ex_obj, type_to_llvm_type (ctx, var->inst_vtype)), ctx->addresses [vreg]);
+               }
+       }
+
+       target_bb = bblocks [bb->block_num].call_handler_target_bb;
+       g_assert (target_bb);
+#endif
+
+       /*
+        * Branch to the correct landing pad
+        */
+       LLVMValueRef ex_selector = LLVMBuildExtractValue (builder, landing_pad, 1, "ex_selector");
+       LLVMValueRef switch_ins = LLVMBuildSwitch (builder, ex_selector, target_bb, 0);
+
+       for (l = ctx->nested_in [clause_index]; l; l = l->next) {
+               int nesting_clause_index = GPOINTER_TO_INT (l->data);
+               MonoBasicBlock *handler_bb;
+
+               handler_bb = g_hash_table_lookup (ctx->clause_to_handler, GINT_TO_POINTER (nesting_clause_index));
+               g_assert (handler_bb);
+
+               g_assert (ctx->bblocks [handler_bb->block_num].call_handler_target_bb);
+               LLVMAddCase (switch_ins, LLVMConstInt (LLVMInt32Type (), nesting_clause_index, FALSE), ctx->bblocks [handler_bb->block_num].call_handler_target_bb);
+       }
+
        /* Start a new bblock which CALL_HANDLER can branch to */
        target_bb = bblocks [bb->block_num].call_handler_target_bb;
        if (target_bb) {
-               LLVMBuildBr (builder, target_bb);
-
                ctx->builder = builder = create_builder (ctx);
                LLVMPositionBuilderAtEnd (ctx->builder, target_bb);