[llvm] Add support for fault clauses. Fixes #58114. (#5203)
authorZoltan Varga <vargaz@gmail.com>
Fri, 14 Jul 2017 04:43:23 +0000 (00:43 -0400)
committerGitHub <noreply@github.com>
Fri, 14 Jul 2017 04:43:23 +0000 (00:43 -0400)
mono/mini/iltests.il
mono/mini/mini-llvm.c

index 88eac7edb4550f5cfbea080941a36a37afc95da7..09c94309b70353d96b20dcc7a676d4e01665515b 100644 (file)
@@ -2820,4 +2820,80 @@ END:
        pop
        ret
   }
+
+  .method public static int32 test_2_fault () cil managed
+  {
+       .maxstack 16
+       .locals init (int32 V_0)
+    IL_0000:  ldc.i4.0
+    IL_0001:  stloc.0
+    .try
+    {
+      .try
+      {
+        IL_0002:  newobj     instance void [mscorlib]System.Exception::.ctor()
+        IL_0007:  throw
+               leave.s    IL_0018
+      }  // end .try
+         fault
+      {
+        IL_0009:  ldloc.0
+        IL_000a:  ldc.i4.1
+        IL_000b:  add
+        IL_000c:  stloc.0
+                                 endfinally
+      }  // end handler
+      IL_000f:  leave.s    IL_0018
+
+    }  // end .try
+    catch [mscorlib]System.Object
+    {
+      IL_0011:  pop
+      IL_0012:  ldloc.0
+      IL_0013:  ldc.i4.1
+      IL_0014:  add
+      IL_0015:  stloc.0
+      IL_0016:  leave.s    IL_0018
+
+    }  // end handler
+    IL_0018:  ldloc.0
+       ret
+       }
+
+  .method public static int32 test_0_fault_no_exception () cil managed
+  {
+       .maxstack 16
+       .locals init (int32 V_0)
+    IL_0000:  ldc.i4.0
+    IL_0001:  stloc.0
+    .try
+    {
+      .try
+      {
+               leave.s    IL_0018
+      }  // end .try
+         fault
+      {
+        IL_0009:  ldloc.0
+        IL_000a:  ldc.i4.1
+        IL_000b:  add
+        IL_000c:  stloc.0
+                                 endfinally
+      }  // end handler
+      IL_000f:  leave.s    IL_0018
+
+    }  // end .try
+    catch [mscorlib]System.Object
+    {
+      IL_0011:  pop
+      IL_0012:  ldloc.0
+      IL_0013:  ldc.i4.1
+      IL_0014:  add
+      IL_0015:  stloc.0
+      IL_0016:  leave.s    IL_0018
+
+    }  // end handler
+    IL_0018:  ldloc.0
+       ret
+       }
 }
index f1bec8a2a156f545fceb3457821e42de8aab5310..75e60e6dcd91e1fed9d85437a666b3501622f727 100644 (file)
@@ -1832,7 +1832,7 @@ emit_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, LL
                clause = get_most_deep_clause (cfg, ctx, bb);
 
                if (clause) {
-                       g_assert (clause->flags == MONO_EXCEPTION_CLAUSE_NONE || clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY);
+                       g_assert (clause->flags == MONO_EXCEPTION_CLAUSE_NONE || clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY || clause->flags == MONO_EXCEPTION_CLAUSE_FAULT);
 
                        /*
                         * Have to use an invoke instead of a call, branching to the
@@ -1871,7 +1871,7 @@ emit_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, LL
                         * handler bblock of the clause containing this bblock.
                         */
 
-                       g_assert (ec->flags == MONO_EXCEPTION_CLAUSE_NONE || ec->flags == MONO_EXCEPTION_CLAUSE_FINALLY);
+                       g_assert (ec->flags == MONO_EXCEPTION_CLAUSE_NONE || ec->flags == MONO_EXCEPTION_CLAUSE_FINALLY || ec->flags == MONO_EXCEPTION_CLAUSE_FAULT);
 
                        tblock = cfg->cil_offset_to_bb [ec->handler_offset];
                        g_assert (tblock);
@@ -3911,7 +3911,7 @@ emit_landing_pad (EmitContext *ctx, int group_index, int group_size)
        MonoExceptionClause *group_cursor = group_start;
 
        for (int i = 0; i < group_size; i ++) {
-               if (!(group_cursor->flags & MONO_EXCEPTION_CLAUSE_FINALLY))
+               if (!(group_cursor->flags & MONO_EXCEPTION_CLAUSE_FINALLY || group_cursor->flags & MONO_EXCEPTION_CLAUSE_FAULT))
                        finally_only = FALSE;
 
                group_cursor++;
@@ -3960,7 +3960,7 @@ emit_llvmonly_handler_start (EmitContext *ctx, MonoBasicBlock *bb, LLVMBasicBloc
        MonoExceptionClause *clause = &ctx->cfg->header->clauses [clause_index];
 
        // Make exception available to catch blocks
-       if (!(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
+       if (!(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY || clause->flags & MONO_EXCEPTION_CLAUSE_FAULT)) {
                LLVMValueRef mono_exc = mono_llvm_emit_load_exception_call (ctx, ctx->builder);
 
                g_assert (ctx->ex_var);
@@ -6537,33 +6537,39 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        LLVMValueRef val, switch_ins, callee;
                        GSList *bb_list;
                        BBInfo *info;
+                       gboolean is_fault = MONO_REGION_FLAGS (bb->region) == MONO_EXCEPTION_CLAUSE_FAULT;
 
-                       handler_bb = (MonoBasicBlock*)g_hash_table_lookup (ctx->region_to_handler, GUINT_TO_POINTER (mono_get_block_region_notry (cfg, bb->region)));
-                       g_assert (handler_bb);
-                       info = &bblocks [handler_bb->block_num];
-                       lhs = info->finally_ind;
-                       g_assert (lhs);
+                       /*
+                        * Fault clauses are like finally clauses, but they are only called if an exception is thrown.
+                        */
+                       if (!is_fault) {
+                               handler_bb = (MonoBasicBlock*)g_hash_table_lookup (ctx->region_to_handler, GUINT_TO_POINTER (mono_get_block_region_notry (cfg, bb->region)));
+                               g_assert (handler_bb);
+                               info = &bblocks [handler_bb->block_num];
+                               lhs = info->finally_ind;
+                               g_assert (lhs);
 
-                       bb_list = info->call_handler_return_bbs;
+                               bb_list = info->call_handler_return_bbs;
 
-                       resume_bb = gen_bb (ctx, "ENDFINALLY_RESUME_BB");
+                               resume_bb = gen_bb (ctx, "ENDFINALLY_RESUME_BB");
 
-                       /* Load the finally variable */
-                       val = LLVMBuildLoad (builder, lhs, "");
+                               /* Load the finally variable */
+                               val = LLVMBuildLoad (builder, lhs, "");
 
-                       /* Reset the variable */
-                       LLVMBuildStore (builder, LLVMConstInt (LLVMInt32Type (), 0, FALSE), lhs);
+                               /* Reset the variable */
+                               LLVMBuildStore (builder, LLVMConstInt (LLVMInt32Type (), 0, FALSE), lhs);
 
-                       /* Branch to either resume_bb, or to the bblocks in bb_list */
-                       switch_ins = LLVMBuildSwitch (builder, val, resume_bb, g_slist_length (bb_list));
-                       /* 
-                        * The other targets are added at the end to handle OP_CALL_HANDLER
-                        * opcodes processed later.
-                        */
-                       info->endfinally_switch_ins_list = g_slist_append_mempool (cfg->mempool, info->endfinally_switch_ins_list, switch_ins);
+                               /* Branch to either resume_bb, or to the bblocks in bb_list */
+                               switch_ins = LLVMBuildSwitch (builder, val, resume_bb, g_slist_length (bb_list));
+                               /*
+                                * The other targets are added at the end to handle OP_CALL_HANDLER
+                                * opcodes processed later.
+                                */
+                               info->endfinally_switch_ins_list = g_slist_append_mempool (cfg->mempool, info->endfinally_switch_ins_list, switch_ins);
 
-                       builder = ctx->builder = create_builder (ctx);
-                       LLVMPositionBuilderAtEnd (ctx->builder, resume_bb);
+                               builder = ctx->builder = create_builder (ctx);
+                               LLVMPositionBuilderAtEnd (ctx->builder, resume_bb);
+                       }
 
                        if (ctx->llvm_only) {
                                emit_resume_eh (ctx, bb);
@@ -7003,8 +7009,8 @@ emit_method_inner (EmitContext *ctx)
        header = cfg->header;
        for (i = 0; i < header->num_clauses; ++i) {
                clause = &header->clauses [i];
-               if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_NONE) {
-                   set_failure (ctx, "non-finally/catch clause.");
+               if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FAULT && clause->flags != MONO_EXCEPTION_CLAUSE_NONE) {
+                   set_failure (ctx, "non-finally/catch/fault clause.");
                        return;
                }
        }