Enable support for wrapping non Exception subclasses in RuntimeWrappedException objec...
authorZoltan Varga <vargaz@gmail.com>
Sat, 25 Sep 2010 18:47:10 +0000 (20:47 +0200)
committerZoltan Varga <vargaz@gmail.com>
Sat, 25 Sep 2010 18:48:36 +0000 (20:48 +0200)
mono/metadata/metadata-internals.h
mono/mini/iltests.il.in
mono/mini/mini-exceptions.c
mono/tests/generic-array-exc.2.il
mono/tests/generics-sharing-other-exc.2.il

index 1344632927bdaf94f4a7da82d26cd6443a71b400..655ec7d24c164d11704d2956e8b0cd775eb917d8 100644 (file)
@@ -80,6 +80,8 @@ struct _MonoAssembly {
        guint8 dynamic;
        guint8 corlib_internal;
        gboolean ref_only;
+       guint8 wrap_non_exception_throws;
+       guint8 wrap_non_exception_throws_inited;
        /* security manager flags (one bit is for lazy initialization) */
        guint32 ecma:2;         /* Has the ECMA key */
        guint32 aptc:2;         /* Has the [AllowPartiallyTrustedCallers] attributes */
index 6d63e4171dfea60b437ad0f3f0d665d54a9d3aec..513cf700677a667e61d963f3003aa71e66e68f70 100644 (file)
@@ -1,4 +1,8 @@
-.assembly iltests {}
+.assembly iltests {
+  .custom instance void class [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::'.ctor'() =  (
+               01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78   // ....T..WrapNonEx
+               63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01       ) // ceptionThrows.
+}
 .assembly extern TestDriver {}
 .assembly extern mscorlib {}
 
@@ -2582,4 +2586,19 @@ END:
                          ldc.i4.0
                          ret
     }
+
+       .method public static default int32 test_0_wrap_non_exception_throws () cil managed
+       {
+         .try {
+                   newobj instance void class [mscorlib]System.Object::'.ctor'()
+                       throw
+                 leave IL_0
+         } catch class [mscorlib]System.Runtime.CompilerServices.RuntimeWrappedException {
+                 leave IL_0
+               }
+               IL_0:
+               ldc.i4.0
+               ret
+    }
+
 }
index 4783f7d279a3bf6103470d31d6b61eabf9298fed..934f9ab53836f5b5971265bef9ce0f32fce0aa68 100644 (file)
@@ -43,6 +43,7 @@
 #include <mono/metadata/gc-internal.h>
 #include <mono/metadata/mono-debug.h>
 #include <mono/metadata/profiler.h>
+#include <mono/metadata/mono-endian.h>
 #include <mono/utils/mono-mmap.h>
 
 #include "mini.h"
@@ -1113,6 +1114,72 @@ mini_jit_info_table_find (MonoDomain *domain, char *addr, MonoDomain **out_domai
        return NULL;
 }
 
+/*
+ * wrap_non_exception_throws:
+ *
+ *   Determine whenever M's assembly has a RuntimeCompatibilityAttribute with the
+ * WrapNonExceptionThrows flag set.
+ */
+static gboolean
+wrap_non_exception_throws (MonoMethod *m)
+{
+       MonoAssembly *ass = m->klass->image->assembly;
+       MonoCustomAttrInfo* attrs;
+       static MonoClass *klass;
+       int i;
+       gboolean val = FALSE;
+
+       g_assert (ass);
+       if (ass->wrap_non_exception_throws_inited)
+               return ass->wrap_non_exception_throws;
+
+       klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Runtime.CompilerServices", "RuntimeCompatibilityAttribute");
+
+       attrs = mono_custom_attrs_from_assembly (ass);
+       if (attrs) {
+               for (i = 0; i < attrs->num_attrs; ++i) {
+                       MonoCustomAttrEntry *attr = &attrs->attrs [i];
+                       const gchar *p;
+                       int len, num_named, named_type, data_type, name_len;
+                       char *name;
+
+                       if (!attr->ctor || attr->ctor->klass != klass)
+                               continue;
+                       /* Decode the RuntimeCompatibilityAttribute. See reflection.c */
+                       len = attr->data_size;
+                       p = (const char*)attr->data;
+                       g_assert (read16 (p) == 0x0001);
+                       p += 2;
+                       num_named = read16 (p);
+                       if (num_named != 1)
+                               continue;
+                       p += 2;
+                       named_type = *p;
+                       p ++;
+                       data_type = *p;
+                       p ++;
+                       /* Property */
+                       if (named_type != 0x54)
+                               continue;
+                       name_len = mono_metadata_decode_blob_size (p, &p);
+                       name = g_malloc (name_len + 1);
+                       memcpy (name, p, name_len);
+                       name [name_len] = 0;
+                       p += name_len;
+                       g_assert (!strcmp (name, "WrapNonExceptionThrows"));
+                       g_free (name);
+                       /* The value is a BOOLEAN */
+                       val = *p;
+               }
+       }
+
+       ass->wrap_non_exception_throws = val;
+       mono_memory_barrier ();
+       ass->wrap_non_exception_throws_inited = TRUE;
+
+       return val;
+}
+
 /**
  * mono_handle_exception_internal:
  * @ctx: saved processor state
@@ -1123,7 +1190,7 @@ mini_jit_info_table_find (MonoDomain *domain, char *addr, MonoDomain **out_domai
  * @resume: whenever to resume unwinding based on the state in MonoJitTlsData.
  */
 static gboolean
-mono_handle_exception_internal (MonoContext *ctx, gpointer obj, gpointer original_ip, gboolean test_only, gboolean resume, gint32 *out_filter_idx, MonoJitInfo **out_ji)
+mono_handle_exception_internal (MonoContext *ctx, gpointer obj, gpointer original_ip, gboolean test_only, gboolean resume, gint32 *out_filter_idx, MonoJitInfo **out_ji, MonoObject *non_exception)
 {
        MonoDomain *domain = mono_domain_get ();
        MonoJitInfo *ji, rji;
@@ -1140,7 +1207,6 @@ mono_handle_exception_internal (MonoContext *ctx, gpointer obj, gpointer origina
        gboolean has_dynamic_methods = FALSE;
        gint32 filter_idx, first_filter_idx;
 
-
        g_assert (ctx != NULL);
        if (!obj) {
                MonoException *ex = mono_get_exception_null_reference ();
@@ -1162,19 +1228,13 @@ mono_handle_exception_internal (MonoContext *ctx, gpointer obj, gpointer origina
                obj = mono_get_exception_null_reference ();
        }
 
-#if 0
-       // FIXME: This breaks some tests
-       if (!mono_object_isinst (obj, mono_defaults.exception_class)) {
+       if (!test_only && !mono_object_isinst (obj, mono_defaults.exception_class)) {
+               non_exception = obj;
                obj = mono_get_exception_runtime_wrapped (obj);
-               /*
-                * FIXME: Might have to unwrap this before passing it to a catch clause based on the
-                * RuntimeCompatibilityAttribute.
-                */
        }
 
        mono_ex = (MonoException*)obj;
        initial_trace_ips = mono_ex->trace_ips;
-#endif
 
        if (mono_object_isinst (obj, mono_defaults.exception_class)) {
                mono_ex = (MonoException*)obj;
@@ -1229,7 +1289,7 @@ mono_handle_exception_internal (MonoContext *ctx, gpointer obj, gpointer origina
                                mono_print_thread_dump_from_ctx (ctx);
                }
                mono_profiler_exception_thrown (obj);
-               if (!mono_handle_exception_internal (&ctx_cp, obj, original_ip, TRUE, FALSE, &first_filter_idx, out_ji)) {
+               if (!mono_handle_exception_internal (&ctx_cp, obj, original_ip, TRUE, FALSE, &first_filter_idx, out_ji, non_exception)) {
                        if (mono_break_on_exc)
                                G_BREAKPOINT ();
                        mono_debugger_agent_handle_exception (obj, ctx, NULL);
@@ -1321,6 +1381,7 @@ mono_handle_exception_internal (MonoContext *ctx, gpointer obj, gpointer origina
                         */
                        if ((free_stack > (64 * 1024)) && ji->num_clauses) {
                                int i;
+                               MonoObject *ex_obj;
                                
                                for (i = clause_index_start; i < ji->num_clauses; i++) {
                                        MonoJitExceptionInfo *ei = &ji->clauses [i];
@@ -1339,23 +1400,32 @@ mono_handle_exception_internal (MonoContext *ctx, gpointer obj, gpointer origina
                                                /* catch block */
                                                MonoClass *catch_class = get_exception_catch_class (ei, ji, ctx);
 
+                                               /*
+                                                * Have to unwrap RuntimeWrappedExceptions if the
+                                                * method's assembly doesn't have a RuntimeCompatibilityAttribute.
+                                                */
+                                               if (non_exception && !wrap_non_exception_throws (ji->method))
+                                                       ex_obj = non_exception;
+                                               else
+                                                       ex_obj = obj;
+
                                                if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE) || (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)) {
                                                        if (ji->from_llvm) {
 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
-                                                               MONO_CONTEXT_SET_LLVM_EXC_REG (ctx, obj);
+                                                               MONO_CONTEXT_SET_LLVM_EXC_REG (ctx, ex_obj);
 #else
                                                                g_assert_not_reached ();
 #endif
                                                        } else {
                                                                /* store the exception object in bp + ei->exvar_offset */
-                                                               *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = obj;
+                                                               *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = ex_obj;
                                                        }
                                                }
 
                                                if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
                                                        if (test_only) {
                                                                mono_perfcounters->exceptions_filters++;
-                                                               mono_debugger_call_exception_handler (ei->data.filter, MONO_CONTEXT_GET_SP (ctx), obj);
+                                                               mono_debugger_call_exception_handler (ei->data.filter, MONO_CONTEXT_GET_SP (ctx), ex_obj);
                                                                filtered = call_filter (ctx, ei->data.filter);
                                                                if (filtered && out_filter_idx)
                                                                        *out_filter_idx = filter_idx;
@@ -1373,7 +1443,7 @@ mono_handle_exception_internal (MonoContext *ctx, gpointer obj, gpointer origina
                                                }
 
                                                if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE && 
-                                                    mono_object_isinst (obj, catch_class)) || filtered) {
+                                                    mono_object_isinst (ex_obj, catch_class)) || filtered) {
                                                        if (test_only) {
                                                                if (mono_ex && !initial_trace_ips) {
                                                                        trace_ips = g_list_reverse (trace_ips);
@@ -1424,7 +1494,7 @@ mono_handle_exception_internal (MonoContext *ctx, gpointer obj, gpointer origina
                                                        if (mono_trace_is_enabled () && mono_trace_eval (ji->method))
                                                                g_print ("EXCEPTION: catch found at clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
                                                        mono_profiler_exception_clause_handler (ji->method, ei->flags, i);
-                                                       mono_debugger_call_exception_handler (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), obj);
+                                                       mono_debugger_call_exception_handler (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), ex_obj);
                                                        MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
                                                        *(mono_get_lmf_addr ()) = lmf;
                                                        mono_perfcounters->exceptions_depth += frame_count;
@@ -1438,7 +1508,7 @@ mono_handle_exception_internal (MonoContext *ctx, gpointer obj, gpointer origina
                                                        if (mono_trace_is_enabled () && mono_trace_eval (ji->method))
                                                                g_print ("EXCEPTION: fault clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
                                                        mono_profiler_exception_clause_handler (ji->method, ei->flags, i);
-                                                       mono_debugger_call_exception_handler (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), obj);
+                                                       mono_debugger_call_exception_handler (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), ex_obj);
                                                        call_filter (ctx, ei->handler_start);
                                                }
                                                if (!test_only && is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (ctx)) &&
@@ -1446,7 +1516,7 @@ mono_handle_exception_internal (MonoContext *ctx, gpointer obj, gpointer origina
                                                        if (mono_trace_is_enabled () && mono_trace_eval (ji->method))
                                                                g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
                                                        mono_profiler_exception_clause_handler (ji->method, ei->flags, i);
-                                                       mono_debugger_call_exception_handler (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), obj);
+                                                       mono_debugger_call_exception_handler (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), ex_obj);
                                                        mono_perfcounters->exceptions_finallys++;
                                                        *(mono_get_lmf_addr ()) = lmf;
                                                        if (ji->from_llvm) {
@@ -1547,7 +1617,7 @@ mono_debugger_handle_exception (MonoContext *ctx, MonoObject *obj)
                 * The debugger wants us to stop only if this exception is user-unhandled.
                 */
 
-               ret = mono_handle_exception_internal (&ctx_cp, obj, MONO_CONTEXT_GET_IP (ctx), TRUE, FALSE, NULL, &ji);
+               ret = mono_handle_exception_internal (&ctx_cp, obj, MONO_CONTEXT_GET_IP (ctx), TRUE, FALSE, NULL, &ji, NULL);
                if (ret && (ji != NULL) && (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE)) {
                        /*
                         * The exception is handled in a runtime-invoke wrapper, that means that it's unhandled
@@ -1625,7 +1695,7 @@ mono_handle_exception (MonoContext *ctx, gpointer obj, gpointer original_ip, gbo
        if (!test_only)
                mono_perfcounters->exceptions_thrown++;
 
-       return mono_handle_exception_internal (ctx, obj, original_ip, test_only, FALSE, NULL, NULL);
+       return mono_handle_exception_internal (ctx, obj, original_ip, test_only, FALSE, NULL, NULL, NULL);
 }
 
 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
@@ -2068,7 +2138,7 @@ mono_resume_unwind (MonoContext *ctx)
        MONO_CONTEXT_SET_SP (ctx, MONO_CONTEXT_GET_SP (&jit_tls->resume_state.ctx));
        new_ctx = *ctx;
 
-       mono_handle_exception_internal (&new_ctx, jit_tls->resume_state.ex_obj, NULL, FALSE, TRUE, NULL, NULL);
+       mono_handle_exception_internal (&new_ctx, jit_tls->resume_state.ex_obj, NULL, FALSE, TRUE, NULL, NULL, NULL);
 
        if (!restore_context)
                restore_context = mono_get_restore_context ();
index 875c93ef90cacce68a2b1787d2c1e1258a4e6041..b8856b18d56537432ae73a75dbcb67aa918ed5f0 100644 (file)
@@ -5,10 +5,6 @@
 }
 .assembly 'generic-array-exc.2'
 {
-  .custom instance void class [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() =  (
-               01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78   // ....T..WrapNonEx
-               63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01       ) // ceptionThrows.
-
   .hash algorithm 0x00008004
   .ver  0:0:0:0
 }
index 37ef91e7c8ca3f35e1339d664393d4b2a16189e7..a305b30d4db946377b55d0bf9b8ddfbfe1921e4d 100644 (file)
@@ -5,10 +5,6 @@
 }
 .assembly 'generics-sharing-other-exc.2'
 {
-  .custom instance void class [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() =  (
-               01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78   // ....T..WrapNonEx
-               63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01       ) // ceptionThrows.
-
   .hash algorithm 0x00008004
   .ver  0:0:0:0
 }