2009-01-20 Mark Probst <mark.probst@gmail.com>
authorMark Probst <mark.probst@gmail.com>
Tue, 20 Jan 2009 20:43:04 +0000 (20:43 -0000)
committerMark Probst <mark.probst@gmail.com>
Tue, 20 Jan 2009 20:43:04 +0000 (20:43 -0000)
Backport of r123917.

* 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>

Backport of r123917.

* class.c (mono_class_has_parent_and_ignore_generics),
class-internals.h: Made non-static.

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

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

Backport of r123917.

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

* Makefile.am: Test added.

svn path=/branches/mono-2-2/mono/; revision=123920

mono/metadata/ChangeLog
mono/metadata/class-internals.h
mono/metadata/class.c
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 f4ed1d80b10d2d9c5b474c6e9eed9c1f0e2e25fe..dc03161b08fee1431d8fe030310ef7f8affce4b7 100644 (file)
@@ -1,3 +1,13 @@
+2009-01-20  Mark Probst  <mark.probst@gmail.com>
+
+       Backport of r123917.
+
+       * class.c (mono_class_has_parent_and_ignore_generics),
+       class-internals.h: Made non-static.
+
+       * object-internals.h (struct _MonoException): Added a comment
+       explaining the new use of trace_ips.
+
 2009-01-19  Zoltan Varga  <vargaz@gmail.com>
 
        Backport of r123812.
index 53640c4b06746c7ea423036a800859d670c042c9..13a90f5d26bcf8d1d07bcfa57be94692f24976b3 100644 (file)
@@ -1128,6 +1128,9 @@ mono_method_can_access_method_full (MonoMethod *method, MonoMethod *called, Mono
 gboolean
 mono_method_can_access_field_full (MonoMethod *method, MonoClassField *field, MonoClass *context_klass) MONO_INTERNAL;
 
+gboolean
+mono_class_has_parent_and_ignore_generics (MonoClass *klass, MonoClass *parent) MONO_INTERNAL;
+
 MonoClass *
 mono_class_get_generic_type_definition (MonoClass *klass) MONO_INTERNAL;
 
index ad809aa92202efdc6d80851ea2d6fda1140e48fc..f3340b426bb112f654d42a5185e669b71dcd39ff 100644 (file)
@@ -7132,7 +7132,7 @@ mono_class_get_generic_type_definition (MonoClass *klass)
  * 
  * Visibility checks ignoring generic instantiations.  
  */
-static gboolean
+gboolean
 mono_class_has_parent_and_ignore_generics (MonoClass *klass, MonoClass *parent)
 {
        int i;
index 772ae645d7172f4183f3b5bb773ac2773ad39733..80f62317cfe843c420bc906e30459b60ec4dcda2 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 37f4e8fc8e73260c79f7bc6dbdb359987538c189..90f1712e8f271c5fc16f011c15ca65cb41e7482d 100644 (file)
@@ -1,3 +1,14 @@
+2009-01-20  Mark Probst  <mark.probst@gmail.com>
+
+       Backport of r123917.
+
+       * 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-19  Rodrigo Kumpera  <rkumpera@novell.com>
 
        Backport of r123754.
index e71a9965d0da408fefe4caaefe4527916c5b8545..849720a0b91fb1b94904ab4734e3548ab4d2f112 100644 (file)
@@ -5417,6 +5417,12 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
        }
        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 17cc68acc8b1ef6f0e27253e1698e97ecc58a845..2a403dbeacf2203eaa93fbc72e4479016a6118dc 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)
@@ -915,6 +998,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 fee555cecceb5dbf2b8bfdbb258171620164ca79..90785f206a5fc94f9737746679cc1afe8ab46016 100644 (file)
@@ -1,3 +1,12 @@
+2009-01-20  Mark Probst  <mark.probst@gmail.com>
+
+       Backport of r123917.
+
+       * generic-stack-traces.2.cs: Generic sharing test for stack
+       traces.
+
+       * Makefile.am: Test added.
+
 2009-01-18  Zoltan Varga  <vargaz@gmail.com>
 
        * marshal9.cs: Change a test to be compatible with MS.NET.
index 403d4e9379e1a735cb022b359c9d9ebd1e46d70e..ac48285656cfffcf762f8e998178122f6e8a3de6 100644 (file)
@@ -294,6 +294,7 @@ BASE_TEST_CS_SRC=           \
        generic-virtual-invoke.2.cs     \
        bug-461198.2.cs \
        generic-sealed-virtual.2.cs     \
+       generic-stack-traces.2.cs       \
        recursive-generics.2.cs \
        bug-80392.2.cs          \
        dynamic-method-access.2.cs      \
@@ -727,7 +728,7 @@ 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-sealed-virtual.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;
+    }
+}