Add unit test for AggregateException.GetBaseException that works on .net but is broke...
[mono.git] / mono / mini / mini-trampolines.c
index 30880c89f940cd6e923dcd6e44e913d1c122fbd7..b95ccf557c24c6aa6198cfd45e8c87b4cb256228 100644 (file)
@@ -12,9 +12,9 @@
 #include <mono/metadata/tabledefs.h>
 #include <mono/utils/mono-counters.h>
 #include <mono/utils/mono-error-internals.h>
+#include <mono/utils/mono-membar.h>
 
 #include "mini.h"
-#include "debug-mini.h"
 
 /*
  * Address of the trampoline code.  This is used by the debugger to check
@@ -31,24 +31,6 @@ static guint32 trampoline_calls, jit_trampolines, unbox_trampolines, static_rgct
 #define mono_trampolines_unlock() LeaveCriticalSection (&trampolines_mutex)
 static CRITICAL_SECTION trampolines_mutex;
 
-static gpointer
-get_unbox_trampoline (MonoMethod *m, gpointer addr, gboolean need_rgctx_tramp)
-{
-       if (mono_aot_only) {
-               if (need_rgctx_tramp)
-                       /* 
-                        * The unbox trampolines call the method directly, so need to add
-                        * an rgctx tramp before them.
-                        */
-                       return mono_create_static_rgctx_trampoline (m, mono_aot_get_unbox_trampoline (m));
-               else
-                       return mono_aot_get_unbox_trampoline (m);
-       } else {
-               unbox_trampolines ++;
-               return mono_arch_get_unbox_trampoline (m, addr);
-       }
-}
-
 #ifdef MONO_ARCH_GSHARED_SUPPORTED
 
 typedef struct {
@@ -166,7 +148,7 @@ static gpointer*
  */
 __attribute__ ((noinline))
 #endif
-mono_convert_imt_slot_to_vtable_slot (gpointer* slot, mgreg_t *regs, guint8 *code, MonoMethod *method, MonoMethod **impl_method, gboolean *need_rgctx_tramp, gboolean *variance_used, gpointer *aot_addr)
+       mono_convert_imt_slot_to_vtable_slot (gpointer* slot, mgreg_t *regs, guint8 *code, MonoMethod *method, gboolean lookup_aot, MonoMethod **impl_method, gboolean *need_rgctx_tramp, gboolean *variance_used, gpointer *aot_addr)
 {
        MonoObject *this_argument = mono_arch_get_this_arg_from_call (regs, code);
        MonoVTable *vt = this_argument->vtable;
@@ -208,7 +190,7 @@ mono_convert_imt_slot_to_vtable_slot (gpointer* slot, mgreg_t *regs, guint8 *cod
                        impl = mono_class_inflate_generic_method (impl, &context);
                } else {
                        /* Avoid loading metadata or creating a generic vtable if possible */
-                       if (!vt->klass->valuetype)
+                       if (lookup_aot && !vt->klass->valuetype)
                                *aot_addr = mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, interface_offset + mono_method_get_vtable_slot (imt_method));
                        else
                                *aot_addr = NULL;
@@ -284,8 +266,9 @@ is_generic_method_definition (MonoMethod *m)
                return TRUE;
        return FALSE;
 }
-static gboolean
-ji_is_gsharedvt (MonoJitInfo *ji)
+
+gboolean
+mini_jit_info_is_gsharedvt (MonoJitInfo *ji)
 {
        if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->var_is_vt ||
                                                                                   mono_jit_info_get_generic_sharing_context (ji)->mvar_is_vt))
@@ -297,20 +280,21 @@ ji_is_gsharedvt (MonoJitInfo *ji)
 /*
  * mini_add_method_trampoline:
  *
- *   Add static rgctx/gsharedvt_in trampoline to M/COMPILED_METHOD if needed. Return the trampoline address, or
+ *   Add static rgctx/gsharedvt_in/unbox trampolines to M/COMPILED_METHOD if needed. Return the trampoline address, or
  * COMPILED_METHOD if no trampoline is needed.
  * ORIG_METHOD is the method the caller originally called i.e. an iface method, or NULL.
  */
 gpointer
-mini_add_method_trampoline (MonoMethod *orig_method, MonoMethod *m, gpointer compiled_method, gboolean add_static_rgctx_tramp)
+mini_add_method_trampoline (MonoMethod *orig_method, MonoMethod *m, gpointer compiled_method, gboolean add_static_rgctx_tramp, gboolean add_unbox_tramp)
 {
        gpointer addr = compiled_method;
        gboolean callee_gsharedvt, callee_array_helper;
+       MonoMethod *jmethod = NULL;
        MonoJitInfo *ji = 
                mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (compiled_method), NULL);
 
        // FIXME: This loads information from AOT
-       callee_gsharedvt = ji_is_gsharedvt (ji);
+       callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
 
        callee_array_helper = FALSE;
        if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_MANAGED) {
@@ -341,7 +325,22 @@ mini_add_method_trampoline (MonoMethod *orig_method, MonoMethod *m, gpointer com
 
        addr = compiled_method;
 
-       if (callee_gsharedvt && mini_is_gsharedvt_variable_signature (mono_method_signature (ji->method))) {
+       if (add_unbox_tramp) {
+               /* 
+                * The unbox trampolines call the method directly, so need to add
+                * an rgctx tramp before them.
+                */
+               if (mono_aot_only) {
+                       addr = mono_aot_get_unbox_trampoline (m);
+               } else {
+                       unbox_trampolines ++;
+                       addr = mono_arch_get_unbox_trampoline (m, addr);
+               }
+       }
+
+       if (ji)
+               jmethod = jinfo_get_method (ji);
+       if (callee_gsharedvt && mini_is_gsharedvt_variable_signature (mono_method_signature (jmethod))) {
                MonoGenericSharingContext *gsctx;
                MonoMethodSignature *sig, *gsig;
 
@@ -351,9 +350,9 @@ mini_add_method_trampoline (MonoMethod *orig_method, MonoMethod *m, gpointer com
                gsctx = mono_jit_info_get_generic_sharing_context (ji);
 
                sig = mono_method_signature (m);
-               gsig = mono_method_signature (ji->method); 
+               gsig = mono_method_signature (jmethod);
 
-               addr = mini_get_gsharedvt_wrapper (TRUE, compiled_method, sig, gsig, gsctx, -1, FALSE);
+               addr = mini_get_gsharedvt_wrapper (TRUE, addr, sig, gsig, gsctx, -1, FALSE);
 
                //printf ("IN: %s\n", mono_method_full_name (m, TRUE));
        }
@@ -375,6 +374,7 @@ common_call_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, guint8* tram
 {
        gpointer addr, compiled_method;
        gboolean generic_shared = FALSE;
+       gboolean need_unbox_tramp = FALSE;
        MonoMethod *declaring = NULL;
        MonoMethod *generic_virtual = NULL, *variant_iface = NULL, *orig_method = NULL;
        int context_used;
@@ -409,14 +409,8 @@ common_call_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, guint8* tram
                    m = mono_object_get_virtual_method (this_arg, m);
                        vtable_slot_to_patch = NULL;
                } else {
-                       addr = NULL;
-                       vtable_slot = mono_convert_imt_slot_to_vtable_slot (vtable_slot, regs, code, m, &impl_method, &need_rgctx_tramp, &variance_used, &addr);
-                       /* This is the vcall slot which gets called through the IMT thunk */
-                       vtable_slot_to_patch = vtable_slot;
-                       /* mono_convert_imt_slot_to_vtable_slot () also gives us the method that is supposed
-                        * to be called, so we compile it and go ahead as usual.
-                        */
-                       /*g_print ("imt found method %p (%s) at %p\n", impl_method, impl_method->name, code);*/
+                       gboolean lookup_aot;
+
                        if (m->is_inflated && ((MonoMethodInflated*)m)->context.method_inst) {
                                /* Generic virtual method */
                                generic_virtual = m;
@@ -425,7 +419,18 @@ common_call_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, guint8* tram
                                variant_iface = m;
                        }
 
-                       if (addr && !generic_virtual && !variant_iface) {
+                       addr = NULL;
+                       /* We can only use the AOT compiled code if we don't require further processing */
+                       lookup_aot = !generic_virtual & !variant_iface;
+                       vtable_slot = mono_convert_imt_slot_to_vtable_slot (vtable_slot, regs, code, m, lookup_aot, &impl_method, &need_rgctx_tramp, &variance_used, &addr);
+                       /* This is the vcall slot which gets called through the IMT thunk */
+                       vtable_slot_to_patch = vtable_slot;
+                       /* mono_convert_imt_slot_to_vtable_slot () also gives us the method that is supposed
+                        * to be called, so we compile it and go ahead as usual.
+                        */
+                       /*g_print ("imt found method %p (%s) at %p\n", impl_method, impl_method->name, code);*/
+
+                       if (addr) {
                                /*
                                 * We found AOT compiled code for the method, skip the rest.
                                 */
@@ -528,7 +533,7 @@ common_call_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, guint8* tram
                        actual_method = vt->klass->vtable [displacement];
                }
 
-               if (method_inst) {
+               if (method_inst || m->wrapper_type) {
                        MonoGenericContext context = { NULL, NULL };
 
                        if (m->is_inflated)
@@ -571,9 +576,15 @@ common_call_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, guint8* tram
        addr = compiled_method = mono_compile_method (m);
        g_assert (addr);
 
-       mono_debugger_trampoline_compiled (code, m, addr);
+       if (generic_virtual || variant_iface) {
+               if (vt->klass->valuetype) /*FIXME is this required variant iface?*/
+                       need_unbox_tramp = TRUE;
+       } else if (orig_vtable_slot) {
+               if (m->klass->valuetype)
+                       need_unbox_tramp = TRUE;
+       }
 
-       addr = mini_add_method_trampoline (orig_method, m, compiled_method, need_rgctx_tramp);
+       addr = mini_add_method_trampoline (orig_method, m, compiled_method, need_rgctx_tramp, need_unbox_tramp);
 
        if (generic_virtual || variant_iface) {
                MonoMethod *target = generic_virtual ? generic_virtual : variant_iface;
@@ -581,9 +592,6 @@ common_call_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, guint8* tram
                vtable_slot = orig_vtable_slot;
                g_assert (vtable_slot);
 
-               if (vt->klass->valuetype) /*FIXME is this required variant iface?*/
-                       addr = get_unbox_trampoline (m, addr, need_rgctx_tramp);
-
                mono_method_add_generic_virtual_invocation (mono_domain_get (), 
                                                                                                        vt, vtable_slot,
                                                                                                        target, addr);
@@ -622,9 +630,6 @@ common_call_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, guint8* tram
        vtable_slot = orig_vtable_slot;
 
        if (vtable_slot) {
-               if (m->klass->valuetype)
-                       addr = get_unbox_trampoline (m, addr, need_rgctx_tramp);
-
                if (vtable_slot_to_patch && (mono_aot_is_got_entry (code, (guint8*)vtable_slot_to_patch) || mono_domain_owns_vtable_slot (mono_domain_get (), vtable_slot_to_patch))) {
                        g_assert (*vtable_slot_to_patch);
                        *vtable_slot_to_patch = mono_get_addr_from_ftnptr (addr);
@@ -652,7 +657,7 @@ common_call_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, guint8* tram
                        if (generic_shared) {
                                if (m->wrapper_type != MONO_WRAPPER_NONE)
                                        m = mono_marshal_method_from_wrapper (m);
-                               //g_assert (mono_method_is_generic_sharable_impl (m, FALSE));
+                               //g_assert (mono_method_is_generic_sharable (m, FALSE));
                        }
 
                        /* Patch calling code */
@@ -801,8 +806,6 @@ mono_generic_virtual_remoting_trampoline (mgreg_t *regs, guint8 *code, MonoMetho
        addr = mono_compile_method (m);
        g_assert (addr);
 
-       mono_debugger_trampoline_compiled (NULL, m, addr);
-
        return addr;
 }
 #endif
@@ -999,7 +1002,7 @@ mono_delegate_trampoline (mgreg_t *regs, guint8 *code, gpointer *tramp_data, gui
 #ifndef DISABLE_REMOTING
                if (delegate->target && delegate->target->vtable->klass == mono_defaults.transparent_proxy_class) {
 #ifndef DISABLE_COM
-                       if (((MonoTransparentProxy *)delegate->target)->remote_class->proxy_class != mono_defaults.com_object_class && 
+                       if (((MonoTransparentProxy *)delegate->target)->remote_class->proxy_class != mono_class_get_com_object_class () &&
                           !mono_class_is_com_object (((MonoTransparentProxy *)delegate->target)->remote_class->proxy_class))
 #endif
                                method = mono_marshal_get_remoting_invoke (method);
@@ -1021,7 +1024,7 @@ mono_delegate_trampoline (mgreg_t *regs, guint8 *code, gpointer *tramp_data, gui
        } else {
                ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (delegate->method_ptr));
                if (ji)
-                       method = ji->method;
+                       method = jinfo_get_method (ji);
        }
 
        if (method) {
@@ -1056,15 +1059,10 @@ mono_delegate_trampoline (mgreg_t *regs, guint8 *code, gpointer *tramp_data, gui
                        delegate->method_ptr = *delegate->method_code;
                } else {
                        compiled_method = addr = mono_compile_method (method);
-                       if (need_unbox_tramp)
-                               // FIXME: GSHAREDVT
-                               addr = get_unbox_trampoline (method, addr, need_rgctx_tramp);
-                       else
-                               addr = mini_add_method_trampoline (NULL, method, compiled_method, need_rgctx_tramp);
+                       addr = mini_add_method_trampoline (NULL, method, compiled_method, need_rgctx_tramp, need_unbox_tramp);
                        delegate->method_ptr = addr;
                        if (enable_caching && delegate->method_code)
                                *delegate->method_code = delegate->method_ptr;
-                       mono_debugger_trampoline_compiled (NULL, method, delegate->method_ptr);
                }
        } else {
                if (need_rgctx_tramp)
@@ -1088,9 +1086,8 @@ mono_delegate_trampoline (mgreg_t *regs, guint8 *code, gpointer *tramp_data, gui
        /* The general, unoptimized case */
        m = mono_marshal_get_delegate_invoke (invoke, delegate);
        code = mono_compile_method (m);
-       code = mini_add_method_trampoline (NULL, m, code, mono_method_needs_static_rgctx_invoke (m, FALSE));
+       code = mini_add_method_trampoline (NULL, m, code, mono_method_needs_static_rgctx_invoke (m, FALSE), FALSE);
        delegate->invoke_impl = mono_get_addr_from_ftnptr (code);
-       mono_debugger_trampoline_compiled (NULL, m, delegate->invoke_impl);
 
        return code;
 }
@@ -1134,6 +1131,11 @@ gpointer
 mono_create_handler_block_trampoline (void)
 {
        static gpointer code;
+       if (code) {
+               mono_memory_barrier ();
+               return code;
+       }
+
 
        if (mono_aot_only) {
                g_assert (0);
@@ -1142,9 +1144,11 @@ mono_create_handler_block_trampoline (void)
 
        mono_trampolines_lock ();
 
-       if (!code)
-               code = mono_arch_create_handler_block_trampoline ();
-
+       if (!code) {
+               gpointer tmp = mono_arch_create_handler_block_trampoline ();
+               mono_memory_barrier ();
+               code = tmp;
+       }
        mono_trampolines_unlock ();
 
        return code;
@@ -1209,12 +1213,7 @@ create_trampoline_code (MonoTrampolineType tramp_type)
        guchar *code;
 
        code = mono_arch_create_generic_trampoline (tramp_type, &info, FALSE);
-       if (info) {
-               mono_save_trampoline_xdebug_info (info);
-               if (mono_jit_map_is_enabled ())
-                       mono_emit_jit_tramp (info->code, info->code_size, info->name);
-               mono_tramp_info_free (info);
-       }
+       mono_tramp_info_register (info);
 
        return code;
 }
@@ -1338,13 +1337,7 @@ mono_create_generic_class_init_trampoline (void)
                        code = mono_get_addr_from_ftnptr (mono_aot_get_trampoline ("generic_class_init_trampoline"));
                else {
                        code = mono_arch_create_generic_class_init_trampoline (&info, FALSE);
-
-                       if (info) {
-                               mono_save_trampoline_xdebug_info (info);
-                               if (mono_jit_map_is_enabled ())
-                                       mono_emit_jit_tramp (info->code, info->code_size, info->name);
-                               mono_tramp_info_free (info);
-                       }
+                       mono_tramp_info_register (info);
                }
        }
 
@@ -1385,7 +1378,7 @@ mono_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean ad
        ji = mono_domain_alloc0 (domain, MONO_SIZEOF_JIT_INFO);
        ji->code_start = code;
        ji->code_size = code_size;
-       ji->method = method;
+       ji->d.method = method;
 
        /*
         * mono_delegate_ctor needs to find the method metadata from the 
@@ -1506,9 +1499,6 @@ mono_create_rgctx_lazy_fetch_trampoline (guint32 offset)
 
        gpointer tramp, ptr;
 
-       if (mono_aot_only)
-               return mono_aot_get_lazy_fetch_trampoline (offset);
-
        mono_trampolines_lock ();
        if (rgctx_lazy_fetch_trampoline_hash)
                tramp = g_hash_table_lookup (rgctx_lazy_fetch_trampoline_hash, GUINT_TO_POINTER (offset));
@@ -1518,14 +1508,13 @@ mono_create_rgctx_lazy_fetch_trampoline (guint32 offset)
        if (tramp)
                return tramp;
 
-       tramp = mono_arch_create_rgctx_lazy_fetch_trampoline (offset, &info, FALSE);
-       if (info) {
-               mono_save_trampoline_xdebug_info (info);
-               if (mono_jit_map_is_enabled ())
-                       mono_emit_jit_tramp (info->code, info->code_size, info->name);
-               mono_tramp_info_free (info);
+       if (mono_aot_only) {
+               ptr = mono_aot_get_lazy_fetch_trampoline (offset);
+       } else {
+               tramp = mono_arch_create_rgctx_lazy_fetch_trampoline (offset, &info, FALSE);
+               mono_tramp_info_register (info);
+               ptr = mono_create_ftnptr (mono_get_root_domain (), tramp);
        }
-       ptr = mono_create_ftnptr (mono_get_root_domain (), tramp);
 
        mono_trampolines_lock ();
        if (!rgctx_lazy_fetch_trampoline_hash) {
@@ -1565,12 +1554,7 @@ mono_create_monitor_enter_trampoline (void)
                MonoTrampInfo *info;
 
                code = mono_arch_create_monitor_enter_trampoline (&info, FALSE);
-               if (info) {
-                       mono_save_trampoline_xdebug_info (info);
-                       if (mono_jit_map_is_enabled ())
-                               mono_emit_jit_tramp (info->code, info->code_size, info->name);
-                       mono_tramp_info_free (info);
-               }
+               mono_tramp_info_register (info);
        }
 
        mono_trampolines_unlock ();
@@ -1600,12 +1584,7 @@ mono_create_monitor_exit_trampoline (void)
                MonoTrampInfo *info;
 
                code = mono_arch_create_monitor_exit_trampoline (&info, FALSE);
-               if (info) {
-                       mono_save_trampoline_xdebug_info (info);
-                       if (mono_jit_map_is_enabled ())
-                               mono_emit_jit_tramp (info->code, info->code_size, info->name);
-                       mono_tramp_info_free (info);
-               }
+               mono_tramp_info_register (info);
        }
 
        mono_trampolines_unlock ();
@@ -1680,15 +1659,11 @@ static const char*tramp_names [MONO_TRAMPOLINE_NUM] = {
        "aot_plt",
        "delegate",
        "restore_stack_prot",
-#ifndef DISABLE_REMOTING
        "generic_virtual_remoting",
-#endif
        "monitor_enter",
        "monitor_exit",
        "vcall",
-#ifdef MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD
        "handler_block_guard"
-#endif
 };
 
 /*
@@ -1719,3 +1694,24 @@ mono_get_rgctx_fetch_trampoline_name (int slot)
        return g_strdup_printf ("rgctx_fetch_trampoline_%s_%d", mrgctx ? "mrgctx" : "rgctx", index);
 }
 
+gpointer
+mini_get_nullified_class_init_trampoline (void)
+{
+       static gpointer nullified_class_init_trampoline;
+
+       if (!nullified_class_init_trampoline) {
+               gpointer tramp;
+               MonoTrampInfo *info;
+
+               if (mono_aot_only) {
+                       tramp = mono_aot_get_trampoline ("nullified_class_init_trampoline");
+               } else {
+                       tramp = mono_arch_get_nullified_class_init_trampoline (&info);
+                       mono_tramp_info_register (info);
+               }
+               mono_memory_barrier ();
+               nullified_class_init_trampoline = tramp;
+       }
+
+       return nullified_class_init_trampoline;
+}