2009-01-20 Mark Probst <mark.probst@gmail.com>
authorMark Probst <mark.probst@gmail.com>
Tue, 20 Jan 2009 20:15:29 +0000 (20:15 -0000)
committerMark Probst <mark.probst@gmail.com>
Tue, 20 Jan 2009 20:15:29 +0000 (20:15 -0000)
* method-to-ir.c: Force the vtable variable in shared generic code
for the case that they might show up on a stack trace where they
are needed.

* mini-exceptions.c: Save and use generic sharing info as well as
IP in stack traces to resolve shared generic instantiations.

2009-01-20  Mark Probst  <mark.probst@gmail.com>

* object-internals.h (struct _MonoException): Added a comment
explaining the new use of trace_ips.

2009-01-20  Mark Probst  <mark.probst@gmail.com>

* generic-stack-traces.2.cs: Generic sharing test for stack
traces.

* Makefile.am: Test added.

svn path=/trunk/mono/; revision=123917

mono/metadata/ChangeLog
mono/metadata/object-internals.h
mono/mini/ChangeLog
mono/mini/method-to-ir.c
mono/mini/mini-exceptions.c
mono/tests/ChangeLog
mono/tests/Makefile.am
mono/tests/generic-stack-traces.2.cs [new file with mode: 0644]

index 84c37dc58b8dec9809fd8f1ebd528983415761ca..0b5af3deaa8f2d4ade89639a9603ee6ccfc69461 100644 (file)
@@ -1,3 +1,8 @@
+2009-01-20  Mark Probst  <mark.probst@gmail.com>
+
+       * object-internals.h (struct _MonoException): Added a comment
+       explaining the new use of trace_ips.
+
 2009-01-20  Mark Probst  <mark.probst@gmail.com>
 
        * generic-sharing.c (inflate_other_data): Inflate array methods
index 0d9210c7c87f75dad12ec77dd97dabd25940668e..faa239ece27b6a5cecba3547a2a3cf8fad2690ce 100644 (file)
@@ -140,6 +140,8 @@ typedef struct {
 
 struct _MonoException {
        MonoObject object;
+       /* Stores the IPs and the generic sharing infos
+          (vtable/MRGCTX) of the frames. */
        MonoArray  *trace_ips;
        MonoObject *inner_ex;
        MonoString *message;
index cbc91981a579d44ec98036a1d032906b47b03be7..e1d640781dbd06c9bcebb379810e03d369d70f69 100644 (file)
@@ -1,3 +1,12 @@
+2009-01-20  Mark Probst  <mark.probst@gmail.com>
+
+       * method-to-ir.c: Force the vtable variable in shared generic code
+       for the case that they might show up on a stack trace where they
+       are needed.
+
+       * mini-exceptions.c: Save and use generic sharing info as well as
+       IP in stack traces to resolve shared generic instantiations.
+
 2009-01-20  Zoltan Varga  <vargaz@gmail.com>
 
        * mini-trampolines.c (mono_delegate_trampoline): Revert the change which
index 9aab934595e10e486473d885daf9f442168a666c..e27f645ab51a4ce22ca33aad69f95a25ed33ec2b 100644 (file)
@@ -5407,6 +5407,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        }
        class_inits = NULL;
 
+       /* We force the vtable variable here for all shared methods
+          for the possibility that they might show up in a stack
+          trace where their exact instantiation is needed. */
+       if (cfg->generic_sharing_context)
+               mono_get_vtable_var (cfg);
+
        /* add a check for this != NULL to inlined methods */
        if (is_virtual_call) {
                MonoInst *arg_ins;
index 5cea5237e57aece4c7018bcc8d1870a510d4ff0e..abb2eb5e27ba9d4633561ec1cc699fa5699bd335 100644 (file)
@@ -246,6 +246,82 @@ mono_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *re
        return ji;
 }
 
+static gpointer
+get_generic_info_from_stack_frame (MonoJitInfo *ji, MonoContext *ctx)
+{
+       MonoGenericJitInfo *gi;
+
+       if (!ji->has_generic_jit_info)
+               return NULL;
+       gi = mono_jit_info_get_generic_jit_info (ji);
+       if (!gi->has_this)
+               return NULL;
+
+       if (gi->this_in_reg)
+               return mono_arch_context_get_int_reg (ctx, gi->this_reg);
+       else
+               return *(gpointer*)(gpointer)((char*)mono_arch_context_get_int_reg (ctx, gi->this_reg) +
+                               gi->this_offset);
+}
+
+static MonoGenericContext
+get_generic_context_from_stack_frame (MonoJitInfo *ji, gpointer generic_info)
+{
+       MonoGenericContext context = { NULL, NULL };
+       MonoClass *class, *method_container_class;
+
+       g_assert (generic_info);
+
+       g_assert (ji->method->is_inflated);
+       if (mono_method_get_context (ji->method)->method_inst) {
+               MonoMethodRuntimeGenericContext *mrgctx = generic_info;
+
+               class = mrgctx->class_vtable->klass;
+               context.method_inst = mrgctx->method_inst;
+               g_assert (context.method_inst);
+       } else if ((ji->method->flags & METHOD_ATTRIBUTE_STATIC) || ji->method->klass->valuetype) {
+               MonoVTable *vtable = generic_info;
+
+               class = vtable->klass;
+       } else {
+               MonoObject *this = generic_info;
+
+               class = this->vtable->klass;
+       }
+
+       if (class->generic_class || class->generic_container)
+               context.class_inst = mini_class_get_context (class)->class_inst;
+
+       g_assert (!ji->method->klass->generic_container);
+       if (ji->method->klass->generic_class)
+               method_container_class = ji->method->klass->generic_class->container_class;
+       else
+               method_container_class = ji->method->klass;
+
+       if (class->generic_class)
+               g_assert (mono_class_has_parent_and_ignore_generics (class->generic_class->container_class, method_container_class));
+       else
+               g_assert (mono_class_has_parent_and_ignore_generics (class, method_container_class));
+
+       return context;
+}
+
+static MonoMethod*
+get_method_from_stack_frame (MonoJitInfo *ji, gpointer generic_info)
+{
+       MonoGenericContext context;
+       MonoMethod *method;
+
+       if (!ji->has_generic_jit_info || !mono_jit_info_get_generic_jit_info (ji)->has_this)
+               return ji->method;
+       context = get_generic_context_from_stack_frame (ji, generic_info);
+
+       method = mono_method_get_declaring_generic_method (ji->method);
+       method = mono_class_inflate_generic_method (method, &context);
+
+       return method;
+}
+
 MonoString *
 ves_icall_System_Exception_get_trace (MonoException *ex)
 {
@@ -259,11 +335,12 @@ ves_icall_System_Exception_get_trace (MonoException *ex)
                /* Exception is not thrown yet */
                return NULL;
 
-       len = mono_array_length (ta);
+       len = mono_array_length (ta) >> 1;
        trace_str = g_string_new ("");
        for (i = 0; i < len; i++) {
                MonoJitInfo *ji;
-               gpointer ip = mono_array_get (ta, gpointer, i);
+               gpointer ip = mono_array_get (ta, gpointer, i * 2 + 0);
+               gpointer generic_info = mono_array_get (ta, gpointer, i * 2 + 1);
 
                ji = mono_jit_info_table_find (domain, ip);
                if (ji == NULL) {
@@ -272,10 +349,11 @@ ves_icall_System_Exception_get_trace (MonoException *ex)
                } else {
                        gchar *location;
                        gint32 address;
+                       MonoMethod *method = get_method_from_stack_frame (ji, generic_info);
 
                        address = (char *)ip - (char *)ji->code_start;
                        location = mono_debug_print_stack_frame (
-                               ji->method, address, ex->object.vtable->domain);
+                               method, address, ex->object.vtable->domain);
 
                        g_string_append_printf (trace_str, "%s\n", location);
                        g_free (location);
@@ -301,15 +379,17 @@ ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info
                /* Exception is not thrown yet */
                return mono_array_new (domain, mono_defaults.stack_frame_class, 0);
        }
-       
-       len = mono_array_length (ta);
+
+       len = mono_array_length (ta) >> 1;
 
        res = mono_array_new (domain, mono_defaults.stack_frame_class, len > skip ? len - skip : 0);
 
        for (i = skip; i < len; i++) {
                MonoJitInfo *ji;
                MonoStackFrame *sf = (MonoStackFrame *)mono_object_new (domain, mono_defaults.stack_frame_class);
-               gpointer ip = mono_array_get (ta, gpointer, i);
+               gpointer ip = mono_array_get (ta, gpointer, i * 2 + 0);
+               gpointer generic_info = mono_array_get (ta, gpointer, i * 2 + 1);
+               MonoMethod *method;
 
                ji = mono_jit_info_table_find (domain, ip);
                if (ji == NULL) {
@@ -320,16 +400,17 @@ ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info
 
                g_assert (ji != NULL);
 
+               method = get_method_from_stack_frame (ji, generic_info);
                if (ji->method->wrapper_type) {
                        char *s;
 
                        sf->method = NULL;
-                       s = mono_method_full_name (ji->method, TRUE);
+                       s = mono_method_full_name (method, TRUE);
                        MONO_OBJECT_SETREF (sf, internal_method_name, mono_string_new (domain, s));
                        g_free (s);
                }
                else
-                       MONO_OBJECT_SETREF (sf, method, mono_method_get_object (domain, ji->method, NULL));
+                       MONO_OBJECT_SETREF (sf, method, mono_method_get_object (domain, method, NULL));
                sf->native_offset = (char *)ip - (char *)ji->code_start;
 
                /*
@@ -469,7 +550,7 @@ ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
        MonoJitInfo *ji, rji;
        MonoContext ctx, new_ctx;
        MonoDebugSourceLocation *location;
-       MonoMethod *last_method = NULL;
+       MonoMethod *last_method = NULL, *actual_method;
 
        MONO_ARCH_CONTEXT_DEF;
 
@@ -513,7 +594,9 @@ ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
 
        } while (skip >= 0);
 
-       *method = mono_method_get_object (domain, ji->method, NULL);
+       actual_method = get_method_from_stack_frame (ji, &ctx);
+
+       *method = mono_method_get_object (domain, actual_method, NULL);
 
        location = mono_debug_lookup_source_location (ji->method, *native_offset, domain);
        if (location)
@@ -715,59 +798,15 @@ static MonoClass*
 get_exception_catch_class (MonoJitExceptionInfo *ei, MonoJitInfo *ji, MonoContext *ctx)
 {
        MonoClass *catch_class = ei->data.catch_class;
-       MonoGenericJitInfo *gi;
-       gpointer info;
-       MonoClass *class, *method_container_class;
        MonoType *inflated_type;
-       MonoGenericContext context = { NULL, NULL };
+       MonoGenericContext context;
 
        if (!catch_class)
                return NULL;
 
-       if (!ji->has_generic_jit_info)
+       if (!ji->has_generic_jit_info || !mono_jit_info_get_generic_jit_info (ji)->has_this)
                return catch_class;
-
-       gi = mono_jit_info_get_generic_jit_info (ji);
-       if (!gi->has_this)
-               return catch_class;
-
-       if (gi->this_in_reg)
-               info = mono_arch_context_get_int_reg (ctx, gi->this_reg);
-       else
-               info = *(gpointer*)(gpointer)((char*)mono_arch_context_get_int_reg (ctx, gi->this_reg) +
-                               gi->this_offset);
-
-       g_assert (ji->method->is_inflated);
-
-       if (mono_method_get_context (ji->method)->method_inst) {
-               MonoMethodRuntimeGenericContext *mrgctx = info;
-
-               class = mrgctx->class_vtable->klass;
-               context.method_inst = mrgctx->method_inst;
-               g_assert (context.method_inst);
-       } else if ((ji->method->flags & METHOD_ATTRIBUTE_STATIC) || ji->method->klass->valuetype) {
-               MonoVTable *vtable = info;
-
-               class = vtable->klass;
-       } else {
-               MonoObject *this = info;
-
-               class = this->vtable->klass;
-       }
-
-       if (class->generic_class || class->generic_container)
-               context.class_inst = mini_class_get_context (class)->class_inst;
-
-       g_assert (!ji->method->klass->generic_container);
-       if (ji->method->klass->generic_class)
-               method_container_class = ji->method->klass->generic_class->container_class;
-       else
-               method_container_class = ji->method->klass;
-
-       if (class->generic_class)
-               g_assert (mono_class_has_parent_and_ignore_generics (class->generic_class->container_class, method_container_class));
-       else
-               g_assert (mono_class_has_parent_and_ignore_generics (class, method_container_class));
+       context = get_generic_context_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, ctx));
 
        /* FIXME: we shouldn't inflate but instead put the
           type in the rgctx and fetch it from there.  It
@@ -920,6 +959,8 @@ mono_handle_exception_internal (MonoContext *ctx, gpointer obj, gpointer origina
                                 */
                                if (!initial_trace_ips && (frame_count < 1000)) {
                                        trace_ips = g_list_prepend (trace_ips, MONO_CONTEXT_GET_IP (ctx));
+                                       trace_ips = g_list_prepend (trace_ips,
+                                               get_generic_info_from_stack_frame (ji, ctx));
                                }
                        }
 
index b2cd6735a81ca0f5ca302a2b79d6b692c843b069..0558c418b584bbff059b8df8a20514de2f21d7ae 100644 (file)
@@ -1,3 +1,10 @@
+2009-01-20  Mark Probst  <mark.probst@gmail.com>
+
+       * generic-stack-traces.2.cs: Generic sharing test for stack
+       traces.
+
+       * Makefile.am: Test added.
+
 2009-01-20  Mark Probst  <mark.probst@gmail.com>
 
        * generic-system-arrays.2.cs: Generic sharing test case for
index 0bc4e7a66d3ed73fb058fc4d261a5558037a79da..a3a927320598bc0ab694bc18bd2a5cc60bd20e29 100644 (file)
@@ -295,6 +295,7 @@ BASE_TEST_CS_SRC=           \
        bug-461198.2.cs \
        generic-sealed-virtual.2.cs     \
        generic-system-arrays.2.cs      \
+       generic-stack-traces.2.cs       \
        recursive-generics.2.cs \
        bug-80392.2.cs          \
        dynamic-method-access.2.cs      \
@@ -735,7 +736,8 @@ test-generic-sharing : generics-sharing.2.exe shared-generic-methods.2.exe  \
                generic-constrained.2.exe bug-431413.2.exe                      \
                generic-virtual-invoke.2.exe generic-typedef.2.exe              \
                generic-marshalbyref.2.exe bug-459285.2.exe bug-461198.2.exe    \
-               generic-sealed-virtual.2.exe generic-system-arrays.2.exe
+               generic-sealed-virtual.2.exe generic-system-arrays.2.exe        \
+               generic-stack-traces.2.exe
        @for fn in $+ ; do      \
                echo "Testing $$fn ...";        \
                MONO_GENERIC_SHARING=all $(RUNTIME) -O=gshared                $$fn > $$fn.stdout || exit 1;     \
diff --git a/mono/tests/generic-stack-traces.2.cs b/mono/tests/generic-stack-traces.2.cs
new file mode 100644 (file)
index 0000000..c8ae9bf
--- /dev/null
@@ -0,0 +1,75 @@
+using System;
+using System.Diagnostics;
+using System.Reflection;
+
+public class Gen<T> {
+    public static void staticCrash () {
+       object o = null;
+       o.GetType ();
+    }
+
+    public void callStaticCrash () {
+       staticCrash ();
+    }
+}
+
+public class main {
+    public static void callCallStaticCrash<T> () {
+       Gen<T> gt = new Gen<T> ();
+       gt.callStaticCrash ();
+    }
+
+    public static bool test (Exception exc, Type type) {
+       StackTrace st = new StackTrace (exc);
+       for (int i = 0; i < st.FrameCount; ++i) {
+           StackFrame sf = st.GetFrame (i);
+           MethodBase m = sf.GetMethod ();
+           Type t = m.DeclaringType;
+           if (m.IsGenericMethod) {
+               Type[] margs = m.GetGenericArguments ();
+               //Console.WriteLine (m.Name);
+               if (margs.Length != 1)
+                   return false;
+               if (margs [0] != type)
+                   return false;
+           }
+           if (t.IsGenericType) {
+               Type[] targs = t.GetGenericArguments ();
+               //Console.WriteLine (t.FullName);
+               if (targs.Length != 1)
+                   return false;
+               if (targs [0] != type)
+                   return false;
+           }
+       }
+       return true;
+    }
+
+    public static int Main () {
+       try {
+           callCallStaticCrash <int> ();
+       } catch (Exception exc) {
+           if (!test (exc, typeof (int)))
+               return 1;
+       }
+       try {
+           callCallStaticCrash <object> ();
+       } catch (Exception exc) {
+           if (!test (exc, typeof (object)))
+               return 1;
+       }
+       try {
+           callCallStaticCrash <string> ();
+       } catch (Exception exc) {
+           if (!test (exc, typeof (string)))
+               return 1;
+       }
+       try {
+           callCallStaticCrash <Gen<string>> ();
+       } catch (Exception exc) {
+           if (!test (exc, typeof (Gen<string>)))
+               return 1;
+       }
+       return 0;
+    }
+}