[interp] basic filter clause support
authorBernhard Urban <bernhard.urban@xamarin.com>
Thu, 30 Mar 2017 15:50:03 +0000 (11:50 -0400)
committerBernhard Urban <bernhard.urban@xamarin.com>
Thu, 30 Mar 2017 19:16:17 +0000 (15:16 -0400)
mono/mini/exceptions.cs
mono/mini/iltests.il
mono/mini/interp/interp.c
mono/mini/interp/mintops.def
mono/mini/interp/transform.c

index 4755adbaab1f01f086f98a416846348c5356ca8a..c7b10b3a4c1517217b7c56e798bf9379bced451c 100644 (file)
@@ -2846,6 +2846,72 @@ class Tests
                }
                return 0;
        }
+
+       public class MyException : Exception {
+               public int marker = 0;
+               public string res = "";
+
+               public MyException (String res) {
+                       this.res = res;
+               }
+
+               public bool FilterWithoutState () {
+                       return this.marker == 0x666;
+               }
+
+               public bool FilterWithState () {
+                       bool ret = this.marker == 0x566;
+                       this.marker += 0x100;
+                       return ret;
+               }
+
+               public bool FilterWithStringState () {
+                       bool ret = this.marker == 0x777;
+                       this.res = "fromFilter_" + this.res;
+                       return ret;
+               }
+       }
+
+       public static int test_1_basic_filter_catch () {
+               try {
+                       MyException e = new MyException ("");
+                       e.marker = 0x1337;
+                       throw e;
+               } catch (MyException ex) when (ex.marker == 0x1337) {
+                       return 1;
+               }
+               return 0;
+       }
+
+       public static int test_1234_complicated_filter_catch () {
+               string res = "init";
+               try {
+                       MyException e = new MyException (res);
+                       e.marker = 0x566;
+                       try {
+                               try {
+                                       throw e;
+                               } catch (MyException ex) when (ex.FilterWithoutState ()) {
+                                       res = "WRONG_" + res;
+                               } finally {
+                                       e.marker = 0x777;
+                                       res = "innerFinally_" + res;
+                               }
+                       } catch (MyException ex) when (ex.FilterWithState ()) {
+                               res = "2ndcatch_" + res;
+                       }
+                       // "2ndcatch_innerFinally_init"
+                       // Console.WriteLine ("res1: " + res);
+                       e.res = res;
+                       throw e;
+               } catch (MyException ex) when (ex.FilterWithStringState ()) {
+                       res = "fwos_" + ex.res;
+               } finally {
+                       res = "outerFinally_" + res;
+               }
+               // Console.WriteLine ("res2: " + res);
+               return "outerFinally_fwos_fromFilter_2ndcatch_innerFinally_init" == res ? 1234 : 0;
+       }
 }
 
 #if !__MOBILE__
index d1b03b3931b21e42e60353b4c0dbab3051983496..88eac7edb4550f5cfbea080941a36a37afc95da7 100644 (file)
@@ -1247,7 +1247,6 @@ COND:   ldloc.0
        }
 
        .method public static int32 test_1_filters () {
-               .custom instance void [TestDriver]CategoryAttribute::.ctor(string) = ( 01 00 0C 21 49 4E 54 45 52 50 52 45 54 45 52 00 00 )   // ...!INTERPRETER.
                .custom instance void [TestDriver]CategoryAttribute::.ctor(string) = ( 01 00 08 21 42 49 54 43 4F 44 45 00 00 )          // ...!BITCODE..
                .maxstack 16
                .locals init (
index dcea13fe0d09c4ce431dbe5b94b32bf8e1bddb7e..8d2a26859053f0830db1a8e3416508db811b7a86 100644 (file)
@@ -2001,8 +2001,11 @@ static int opcode_counts[512];
 #define MINT_IN_DEFAULT default:
 #endif
 
+static void
+ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context);
+
 static void 
-ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
+ves_exec_method_with_context_with_ip (MonoInvocation *frame, ThreadContext *context, unsigned short *start_with_ip, MonoException *filter_exception)
 {
        MonoInvocation child_frame;
        GSList *finally_ips = NULL;
@@ -2054,25 +2057,26 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
        }
 
        rtm = frame->runtime_method;
-       frame->args = alloca (rtm->alloca_size);
-       memset (frame->args, 0, rtm->alloca_size);
-
-       sp = frame->stack = (stackval *)((char *)frame->args + rtm->args_size);
-       memset (sp, 0, rtm->stack_size);
+       if (!start_with_ip ) {
+               frame->args = alloca (rtm->alloca_size);
+               memset (frame->args, 0, rtm->alloca_size);
 
+               ip = rtm->code;
+       } else {
+               ip = start_with_ip;
+       }
+       sp = frame->stack = (stackval *) ((char *) frame->args + rtm->args_size);
        vt_sp = (unsigned char *) sp + rtm->stack_size;
-       memset (vt_sp, 0, rtm->vt_stack_size);
 #if DEBUG_INTERP
        vtalloc = vt_sp;
 #endif
-
        locals = (unsigned char *) vt_sp + rtm->vt_stack_size;
-       memset (vt_sp, 0, rtm->locals_size);
-
        child_frame.parent = frame;
 
-       /* ready to go */
-       ip = rtm->code;
+       if (filter_exception) {
+               sp->data.p = filter_exception;
+               sp++;
+       }
 
        /*
         * using while (ip < end) may result in a 15% performance drop, 
@@ -4573,9 +4577,10 @@ array_constructed:
                        ++ip;
                        MINT_IN_BREAK;
                }
-#if 0
-               MINT_IN_CASE(MINT_ENDFILTER) ves_abort(); MINT_IN_BREAK;
-#endif
+               MINT_IN_CASE(MINT_ENDFILTER)
+                       /* top of stack is result of filter */
+                       frame->retval = &sp [-1];
+                       goto exit_frame;
                MINT_IN_CASE(MINT_INITOBJ)
                        --sp;
                        memset (sp->data.vt, 0, READ32(ip + 1));
@@ -4672,24 +4677,44 @@ array_constructed:
                        inv->ex_handler = NULL; /* clear this in case we are trhowing an exception while handling one  - this one wins */
                        for (i = 0; i < inv->runtime_method->num_clauses; ++i) {
                                clause = &inv->runtime_method->clauses [i];
-                               if (clause->flags <= 1 && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
-                                       if (!clause->flags) {
-                                               MonoObject *isinst_obj = mono_object_isinst_checked ((MonoObject*)frame->ex, clause->data.catch_class, &error);
-                                               mono_error_cleanup (&error); /* FIXME: don't swallow the error */
-                                               if (isinst_obj) {
-                                                       /* 
-                                                        * OK, we found an handler, now we need to execute the finally
-                                                        * and fault blocks before branching to the handler code.
-                                                        */
-                                                       inv->ex_handler = clause;
 #if DEBUG_INTERP
-                                                       if (tracing)
-                                                               g_print ("* Found handler at '%s'\n", method->name);
+                               g_print ("* clause [%d]: %p\n", i, clause);
+#endif
+                               if (!MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
+                                       continue;
+                               }
+                               if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
+#if DEBUG_INTERP
+                                       if (tracing)
+                                               g_print ("* Filter found at '%s'\n", method->name);
+#endif
+                                       MonoInvocation dup_frame;
+                                       stackval retval;
+                                       memcpy (&dup_frame, inv, sizeof (MonoInvocation));
+                                       dup_frame.retval = &retval;
+                                       ves_exec_method_with_context_with_ip (&dup_frame, context, inv->runtime_method->code + clause->data.filter_offset, frame->ex);
+                                       if (dup_frame.retval->data.i) {
+#if DEBUG_INTERP
+                                               if (tracing)
+                                                       g_print ("* Matched Filter at '%s'\n", method->name);
+#endif
+                                               inv->ex_handler = clause;
+                                               goto handle_finally;
+                                       }
+                               } else if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE) {
+                                       MonoObject *isinst_obj = mono_object_isinst_checked ((MonoObject*)frame->ex, clause->data.catch_class, &error);
+                                       mono_error_cleanup (&error); /* FIXME: don't swallow the error */
+                                       if (isinst_obj) {
+                                               /* 
+                                                * OK, we found an handler, now we need to execute the finally
+                                                * and fault blocks before branching to the handler code.
+                                                */
+#if DEBUG_INTERP
+                                               if (tracing)
+                                                       g_print ("* Found handler at '%s'\n", method->name);
 #endif
-                                                       goto handle_finally;
-                                               }
-                                       } else {
-                                               g_error ("FIXME: handle filter clause");
+                                               inv->ex_handler = clause;
+                                               goto handle_finally;
                                        }
                                }
                        }
@@ -4815,6 +4840,12 @@ exit_frame:
        DEBUG_LEAVE ();
 }
 
+static void
+ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
+{
+       ves_exec_method_with_context_with_ip (frame, context, NULL, NULL);
+}
+
 void
 ves_exec_method (MonoInvocation *frame)
 {
index 43f4e6b124f9fcd6d70a9f9ba82e23b24aae459a..39330d479f7eea4098161b4560d21350b6d289db 100644 (file)
@@ -266,6 +266,8 @@ OPDEF(MINT_JMP, "jmp", 2, MintOpMethodToken)
 
 OPDEF(MINT_CALLRUN, "callrun", 1, MintOpNoArgs)
 
+OPDEF(MINT_ENDFILTER, "endfilter", 1, MintOpNoArgs)
+
 OPDEF(MINT_NEWOBJ, "newobj", 2, MintOpMethodToken) 
 OPDEF(MINT_INITOBJ, "initobj", 3, MintOpInt) 
 OPDEF(MINT_CASTCLASS, "castclass", 2, MintOpClassToken) 
index ee5f65ac116c34916a3cb621e4d10b90fd262db6..6012bb1e1d78eb1b5b26a0a0972cbecedfebc594 100644 (file)
@@ -977,6 +977,17 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo
                td.stack_state [c->handler_offset] = g_malloc0(sizeof(StackInfo));
                td.stack_state [c->handler_offset][0].type = STACK_TYPE_O;
                td.stack_state [c->handler_offset][0].klass = NULL; /*FIX*/
+
+               if (c->flags & MONO_EXCEPTION_CLAUSE_FILTER) {
+                       td.stack_height [c->data.filter_offset] = 0;
+                       td.vt_stack_size [c->data.filter_offset] = 0;
+                       td.is_bb_start [c->data.filter_offset] = 1;
+
+                       td.stack_height [c->data.filter_offset] = 1;
+                       td.stack_state [c->data.filter_offset] = g_malloc0(sizeof(StackInfo));
+                       td.stack_state [c->data.filter_offset][0].type = STACK_TYPE_O;
+                       td.stack_state [c->data.filter_offset][0].klass = NULL; /*FIX*/
+               }
        }
 
        td.ip = header->code;
@@ -3106,8 +3117,11 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo
                                break;
 #if 0
                        case CEE_UNUSED57: ves_abort(); break;
-                       case CEE_ENDFILTER: ves_abort(); break;
 #endif
+                       case CEE_ENDFILTER:
+                               ADD_CODE (&td, MINT_ENDFILTER);
+                               ++td.ip;
+                               break;
                        case CEE_UNALIGNED_:
                                ++td.ip;
                                /* FIX: should do something? */;
@@ -3236,6 +3250,8 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo
                end_off = c->handler_offset + c->handler_len;
                c->handler_offset = td.in_offsets [c->handler_offset];
                c->handler_len = td.in_offsets [end_off] - c->handler_offset;
+               if (c->flags & MONO_EXCEPTION_CLAUSE_FILTER)
+                       c->data.filter_offset = td.in_offsets [c->data.filter_offset];
        }
        rtm->vt_stack_size = td.max_vt_sp;
        rtm->alloca_size = rtm->locals_size + rtm->args_size + rtm->vt_stack_size + rtm->stack_size;