Merge pull request #505 from roji/shutdown_flow
authorRodrigo Kumpera <kumpera@gmail.com>
Tue, 12 Mar 2013 21:25:47 +0000 (14:25 -0700)
committerRodrigo Kumpera <kumpera@gmail.com>
Tue, 12 Mar 2013 21:25:47 +0000 (14:25 -0700)
Fixed threadpool+ProcessExit problem in shutdown flow

1  2 
mono/metadata/icall.c
mono/metadata/threads.c
mono/mini/mini.c
mono/tests/Makefile.am

diff --combined mono/metadata/icall.c
index 1be47527f85a564707224dea6249fee79cf892c6,73823823c0ef2d8ac26d00fcc8ed758881d3de8c..ed34f324fc96e03b17aa06a093c71102e58b846a
@@@ -73,6 -73,7 +73,7 @@@
  #include <mono/metadata/mono-debug.h>
  #include <mono/metadata/mono-ptr-array.h>
  #include <mono/metadata/verify-internals.h>
+ #include <mono/metadata/runtime.h>
  #include <mono/io-layer/io-layer.h>
  #include <mono/utils/strtod.h>
  #include <mono/utils/monobitset.h>
@@@ -82,7 -83,6 +83,7 @@@
  #include <mono/utils/mono-error-internals.h>
  #include <mono/utils/mono-mmap.h>
  #include <mono/utils/mono-io-portability.h>
 +#include <mono/utils/mono-digest.h>
  
  #if defined (HOST_WIN32)
  #include <windows.h>
@@@ -1169,12 -1169,10 +1170,12 @@@ ves_icall_System_Object_GetType (MonoOb
  {
        MONO_ARCH_SAVE_REGS;
  
 -      if (obj->vtable->klass != mono_defaults.transparent_proxy_class)
 -              return mono_type_get_object (mono_object_domain (obj), &obj->vtable->klass->byval_arg);
 -      else
 +#ifndef DISABLE_REMOTING
 +      if (obj->vtable->klass == mono_defaults.transparent_proxy_class)
                return mono_type_get_object (mono_object_domain (obj), &((MonoTransparentProxy*)obj)->remote_class->proxy_class->byval_arg);
 +      else
 +#endif
 +              return mono_type_get_object (mono_object_domain (obj), &obj->vtable->klass->byval_arg);
  }
  
  ICALL_EXPORT void
@@@ -1644,8 -1642,8 +1645,8 @@@ ves_icall_get_attributes (MonoReflectio
        return klass->flags;
  }
  
 -ICALL_EXPORT MonoReflectionMarshal*
 -ves_icall_System_Reflection_FieldInfo_GetUnmanagedMarshal (MonoReflectionField *field)
 +ICALL_EXPORT MonoReflectionMarshalAsAttribute*
 +ves_icall_System_Reflection_FieldInfo_get_marshal_info (MonoReflectionField *field)
  {
        MonoClass *klass = field->field->parent;
        MonoMarshalType *info;
                        if (!info->fields [i].mspec)
                                return NULL;
                        else
 -                              return mono_reflection_marshal_from_marshal_spec (field->object.vtable->domain, klass, info->fields [i].mspec);
 +                              return mono_reflection_marshal_as_attribute_from_marshal_spec (field->object.vtable->domain, klass, info->fields [i].mspec);
                }
        }
  
@@@ -1752,11 -1750,11 +1753,11 @@@ ves_icall_get_parameter_info (MonoMetho
        return mono_param_get_objects_internal (domain, method, member->reftype ? mono_class_from_mono_type (member->reftype->type) : NULL);
  }
  
 -ICALL_EXPORT MonoReflectionMarshal*
 +ICALL_EXPORT MonoReflectionMarshalAsAttribute*
  ves_icall_System_MonoMethodInfo_get_retval_marshal (MonoMethod *method)
  {
        MonoDomain *domain = mono_domain_get (); 
 -      MonoReflectionMarshal* res = NULL;
 +      MonoReflectionMarshalAsAttribute* res = NULL;
        MonoMarshalSpec **mspecs;
        int i;
  
        mono_method_get_marshal_info (method, mspecs);
  
        if (mspecs [0])
 -              res = mono_reflection_marshal_from_marshal_spec (domain, method->klass, mspecs [0]);
 +              res = mono_reflection_marshal_as_attribute_from_marshal_spec (domain, method->klass, mspecs [0]);
                
        for (i = mono_method_signature (method)->param_count; i >= 0; i--)
                if (mspecs [i])
@@@ -2878,7 -2876,6 +2879,7 @@@ ves_icall_InternalInvoke (MonoReflectio
        return mono_runtime_invoke_array (m, obj, params, NULL);
  }
  
 +#ifndef DISABLE_REMOTING
  ICALL_EXPORT MonoObject *
  ves_icall_InternalExecute (MonoReflectionMethod *method, MonoObject *this, MonoArray *params, MonoArray **outArgs) 
  {
  
        return result;
  }
 +#endif
  
  static guint64
  read_enum_value (char *mem, int type)
@@@ -4538,6 -4534,53 +4539,6 @@@ ves_icall_System_Reflection_Assembly_Ge
        return result;
  }
  
 -typedef struct {
 -      MonoArray *res;
 -      int idx;
 -} NameSpaceInfo;
 -
 -static void
 -foreach_namespace (const char* key, gconstpointer val, NameSpaceInfo *info)
 -{
 -      MonoString *name = mono_string_new (mono_object_domain (info->res), key);
 -
 -      mono_array_setref (info->res, info->idx, name);
 -      info->idx++;
 -}
 -
 -ICALL_EXPORT MonoArray*
 -ves_icall_System_Reflection_Assembly_GetNamespaces (MonoReflectionAssembly *assembly) 
 -{
 -      MonoImage *img = assembly->assembly->image;
 -      MonoArray *res;
 -      NameSpaceInfo info;
 -      int len;
 -
 -      MONO_ARCH_SAVE_REGS;
 -
 -      mono_image_lock (img);
 -      mono_image_init_name_cache (img);
 -
 -RETRY_LEN:
 -      len = g_hash_table_size (img->name_cache);
 -      mono_image_unlock (img);
 -
 -      /*we can't create objects holding the image lock */
 -      res = mono_array_new (mono_object_domain (assembly), mono_defaults.string_class, len);
 -
 -      mono_image_lock (img);
 -      /*len might have changed, create a new array*/
 -      if (len != g_hash_table_size (img->name_cache))
 -              goto RETRY_LEN;
 -
 -      info.res = res;
 -      info.idx = 0;
 -      g_hash_table_foreach (img->name_cache, (GHFunc)foreach_namespace, &info);
 -      mono_image_unlock (img);
 -
 -      return res;
 -}
 -
  /* move this in some file in mono/util/ */
  static char *
  g_concat_dir_and_file (const char *dir, const char *file)
@@@ -6212,10 -6255,6 +6213,10 @@@ ves_icall_System_Buffer_BlockCopyIntern
  
        MONO_ARCH_SAVE_REGS;
  
 +      /* This is called directly from the class libraries without going through the managed wrapper */
 +      MONO_CHECK_ARG_NULL (src);
 +      MONO_CHECK_ARG_NULL (dest);
 +
        /* watch out for integer overflow */
        if ((src_offset > mono_array_get_byte_length (src) - count) || (dest_offset > mono_array_get_byte_length (dest) - count))
                return FALSE;
        return TRUE;
  }
  
 +#ifndef DISABLE_REMOTING
  ICALL_EXPORT MonoObject *
  ves_icall_Remoting_RealProxy_GetTransparentProxy (MonoObject *this, MonoString *class_name)
  {
@@@ -6263,7 -6301,6 +6264,7 @@@ ves_icall_Remoting_RealProxy_InternalGe
  {
        return mono_type_get_object (mono_object_domain (tp), &tp->remote_class->proxy_class->byval_arg);
  }
 +#endif
  
  /* System.Environment */
  
@@@ -6529,6 -6566,10 +6530,10 @@@ ves_icall_System_Environment_Exit (int 
  {
        MONO_ARCH_SAVE_REGS;
  
+ #ifndef MONO_CROSS_COMPILE
+       mono_runtime_shutdown ();
+ #endif
        mono_threads_set_shutting_down ();
  
        mono_runtime_set_shutting_down ();
@@@ -6752,7 -6793,6 +6757,7 @@@ ves_icall_MonoMethodMessage_InitMessag
        mono_message_init (mono_object_domain (this), this, method, out_args);
  }
  
 +#ifndef DISABLE_REMOTING
  ICALL_EXPORT MonoBoolean
  ves_icall_IsTransparentProxy (MonoObject *proxy)
  {
@@@ -6833,7 -6873,6 +6838,7 @@@ ves_icall_System_Runtime_Activation_Act
        if (enable) vtable->remote = 1;
        else vtable->remote = 0;
  }
 +#endif
  
  ICALL_EXPORT MonoObject *
  ves_icall_System_Runtime_Activation_ActivationServices_AllocateUninitializedClassInstance (MonoReflectionType *type)
@@@ -8348,25 -8387,6 +8353,25 @@@ mono_get_jit_icall_info (void
        return jit_icall_hash_name;
  }
  
 +/*
 + * mono_lookup_jit_icall_symbol:
 + *
 + *   Given the jit icall NAME, returns its C symbol if possible, or NULL.
 + */
 +const char*
 +mono_lookup_jit_icall_symbol (const char *name)
 +{
 +      MonoJitICallInfo *info;
 +      const char *res = NULL;
 +
 +      mono_loader_lock ();
 +      info = g_hash_table_lookup (jit_icall_hash_name, name);
 +      if (info)
 +              res = info->c_symbol;
 +      mono_loader_unlock ();
 +      return res;
 +}
 +
  void
  mono_register_jit_icall_wrapper (MonoJitICallInfo *info, gconstpointer wrapper)
  {
  }
  
  MonoJitICallInfo *
 -mono_register_jit_icall (gconstpointer func, const char *name, MonoMethodSignature *sig, gboolean is_save)
 +mono_register_jit_icall_full (gconstpointer func, const char *name, MonoMethodSignature *sig, gboolean is_save, const char *c_symbol)
  {
        MonoJitICallInfo *info;
        
        info->name = name;
        info->func = func;
        info->sig = sig;
 +      info->c_symbol = c_symbol;
  
        if (is_save) {
                info->wrapper = func;
        mono_loader_unlock ();
        return info;
  }
 +
 +MonoJitICallInfo *
 +mono_register_jit_icall (gconstpointer func, const char *name, MonoMethodSignature *sig, gboolean is_save)
 +{
 +      return mono_register_jit_icall_full (func, name, sig, is_save, NULL);
 +}
 +
diff --combined mono/metadata/threads.c
index 0809e076bd87d6e3c1ec10f2b082d9146e6d989a,b1376cd2de9493482688980d39de3f7dca1d4590..56a1ea2646be71194ebe78c192d034ce8c60dd2f
@@@ -33,6 -33,7 +33,7 @@@
  #include <mono/metadata/monitor.h>
  #include <mono/metadata/gc-internal.h>
  #include <mono/metadata/marshal.h>
+ #include <mono/metadata/runtime.h>
  #include <mono/io-layer/io-layer.h>
  #ifndef HOST_WIN32
  #include <mono/io-layer/threads.h>
@@@ -410,11 -411,7 +411,11 @@@ static void thread_cleanup (MonoInterna
        if (mono_thread_cleanup_fn)
                mono_thread_cleanup_fn (thread);
  
 -      MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
 +      if (mono_gc_is_moving ()) {
 +              MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
 +              thread->thread_pinning_ref = NULL;
 +      }
 +              
  }
  
  static gpointer
@@@ -699,22 -696,13 +700,22 @@@ register_thread_start_argument (MonoThr
        mono_g_hash_table_insert (thread_start_args, thread, start_info->start_arg);
  }
  
 -MonoInternalThread* mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size)
 +/*
 + * mono_thread_create_internal:
 + * 
 + * If NO_DETACH is TRUE, then the thread is not detached using pthread_detach (). This is needed to fix the race condition where waiting for a thred to exit only waits for its exit event to be
 + * signalled, which can cause shutdown crashes if the thread shutdown code accesses data already freed by the runtime shutdown.
 + * Currently, this is only used for the finalizer thread.
 + */
 +MonoInternalThread*
 +mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, gboolean no_detach, guint32 stack_size)
  {
        MonoThread *thread;
        MonoInternalThread *internal;
        HANDLE thread_handle;
        struct StartInfo *start_info;
        gsize tid;
 +      guint32 create_flags;
  
        thread = create_thread_object (domain);
        internal = create_internal_thread_object ();
        /* Create suspended, so we can do some housekeeping before the thread
         * starts
         */
 +      create_flags = CREATE_SUSPENDED;
 +#ifndef HOST_WIN32
 +      if (no_detach)
 +              create_flags |= CREATE_NO_DETACH;
 +#endif
        thread_handle = mono_create_thread (NULL, stack_size, (LPTHREAD_START_ROUTINE)start_wrapper, start_info,
 -                                   CREATE_SUSPENDED, &tid);
 +                                   create_flags, &tid);
        THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
        if (thread_handle == NULL) {
                /* The thread couldn't be created, so throw an exception */
        internal->handle=thread_handle;
        internal->tid=tid;
        internal->apartment_state=ThreadApartmentState_Unknown;
 -      internal->thread_pinning_ref = internal;
        internal->managed_id = get_next_managed_thread_id ();
 -      MONO_GC_REGISTER_ROOT_PINNING (internal->thread_pinning_ref);
 +      if (mono_gc_is_moving ()) {
 +              internal->thread_pinning_ref = internal;
 +              MONO_GC_REGISTER_ROOT_PINNING (internal->thread_pinning_ref);
 +      }
  
        internal->synch_cs = g_new0 (CRITICAL_SECTION, 1);
        InitializeCriticalSection (internal->synch_cs);
                ResumeThread (thread_handle);
  
        /* Check that the managed and unmanaged layout of MonoInternalThread matches */
 -      g_assert (((char*)&internal->unused2 - (char*)internal) == mono_defaults.internal_thread_class->fields [mono_defaults.internal_thread_class->field.count - 1].offset);
 +      if (mono_check_corlib_version () == NULL)
 +              g_assert (((char*)&internal->unused2 - (char*)internal) == mono_defaults.internal_thread_class->fields [mono_defaults.internal_thread_class->field.count - 1].offset);
  
        return internal;
  }
  void
  mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
  {
 -      mono_thread_create_internal (domain, func, arg, FALSE, 0);
 +      mono_thread_create_internal (domain, func, arg, FALSE, FALSE, 0);
  }
  
  /*
@@@ -900,11 -880,9 +901,11 @@@ mono_thread_attach (MonoDomain *domain
        thread->android_tid = (gpointer) gettid ();
  #endif
        thread->apartment_state=ThreadApartmentState_Unknown;
 -      thread->thread_pinning_ref = thread;
        thread->managed_id = get_next_managed_thread_id ();
 -      MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref);
 +      if (mono_gc_is_moving ()) {
 +              thread->thread_pinning_ref = thread;
 +              MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref);
 +      }
  
        thread->stack_ptr = &tid;
  
@@@ -1071,10 -1049,8 +1072,10 @@@ HANDLE ves_icall_System_Threading_Threa
                
                internal->handle=thread;
                internal->tid=tid;
 -              internal->thread_pinning_ref = internal;
 -              MONO_GC_REGISTER_ROOT_PINNING (internal->thread_pinning_ref);
 +              if (mono_gc_is_moving ()) {
 +                      internal->thread_pinning_ref = internal;
 +                      MONO_GC_REGISTER_ROOT_PINNING (internal->thread_pinning_ref);
 +              }
                
  
                /* Don't call handle_store() here, delay it to Start.
@@@ -1387,44 -1363,6 +1388,44 @@@ gboolean ves_icall_System_Threading_Thr
        return(FALSE);
  }
  
 +static gint32
 +mono_wait_uninterrupted (MonoInternalThread *thread, gboolean multiple, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, gboolean alertable)
 +{
 +      MonoException *exc;
 +      guint32 ret;
 +      gint64 start;
 +      gint32 diff_ms;
 +      gint32 wait = ms;
 +
 +      start = (ms == -1) ? 0 : mono_100ns_ticks ();
 +      do {
 +              if (multiple)
 +                      ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, alertable);
 +              else
 +                      ret = WaitForSingleObjectEx (handles [0], ms, alertable);
 +
 +              if (ret != WAIT_IO_COMPLETION)
 +                      break;
 +
 +              exc = mono_thread_execute_interruption (thread);
 +              if (exc)
 +                      mono_raise_exception (exc);
 +
 +              if (ms == -1)
 +                      continue;
 +
 +              /* Re-calculate ms according to the time passed */
 +              diff_ms = (mono_100ns_ticks () - start) / 10000;
 +              if (diff_ms >= ms) {
 +                      ret = WAIT_TIMEOUT;
 +                      break;
 +              }
 +              wait = ms - diff_ms;
 +      } while (TRUE);
 +      
 +      return ret;
 +}
 +
  /* FIXME: exitContext isnt documented */
  gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
  {
  
        mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
        
 -      ret=WaitForMultipleObjectsEx(numhandles, handles, TRUE, ms, TRUE);
 +      ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, TRUE, ms, TRUE);
  
        mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
  
        if(ret==WAIT_FAILED) {
                THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
                return(FALSE);
 -      } else if(ret==WAIT_TIMEOUT || ret == WAIT_IO_COMPLETION) {
 -              /* Do we want to try again if we get
 -               * WAIT_IO_COMPLETION? The documentation for
 -               * WaitHandle doesn't give any clues.  (We'd have to
 -               * fiddle with the timeout if we retry.)
 -               */
 +      } else if(ret==WAIT_TIMEOUT) {
                THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
                return(FALSE);
        }
@@@ -1478,6 -1421,7 +1479,6 @@@ gint32 ves_icall_System_Threading_WaitH
        guint32 i;
        MonoObject *waitHandle;
        MonoInternalThread *thread = mono_thread_internal_current ();
 -      guint32 start;
  
        /* Do this WaitSleepJoin check before creating objects */
        mono_thread_current_check_pending_interrupt ();
  
        mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
  
 -      start = (ms == -1) ? 0 : mono_msec_ticks ();
 -      do {
 -              ret = WaitForMultipleObjectsEx (numhandles, handles, FALSE, ms, TRUE);
 -              if (ret != WAIT_IO_COMPLETION)
 -                      break;
 -              if (ms != -1) {
 -                      guint32 diff;
 -
 -                      diff = mono_msec_ticks () - start;
 -                      ms -= diff;
 -                      if (ms <= 0)
 -                              break;
 -              }
 -      } while (ms == -1 || ms > 0);
 +      ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, FALSE, ms, TRUE);
  
        mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
  
@@@ -1533,14 -1490,19 +1534,14 @@@ gboolean ves_icall_System_Threading_Wai
  
        mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
        
 -      ret=WaitForSingleObjectEx (handle, ms, TRUE);
 +      ret = mono_wait_uninterrupted (thread, FALSE, 1, &handle, FALSE, ms, TRUE);
        
        mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
        
        if(ret==WAIT_FAILED) {
                THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
                return(FALSE);
 -      } else if(ret==WAIT_TIMEOUT || ret == WAIT_IO_COMPLETION) {
 -              /* Do we want to try again if we get
 -               * WAIT_IO_COMPLETION? The documentation for
 -               * WaitHandle doesn't give any clues.  (We'd have to
 -               * fiddle with the timeout if we retry.)
 -               */
 +      } else if(ret==WAIT_TIMEOUT) {
                THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
                return(FALSE);
        }
@@@ -2096,14 -2058,13 +2097,14 @@@ mono_thread_get_abort_signal (void
  {
  #ifdef HOST_WIN32
        return -1;
 -#else
 -#ifndef       SIGRTMIN
 +#elif defined(PLATFORM_ANDROID)
 +      return SIGUNUSED;
 +#elif !defined (SIGRTMIN)
  #ifdef SIGUSR1
        return SIGUSR1;
  #else
        return -1;
 -#endif
 +#endif /* SIGUSR1 */
  #else
        static int abort_signum = -1;
        int i;
        }
        /* fallback to the old way */
        return SIGRTMIN;
 -#endif
  #endif /* HOST_WIN32 */
  }
  
@@@ -2466,12 -2428,6 +2467,12 @@@ ves_icall_System_Threading_Thread_Volat
        return *((volatile float *) (ptr));
  }
  
 +MonoObject*
 +ves_icall_System_Threading_Volatile_Read_T (void *ptr)
 +{
 +      return (MonoObject*)*((volatile MonoObject**)ptr);
 +}
 +
  void
  ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
  {
@@@ -2520,13 -2476,6 +2521,13 @@@ ves_icall_System_Threading_Thread_Volat
        *((volatile float *) ptr) = value;
  }
  
 +void
 +ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
 +{
 +      *((volatile MonoObject **) ptr) = value;
 +      mono_gc_wbarrier_generic_nostore (ptr);
 +}
 +
  void mono_thread_init (MonoThreadStartCB start_cb,
                       MonoThreadAttachCB attach_cb)
  {
@@@ -2906,6 -2855,10 +2907,10 @@@ void mono_thread_manage (void
                THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
        } while(wait->num>0);
  
+ #ifndef MONO_CROSS_COMPILE
+       mono_runtime_shutdown ();
+ #endif
        mono_threads_set_shutting_down ();
  
        /* No new threads will be created after this point */
@@@ -4502,8 -4455,6 +4507,8 @@@ static MonoJitInfo
  mono_thread_info_get_last_managed (MonoThreadInfo *info)
  {
        MonoJitInfo *ji = NULL;
 +      if (!info)
 +              return NULL;
        mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, &info->suspend_state, MONO_UNWIND_SIGNAL_SAFE, &ji);
        return ji;
  }
@@@ -4610,20 -4561,10 +4615,20 @@@ suspend_thread_internal (MonoInternalTh
                transition_to_suspended (thread);
                mono_thread_info_self_suspend ();
        } else {
 -              MonoThreadInfo *info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gsize)thread->tid, interrupt);
 -              MonoJitInfo *ji = mono_thread_info_get_last_managed (info);
 -              gboolean protected_wrapper = ji && mono_threads_is_critical_method (ji->method);
 -              gboolean running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&info->suspend_state.ctx));
 +              MonoThreadInfo *info;
 +              MonoJitInfo *ji;
 +              gboolean protected_wrapper;
 +              gboolean running_managed;
 +
 +              /*A null info usually means the thread is already dead. */
 +              if (!(info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gsize)thread->tid, interrupt))) {
 +                      LeaveCriticalSection (thread->synch_cs);
 +                      return;
 +              }
 +
 +              ji = mono_thread_info_get_last_managed (info);
 +              protected_wrapper = ji && mono_threads_is_critical_method (ji->method);
 +              running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&info->suspend_state.ctx));
  
                if (running_managed && !protected_wrapper) {
                        transition_to_suspended (thread);
diff --combined mono/mini/mini.c
index 6c9d1c0a3789934627cd009a90b2b84d27e373c2,5f035d7e4ef6b39d36069617e995d97219ad9a62..28b66be959ff9fe33df01979916b3dd65ec2cc44
@@@ -367,8 -367,6 +367,8 @@@ mono_print_method_from_ip (void *ip
        MonoDomain *domain = mono_domain_get ();
        MonoDomain *target_domain = mono_domain_get ();
        FindTrampUserData user_data;
 +      MonoGenericSharingContext*gsctx;
 +      const char *shared_type;
        
        ji = mini_jit_info_table_find (domain, ip, &target_domain);
        if (!ji) {
        method = mono_method_full_name (ji->method, TRUE);
        source = mono_debug_lookup_source_location (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), target_domain);
  
 -      g_print ("IP %p at offset 0x%x of method %s (%p %p)[domain %p - %s]\n", ip, (int)((char*)ip - (char*)ji->code_start), method, ji->code_start, (char*)ji->code_start + ji->code_size, target_domain, target_domain->friendly_name);
 +      gsctx = mono_jit_info_get_generic_sharing_context (ji);
 +      shared_type = "";
 +      if (gsctx) {
 +              if (gsctx->var_is_vt || gsctx->mvar_is_vt)
 +                      shared_type = "gsharedvt ";
 +              else
 +                      shared_type = "gshared ";
 +      }
 +
 +      g_print ("IP %p at offset 0x%x of %smethod %s (%p %p)[domain %p - %s]\n", ip, (int)((char*)ip - (char*)ji->code_start), shared_type, method, ji->code_start, (char*)ji->code_start + ji->code_size, target_domain, target_domain->friendly_name);
  
        if (source)
                g_print ("%s:%d\n", source->source_file, source->row);
@@@ -873,10 -862,12 +873,10 @@@ handle_enum
                goto handle_enum;
        case MONO_TYPE_VAR:
        case MONO_TYPE_MVAR:
 -              /* FIXME: all the arguments must be references for now,
 -               * later look inside cfg and see if the arg num is
 -               * really a reference
 -               */
 -              g_assert (cfg->generic_sharing_context);
 -              return OP_STORE_MEMBASE_REG;
 +              if (mini_type_var_is_vt (cfg, type))
 +                      return OP_STOREV_MEMBASE;
 +              else
 +                      return OP_STORE_MEMBASE_REG;
        default:
                g_error ("unknown type 0x%02x in type_to_store_membase", type->type);
        }
@@@ -937,11 -928,12 +937,11 @@@ mono_type_to_load_membase (MonoCompile 
                break;
        case MONO_TYPE_VAR:
        case MONO_TYPE_MVAR:
 -              /* FIXME: all the arguments must be references for now,
 -               * later look inside cfg and see if the arg num is
 -               * really a reference
 -               */
                g_assert (cfg->generic_sharing_context);
 -              return OP_LOAD_MEMBASE;
 +              if (mini_type_var_is_vt (cfg, type))
 +                      return OP_LOADV_MEMBASE;
 +              else
 +                      return OP_LOAD_MEMBASE;
        default:
                g_error ("unknown type 0x%02x in type_to_load_membase", type->type);
        }
@@@ -952,28 -944,26 +952,28 @@@ static guin
  mini_type_to_ldind (MonoCompile* cfg, MonoType *type)
  {
        if (cfg->generic_sharing_context && !type->byref) {
 -              /* FIXME: all the arguments must be references for now,
 -               * later look inside cfg and see if the arg num is
 -               * really a reference
 -               */
 -              if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)
 -                      return CEE_LDIND_REF;
 +              if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
 +                      if (mini_type_var_is_vt (cfg, type))
 +                              return CEE_LDOBJ;
 +                      else
 +                              return CEE_LDIND_REF;
 +              }
        }
        return mono_type_to_ldind (type);
  }
  
 +#ifndef DISABLE_JIT
 +
  guint
  mini_type_to_stind (MonoCompile* cfg, MonoType *type)
  {
        if (cfg->generic_sharing_context && !type->byref) {
 -              /* FIXME: all the arguments must be references for now,
 -               * later look inside cfg and see if the arg num is
 -               * really a reference
 -               */
 -              if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)
 -                      return CEE_STIND_REF;
 +              if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
 +                      if (mini_type_var_is_vt (cfg, type))
 +                              return CEE_STOBJ;
 +                      else
 +                              return CEE_STIND_REF;
 +              }
        }
        return mono_type_to_stind (type);
  }
@@@ -1108,8 -1098,6 +1108,8 @@@ mono_decompose_op_imm (MonoCompile *cfg
        bb->max_vreg = MAX (bb->max_vreg, cfg->next_vreg);
  }
  
 +#endif
 +
  static void
  set_vreg_to_inst (MonoCompile *cfg, int vreg, MonoInst *inst)
  {
@@@ -1165,9 -1153,6 +1165,9 @@@ mono_compile_create_var_for_vreg (MonoC
        inst->backend.is_pinvoke = 0;
        inst->dreg = vreg;
  
 +      if (inst->klass->exception_type)
 +              mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
 +
        if (cfg->compute_gc_maps) {
                if (type->byref) {
                        mono_mark_vreg_as_mp (cfg, vreg);
@@@ -1761,22 -1746,18 +1761,22 @@@ mono_allocate_stack_slots2 (MonoCompil
                vmv = current;
                inst = cfg->varinfo [vmv->idx];
  
 +              t = mono_type_get_underlying_type (inst->inst_vtype);
 +              if (cfg->gsharedvt && mini_is_gsharedvt_variable_type (cfg, t))
 +                      t = mini_get_gsharedvt_alloc_type_for_type (cfg, t);
 +
                /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
                * pinvoke wrappers when they call functions returning structures */
 -              if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF) {
 -                      size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &align);
 +              if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (t) && t->type != MONO_TYPE_TYPEDBYREF) {
 +                      size = mono_class_native_size (mono_class_from_mono_type (t), &align);
                }
                else {
                        int ialign;
  
 -                      size = mono_type_size (inst->inst_vtype, &ialign);
 +                      size = mono_type_size (t, &ialign);
                        align = ialign;
  
 -                      if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (inst->inst_vtype)))
 +                      if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (t)))
                                align = 16;
                }
  
                if (cfg->disable_reuse_stack_slots)
                        reuse_slot = FALSE;
  
 -              t = mono_type_get_underlying_type (inst->inst_vtype);
                switch (t->type) {
                case MONO_TYPE_GENERICINST:
                        if (!mono_type_generic_inst_is_valuetype (t)) {
@@@ -2057,24 -2039,17 +2057,24 @@@ mono_allocate_stack_slots (MonoCompile 
                vmv = l->data;
                inst = cfg->varinfo [vmv->idx];
  
 +              t = mono_type_get_underlying_type (inst->inst_vtype);
 +              if (cfg->gsharedvt && mini_is_gsharedvt_variable_type (cfg, t))
 +                      t = mini_get_gsharedvt_alloc_type_for_type (cfg, t);
 +
                /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
                * pinvoke wrappers when they call functions returning structures */
 -              if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF) {
 -                      size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &align);
 +              if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (t) && t->type != MONO_TYPE_TYPEDBYREF) {
 +                      size = mono_class_native_size (mono_class_from_mono_type (t), &align);
                } else {
                        int ialign;
  
 -                      size = mono_type_size (inst->inst_vtype, &ialign);
 +                      size = mono_type_size (t, &ialign);
                        align = ialign;
  
 -                      if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (inst->inst_vtype)))
 +                      if (mono_class_from_mono_type (t)->exception_type)
 +                              mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
 +
 +                      if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (t)))
                                align = 16;
                }
  
                if (cfg->disable_reuse_stack_slots)
                        reuse_slot = FALSE;
  
 -              t = mono_type_get_underlying_type (inst->inst_vtype);
                if (t->byref) {
                        slot_info = &scalar_stack_slots [MONO_TYPE_I];
                } else {
                                if (cfg->disable_reuse_ref_stack_slots)
                                        reuse_slot = FALSE;
                                break;
 -
 +                      case MONO_TYPE_VAR:
 +                      case MONO_TYPE_MVAR:
 +                              slot_info = &scalar_stack_slots [t->type];
 +                              break;
                        default:
                                slot_info = &scalar_stack_slots [t->type];
 +                              break;
                        }
                }
  
@@@ -2292,8 -2264,8 +2292,8 @@@ mono_find_jit_opcode_emulation (int opc
        return NULL;
  }
  
 -void
 -mono_register_opcode_emulation (int opcode, const char *name, const char *sigstr, gpointer func, gboolean no_throw)
 +static void
 +register_opcode_emulation (int opcode, const char *name, const char *sigstr, gpointer func, const char *symbol, gboolean no_throw)
  {
        MonoJitICallInfo *info;
        MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
        g_assert (!sig->hasthis);
        g_assert (sig->param_count < 3);
  
 -      info = mono_register_jit_icall (func, name, sig, no_throw);
 +      info = mono_register_jit_icall_full (func, name, sig, no_throw, symbol);
  
        if (emul_opcode_num >= emul_opcode_alloced) {
                int incr = emul_opcode_alloced? emul_opcode_alloced/2: 16;
        emul_opcode_hit_cache [opcode >> (EMUL_HIT_SHIFT + 3)] |= (1 << (opcode & EMUL_HIT_MASK));
  }
  
 +/*
 + * For JIT icalls implemented in C.
 + * NAME should be the same as the name of the C function whose address is FUNC.
 + */
  static void
  register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
  {
        MonoMethodSignature *sig;
  
 +      if (sigstr)
 +              sig = mono_create_icall_signature (sigstr);
 +      else
 +              sig = NULL;
 +
 +      mono_register_jit_icall_full (func, name, sig, save, save ? name : NULL);
 +}
 +
 +static void
 +register_dyn_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
 +{
 +      MonoMethodSignature *sig;
 +
        if (sigstr)
                sig = mono_create_icall_signature (sigstr);
        else
@@@ -2599,8 -2554,7 +2599,8 @@@ mono_get_lmf_addr (void
  #else
        MonoJitTlsData *jit_tls;
  
 -      if ((jit_tls = mono_native_tls_get_value (mono_jit_tls_id)))
 +      jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
 +      if (G_LIKELY (jit_tls))
                return &jit_tls->lmf;
  
        /*
@@@ -2944,10 -2898,6 +2944,10 @@@ mono_patch_info_dup_mp (MonoMemPool *mp
                memcpy (res->data.rgctx_entry, patch_info->data.rgctx_entry, sizeof (MonoJumpInfoRgctxEntry));
                res->data.rgctx_entry->data = mono_patch_info_dup_mp (mp, res->data.rgctx_entry->data);
                break;
 +      case MONO_PATCH_INFO_GSHAREDVT_CALL:
 +              res->data.gsharedvt = mono_mempool_alloc (mp, sizeof (MonoJumpInfoGSharedVtCall));
 +              memcpy (res->data.gsharedvt, patch_info->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
 +              break;
        default:
                break;
        }
@@@ -2984,8 -2934,6 +2984,8 @@@ mono_patch_info_hash (gconstpointer dat
        case MONO_PATCH_INFO_SFLDA:
        case MONO_PATCH_INFO_SEQ_POINT_INFO:
                return (ji->type << 8) | (gssize)ji->data.target;
 +      case MONO_PATCH_INFO_GSHAREDVT_CALL:
 +              return (ji->type << 8) | (gssize)ji->data.gsharedvt->method;
        default:
                return (ji->type << 8);
        }
@@@ -3022,18 -2970,13 +3022,18 @@@ mono_patch_info_equal (gconstpointer ka
                break;
        case MONO_PATCH_INFO_INTERNAL_METHOD:
                return g_str_equal (ji1->data.name, ji2->data.name);
 -
        case MONO_PATCH_INFO_RGCTX_FETCH: {
                MonoJumpInfoRgctxEntry *e1 = ji1->data.rgctx_entry;
                MonoJumpInfoRgctxEntry *e2 = ji2->data.rgctx_entry;
  
                return e1->method == e2->method && e1->in_mrgctx == e2->in_mrgctx && e1->info_type == e2->info_type && mono_patch_info_equal (e1->data, e2->data);
        }
 +      case MONO_PATCH_INFO_GSHAREDVT_CALL: {
 +              MonoJumpInfoGSharedVtCall *c1 = ji1->data.gsharedvt;
 +              MonoJumpInfoGSharedVtCall *c2 = ji2->data.gsharedvt;
 +
 +              return c1->sig == c2->sig && c1->method == c2->method;
 +      }
        default:
                if (ji1->data.target != ji2->data.target)
                        return 0;
@@@ -3085,15 -3028,6 +3085,15 @@@ mono_resolve_patch_target (MonoMethod *
                target = mono_icall_get_wrapper (mi);
                break;
        }
 +      case MONO_PATCH_INFO_JIT_ICALL_ADDR: {
 +              MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
 +              if (!mi) {
 +                      g_warning ("unknown MONO_PATCH_INFO_JIT_ICALL_ADDR %s", patch_info->data.name);
 +                      g_assert_not_reached ();
 +              }
 +              target = mi->func;
 +              break;
 +      }
        case MONO_PATCH_INFO_METHOD_JUMP:
                target = mono_create_jump_trampoline (domain, patch_info->data.method, FALSE);
  #if defined(__native_client__) && defined(__native_client_codegen__)
                                g_error ("Unregistered icall '%s'\n", mono_method_full_name (patch_info->data.method, TRUE));
                }
                break;
 -      case MONO_PATCH_INFO_JIT_ICALL_ADDR: {
 -              MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
 -              if (!mi) {
 -                      g_warning ("unknown MONO_PATCH_INFO_JIT_ICALL_ADDR %s", patch_info->data.name);
 -                      g_assert_not_reached ();
 -              }
 -              target = mi->func;
 -              break;
 -      }
        case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
                target = mono_thread_interruption_request_flag ();
                break;
                case MONO_PATCH_INFO_FIELD:
                        slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, entry->data->data.field, entry->info_type, mono_method_get_context (entry->method));
                        break;
 +              case MONO_PATCH_INFO_SIGNATURE:
 +                      slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, entry->data->data.sig, entry->info_type, mono_method_get_context (entry->method));
 +                      break;
 +              case MONO_PATCH_INFO_GSHAREDVT_CALL: {
 +                      MonoJumpInfoGSharedVtCall *call_info = mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
 +
 +                      memcpy (call_info, entry->data->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
 +                      slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, call_info, entry->info_type, mono_method_get_context (entry->method));
 +                      break;
 +              }
                default:
                        g_assert_not_reached ();
                        break;
                target = mono_domain_alloc0 (domain, sizeof (gpointer));
                break;
        }
 +      case MONO_PATCH_INFO_JIT_TLS_ID: {
 +              target = (gpointer)mono_jit_tls_id;
 +              break;
 +      }
        default:
                g_assert_not_reached ();
        }
@@@ -3464,6 -3393,8 +3464,6 @@@ mono_compile_create_vars (MonoCompile *
        mono_arch_create_vars (cfg);
  }
  
 -#endif /* #ifndef DISABLE_JIT */
 -
  void
  mono_print_code (MonoCompile *cfg, const char* msg)
  {
                mono_print_bb (bb, msg);
  }
  
 -#ifndef DISABLE_JIT
 -
  static void
  mono_postprocess_patches (MonoCompile *cfg)
  {
                         */
                        if (info) {
                                //printf ("TEST %s %p\n", info->name, patch_info->data.target);
 -                              // FIXME: CLEAN UP THIS MESS.
 -                              if ((cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) && 
 -                                      strstr (cfg->method->name, info->name)) {
 -                                      /*
 -                                       * This is an icall wrapper, and this is a call to the
 -                                       * wrapped function.
 -                                       */
 -                                      if (cfg->compile_aot) {
 -                                              patch_info->type = MONO_PATCH_INFO_JIT_ICALL_ADDR;
 -                                              patch_info->data.name = info->name;
 -                                      }
 -                              } else {
 -                                      /* for these array methods we currently register the same function pointer
 -                                       * since it's a vararg function. But this means that mono_find_jit_icall_by_addr ()
 -                                       * will return the incorrect one depending on the order they are registered.
 -                                       * See tests/test-arr.cs
 -                                       */
 -                                      if (strstr (info->name, "ves_array_new_va_") == NULL && strstr (info->name, "ves_array_element_address_") == NULL) {
 -                                              patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
 -                                              patch_info->data.name = info->name;
 -                                      }
 +                              /* for these array methods we currently register the same function pointer
 +                               * since it's a vararg function. But this means that mono_find_jit_icall_by_addr ()
 +                               * will return the incorrect one depending on the order they are registered.
 +                               * See tests/test-arr.cs
 +                               */
 +                              if (strstr (info->name, "ves_array_new_va_") == NULL && strstr (info->name, "ves_array_element_address_") == NULL) {
 +                                      patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
 +                                      patch_info->data.name = info->name;
                                }
                        }
  
@@@ -3949,34 -3895,6 +3949,34 @@@ mono_handle_out_of_line_bblock (MonoCom
        }
  }
  
 +#endif /* #ifndef DISABLE_JIT */
 +
 +static MonoJitInfo*
 +create_jit_info_for_trampoline (MonoMethod *wrapper, MonoTrampInfo *info)
 +{
 +      MonoDomain *domain = mono_get_root_domain ();
 +      MonoJitInfo *jinfo;
 +      guint8 *uw_info;
 +      guint32 info_len;
 +
 +      if (info->uw_info) {
 +              uw_info = info->uw_info;
 +              info_len = info->uw_info_len;
 +      } else {
 +              uw_info = mono_unwind_ops_encode (info->unwind_ops, &info_len);
 +      }
 +
 +      jinfo = mono_domain_alloc0 (domain, MONO_SIZEOF_JIT_INFO);
 +      jinfo->method = wrapper;
 +      jinfo->code_start = info->code;
 +      jinfo->code_size = info->code_size;
 +      jinfo->used_regs = mono_cache_unwind_info (uw_info, info_len);
 +
 +      return jinfo;
 +}
 +
 +#ifndef DISABLE_JIT
 +
  static MonoJitInfo*
  create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile)
  {
                gi = mono_jit_info_get_generic_jit_info (jinfo);
                g_assert (gi);
  
 -              gi->generic_sharing_context = cfg->generic_sharing_context;
 +              if (cfg->method->dynamic)
 +                      gi->generic_sharing_context = g_new0 (MonoGenericSharingContext, 1);
 +              else
 +                      gi->generic_sharing_context = mono_domain_alloc0 (cfg->domain, sizeof (MonoGenericSharingContext));
 +              memcpy (gi->generic_sharing_context, cfg->generic_sharing_context, sizeof (MonoGenericSharingContext));
  
                if ((method_to_compile->flags & METHOD_ATTRIBUTE_STATIC) ||
                                mini_method_get_context (method_to_compile)->method_inst ||
  }
  #endif
  
 +static MonoType*
 +get_gsharedvt_type (MonoType *t)
 +{
 +      MonoGenericParam *par = t->data.generic_param;
 +      MonoType *res;
 +
 +      /* 
 +       * Create an anonymous gparam with a different serial so normal gshared and gsharedvt methods have
 +       * a different instantiation.
 +       */
 +      g_assert (mono_generic_param_info (par));
 +      par = g_memdup (par, sizeof (MonoGenericParamFull));
 +      par->owner = NULL;
 +      // FIXME:
 +      par->image = mono_defaults.corlib;
 +      par->serial = 1;
 +      res = mono_metadata_type_dup (NULL, t);
 +      res->data.generic_param = par;
 +
 +      return res;
 +}
 +
 +static gboolean
 +is_gsharedvt_type (MonoType *t)
 +{
 +      return (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) && t->data.generic_param->serial == 1;
 +}
 +
 +/* Return whenever METHOD is a gsharedvt method */
 +static gboolean
 +is_gsharedvt_method (MonoMethod *method)
 +{
 +      MonoGenericContext *context;
 +      MonoGenericInst *inst;
 +      int i;
 +
 +      if (!method->is_inflated)
 +              return FALSE;
 +      context = mono_method_get_context (method);
 +      inst = context->class_inst;
 +      if (inst) {
 +              for (i = 0; i < inst->type_argc; ++i)
 +                      if (is_gsharedvt_type (inst->type_argv [i]))
 +                              return TRUE;
 +      }
 +      inst = context->method_inst;
 +      if (inst) {
 +              for (i = 0; i < inst->type_argc; ++i)
 +                      if (is_gsharedvt_type (inst->type_argv [i]))
 +                              return TRUE;
 +      }
 +      return FALSE;
 +}
 +
 +static gboolean
 +has_ref_constraint (MonoGenericParamInfo *info)
 +{
 +      MonoClass **constraints;
 +
 +      //return FALSE;
 +
 +      if (info && info->constraints) {
 +              constraints = info->constraints;
 +
 +              while (*constraints) {
 +                      MonoClass *cklass = *constraints;
 +                      if (!(cklass == mono_defaults.object_class || (cklass->image == mono_defaults.corlib && !strcmp (cklass->name, "ValueType")) || MONO_CLASS_IS_INTERFACE (cklass)))
 +                              return TRUE;
 +                      constraints ++;
 +              }
 +      }
 +      return FALSE;
 +}
 +
 +static MonoGenericInst*
 +get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt)
 +{
 +      MonoGenericInst *res;
 +      MonoType **type_argv;
 +      int i;
 +
 +      type_argv = g_new0 (MonoType*, inst->type_argc);
 +      for (i = 0; i < inst->type_argc; ++i) {
 +              if (!all_vt && (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)) {
 +                      type_argv [i] = shared_inst->type_argv [i];
 +              } else if (all_vt) {
 +                      if (container && has_ref_constraint (&container->type_params [i].info))
 +                              type_argv [i] = shared_inst->type_argv [i];
 +                      else
 +                              type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
 +              } else if (gsharedvt) {
 +                      type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
 +              } else {
 +                      type_argv [i] = inst->type_argv [i];
 +              }
 +      }
 +
 +      res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
 +      g_free (type_argv);
 +      return res;
 +}
 +
  /*
 - * mini_get_shared_method:
 + * mini_get_shared_method_full:
   *
   *   Return the method which is actually compiled/registered when doing generic sharing.
 + * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation.
 + * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints.
 + * METHOD can be a non-inflated generic method.
   */
  MonoMethod*
 -mini_get_shared_method (MonoMethod *method)
 +mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt)
  {
        MonoGenericContext shared_context;
        MonoMethod *declaring_method, *res;
 -      int i;
        gboolean partial = FALSE;
 +      gboolean gsharedvt = FALSE;
 +      MonoGenericContainer *class_container, *method_container = NULL;
  
 -      if (method->is_generic || method->klass->generic_container)
 +      if (method->is_generic || method->klass->generic_container) {
                declaring_method = method;
 -      else
 +      } else {
                declaring_method = mono_method_get_declaring_generic_method (method);
 +      }
  
        if (declaring_method->is_generic)
                shared_context = mono_method_get_generic_container (declaring_method)->context;
        else
                shared_context = declaring_method->klass->generic_container->context;
  
 -      /* Handle partial sharing */
 -      if (method != declaring_method && method->is_inflated && !mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE)) {
 +      /* Handle gsharedvt/partial sharing */
 +      if ((method != declaring_method && method->is_inflated && !mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE, TRUE)) ||
 +              is_gsharedvt || mini_is_gsharedvt_sharable_method (method)) {
                MonoGenericContext *context = mono_method_get_context (method);
                MonoGenericInst *inst;
 -              MonoType **type_argv;
 +
 +              gsharedvt = is_gsharedvt || mini_is_gsharedvt_sharable_method (method);
 +
 +              class_container = declaring_method->klass->generic_container;
 +              method_container = mono_method_get_generic_container (declaring_method);
  
                /* 
                 * Create the shared context by replacing the ref type arguments with
                 * type parameters, and keeping the rest.
                 */
                partial = TRUE;
 -              inst = context->class_inst;
 -              if (inst) {
 -                      type_argv = g_new0 (MonoType*, inst->type_argc);
 -                      for (i = 0; i < inst->type_argc; ++i) {
 -                              if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)
 -                                      type_argv [i] = shared_context.class_inst->type_argv [i];
 -                              else
 -                                      type_argv [i] = inst->type_argv [i];
 -                      }
 -
 -                      shared_context.class_inst = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
 -                      g_free (type_argv);
 -              }
 -
 -              inst = context->method_inst;
 -              if (inst) {
 -                      type_argv = g_new0 (MonoType*, inst->type_argc);
 -                      for (i = 0; i < inst->type_argc; ++i) {
 -                              if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)
 -                                      type_argv [i] = shared_context.method_inst->type_argv [i];
 -                              else
 -                                      type_argv [i] = inst->type_argv [i];
 -                      }
 +              if (context)
 +                      inst = context->class_inst;
 +              else
 +                      inst = shared_context.class_inst;
 +              if (inst)
 +                      shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, all_vt, gsharedvt);
  
 -                      shared_context.method_inst = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
 -                      g_free (type_argv);
 -              }
 +              if (context)
 +                      inst = context->method_inst;
 +              else
 +                      inst = shared_context.method_inst;
 +              if (inst)
 +                      shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, all_vt, gsharedvt);
        }
  
      res = mono_class_inflate_generic_method (declaring_method, &shared_context);
        return res;
  }
  
 +MonoMethod*
 +mini_get_shared_method (MonoMethod *method)
 +{
 +      return mini_get_shared_method_full (method, FALSE, FALSE);
 +}
 +
 +void
 +mini_init_gsctx (MonoGenericContext *context, MonoGenericSharingContext *gsctx)
 +{
 +      MonoGenericInst *inst;
 +      int i;
 +
 +      memset (gsctx, 0, sizeof (MonoGenericSharingContext));
 +
 +      if (context->class_inst) {
 +              inst = context->class_inst;
 +              gsctx->var_is_vt = g_new0 (gboolean, inst->type_argc);
 +
 +              for (i = 0; i < inst->type_argc; ++i) {
 +                      MonoType *type = inst->type_argv [i];
 +
 +                      if ((type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && type->data.generic_param->serial == 1)
 +                              gsctx->var_is_vt [i] = TRUE;
 +              }
 +      }
 +      if (context->method_inst) {
 +              inst = context->method_inst;
 +              gsctx->mvar_is_vt = g_new0 (gboolean, inst->type_argc);
 +
 +              for (i = 0; i < inst->type_argc; ++i) {
 +                      MonoType *type = inst->type_argv [i];
 +
 +                      if ((type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && type->data.generic_param->serial == 1)
 +                              gsctx->mvar_is_vt [i] = TRUE;
 +              }
 +      }
 +}
 +
  #ifndef DISABLE_JIT
  /*
   * mini_method_compile:
@@@ -4524,7 -4302,6 +4524,7 @@@ mini_method_compile (MonoMethod *method
        gboolean deadce_has_run = FALSE;
        gboolean try_generic_shared, try_llvm = FALSE;
        MonoMethod *method_to_compile, *method_to_register;
 +      gboolean method_is_gshared = FALSE;
  
        InterlockedIncrement (&mono_jit_stats.methods_compiled);
        if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)
                 * FIXME: Remove the method->klass->generic_class limitation.
                 */
                try_generic_shared = mono_class_generic_sharing_enabled (method->klass) &&
 -                      (opts & MONO_OPT_GSHARED) && ((method->is_generic || method->klass->generic_container) || (!method->klass->generic_class && mono_method_is_generic_sharable_impl (method, TRUE)));
 +                      (opts & MONO_OPT_GSHARED) && ((method->is_generic || method->klass->generic_container) || (!method->klass->generic_class && mono_method_is_generic_sharable_impl_full (method, TRUE, FALSE, FALSE)));
        else
                try_generic_shared = mono_class_generic_sharing_enabled (method->klass) &&
 -                      (opts & MONO_OPT_GSHARED) && mono_method_is_generic_sharable_impl (method, FALSE);
 +                      (opts & MONO_OPT_GSHARED) && mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE, TRUE);
  
        if (opts & MONO_OPT_GSHARED) {
                if (try_generic_shared)
                        mono_stats.generics_unsharable_methods++;
        }
  
 +      if (mini_is_gsharedvt_sharable_method (method)) {
 +              if (!mono_debug_count ())
 +                      try_generic_shared = FALSE;
 +              if (compile_aot)
 +                      try_generic_shared = FALSE;
 +      }
 +
 +      if (is_gsharedvt_method (method)) {
 +              /* We are AOTing a gshared method directly */
 +              method_is_gshared = TRUE;
 +              g_assert (compile_aot);
 +              try_generic_shared = TRUE;
 +      }
 +
  #ifdef ENABLE_LLVM
        try_llvm = mono_use_llvm;
  #endif
  
   restart_compile:
 -      if (try_generic_shared) {
 -              method_to_compile = mini_get_shared_method (method);
 -              g_assert (method_to_compile);
 -      } else {
 +      if (method_is_gshared) {
                method_to_compile = method;
 +      } else {
 +              if (try_generic_shared) {
 +                      method_to_compile = mini_get_shared_method (method);
 +                      g_assert (method_to_compile);
 +              } else {
 +                      method_to_compile = method;
 +              }
        }
  
        cfg = g_new0 (MonoCompile, 1);
        cfg->explicit_null_checks = debug_options.explicit_null_checks;
        cfg->soft_breakpoints = debug_options.soft_breakpoints;
        if (try_generic_shared)
 -              cfg->generic_sharing_context = (MonoGenericSharingContext*)&cfg->generic_sharing_context;
 +              cfg->generic_sharing_context = (MonoGenericSharingContext*)&cfg->gsctx;
        cfg->compile_llvm = try_llvm;
        cfg->token_info_hash = g_hash_table_new (NULL, NULL);
  
        if (cfg->gen_seq_points)
                cfg->seq_points = g_ptr_array_new ();
  
 -      if (cfg->compile_aot && !try_generic_shared && (method->is_generic || method->klass->generic_container)) {
 +      if (cfg->compile_aot && !try_generic_shared && (method->is_generic || method->klass->generic_container || method_is_gshared)) {
                cfg->exception_type = MONO_EXCEPTION_GENERIC_SHARING_FAILED;
                return cfg;
        }
  
 +      if (cfg->generic_sharing_context && (mini_is_gsharedvt_sharable_method (method) || method_is_gshared)) {
 +              MonoMethodInflated *inflated;
 +              MonoGenericContext *context;
 +
 +              // FIXME: Free the contents of gsctx if compilation fails
 +              if (method_is_gshared) {
 +                      g_assert (method->is_inflated);
 +                      inflated = (MonoMethodInflated*)method;
 +                      context = &inflated->context;
 +
 +                      /* We are compiling a gsharedvt method directly */
 +                      g_assert (compile_aot);
 +              } else {
 +                      g_assert (method_to_compile->is_inflated);
 +                      inflated = (MonoMethodInflated*)method_to_compile;
 +                      context = &inflated->context;
 +              }
 +
 +              mini_init_gsctx (context, &cfg->gsctx);
 +
 +              cfg->gsharedvt = TRUE;
 +              // FIXME:
 +              cfg->disable_llvm = TRUE;
 +      }
 +
        if (cfg->generic_sharing_context) {
                method_to_register = method_to_compile;
        } else {
  
        if (cfg->verbose_level > 0) {
                char *method_name;
 +
 +              method_name = mono_method_full_name (method, TRUE);
 +              g_print ("converting %s%s%smethod %s\n", COMPILE_LLVM (cfg) ? "llvm " : "", cfg->gsharedvt ? "gsharedvt " : "", (cfg->generic_sharing_context && !cfg->gsharedvt) ? "gshared " : "", method_name);
 +              /*
                if (COMPILE_LLVM (cfg))
                        g_print ("converting llvm method %s\n", method_name = mono_method_full_name (method, TRUE));
 +              else if (cfg->gsharedvt)
 +                      g_print ("converting gsharedvt method %s\n", method_name = mono_method_full_name (method_to_compile, TRUE));
                else if (cfg->generic_sharing_context)
                        g_print ("converting shared method %s\n", method_name = mono_method_full_name (method_to_compile, TRUE));
                else
                        g_print ("converting method %s\n", method_name = mono_method_full_name (method, TRUE));
 +              */
                g_free (method_name);
        }
  
                mono_domain_unlock (cfg->domain);
        }
  
 +#if 0
 +      if (cfg->gsharedvt)
 +              printf ("GSHAREDVT: %s\n", mono_method_full_name (cfg->method, TRUE));
 +#endif
 +
        /* collect statistics */
 +#ifndef DISABLE_PERFCOUNTERS
        mono_perfcounters->jit_methods++;
        mono_perfcounters->jit_bytes += header->code_size;
 +#endif
        mono_jit_stats.allocated_code_size += cfg->code_len;
        code_size_ratio = cfg->code_len;
        if (code_size_ratio > mono_jit_stats.biggest_method_size && mono_jit_stats.enabled) {
@@@ -5410,7 -5130,7 +5410,7 @@@ lookup_method_inner (MonoDomain *domain
        if (ji)
                return ji;
  
 -      if (!mono_method_is_generic_sharable_impl (method, FALSE))
 +      if (!mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE, TRUE))
                return NULL;
        return mono_domain_lookup_shared_generic (domain, method);
  }
@@@ -5568,42 -5288,9 +5568,42 @@@ mono_jit_compile_method_inner (MonoMeth
                return NULL;
        }
  
 +      if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
 +              WrapperInfo *info = mono_marshal_get_wrapper_info (method);
 +
 +              if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN || info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_OUT) {
 +                      static MonoTrampInfo *in_tinfo, *out_tinfo;
 +                      MonoTrampInfo *tinfo;
 +                      MonoJitInfo *jinfo;
 +                      gboolean is_in = info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN;
 +
 +                      if (is_in && in_tinfo)
 +                              return in_tinfo->code;
 +                      else if (!is_in && out_tinfo)
 +                              return out_tinfo->code;
 +
 +                      /*
 +                       * This is a special wrapper whose body is implemented in assembly, like a trampoline. We use a wrapper so EH
 +                       * works.
 +                       * FIXME: The caller signature doesn't match the callee, which might cause problems on some platforms
 +                       */
 +                      if (mono_aot_only)
 +                              mono_aot_get_trampoline_full (is_in ? "gsharedvt_trampoline" : "gsharedvt_out_trampoline", &tinfo);
 +                      else
 +                              mono_arch_get_gsharedvt_trampoline (&tinfo, FALSE);
 +                      jinfo = create_jit_info_for_trampoline (method, tinfo);
 +                      mono_jit_info_table_add (mono_get_root_domain (), jinfo);
 +                      if (is_in)
 +                              in_tinfo = tinfo;
 +                      else
 +                              out_tinfo = tinfo;
 +                      return tinfo->code;
 +              }
 +      }
 +
        if (mono_aot_only) {
                char *fullname = mono_method_full_name (method, TRUE);
 -              char *msg = g_strdup_printf ("Attempting to JIT compile method '%s' while running with --aot-only.\n", fullname);
 +              char *msg = g_strdup_printf ("Attempting to JIT compile method '%s' while running with --aot-only. See http://docs.xamarin.com/ios/about/limitations for more information.\n", fullname);
  
                *jit_ex = mono_get_exception_execution_engine (msg);
                g_free (fullname);
                mono_domain_jit_code_hash_unlock (target_domain);
                code = cfg->native_code;
  
 -              if (cfg->generic_sharing_context && mono_method_is_generic_sharable_impl (method, FALSE))
 +              if (cfg->generic_sharing_context && mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE, TRUE))
                        mono_stats.generics_shared_methods++;
 +              if (cfg->gsharedvt)
 +                      mono_stats.gsharedvt_methods++;
        } else {
                mono_domain_jit_code_hash_unlock (target_domain);
        }
@@@ -5814,16 -5499,17 +5814,16 @@@ mono_jit_compile_method_with_opt (MonoM
        MonoJitInfo *info;
        gpointer code, p;
        MonoJitICallInfo *callinfo = NULL;
 +      WrapperInfo *winfo = NULL;
  
        /*
         * ICALL wrappers are handled specially, since there is only one copy of them
         * shared by all appdomains.
         */
 -      if ((method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) && (strstr (method->name, "__icall_wrapper_") == method->name)) {
 -              const char *icall_name;
 -
 -              icall_name = method->name + strlen ("__icall_wrapper_");
 -              g_assert (icall_name);
 -              callinfo = mono_find_jit_icall_by_name (icall_name);
 +      if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
 +              winfo = mono_marshal_get_wrapper_info (method);
 +      if (winfo && winfo->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER) {
 +              callinfo = mono_find_jit_icall_by_addr (winfo->d.icall.func);
                g_assert (callinfo);
  
                /* Must be domain neutral since there is only one copy */
@@@ -5911,7 -5597,7 +5911,7 @@@ static voi
  invalidated_delegate_trampoline (char *desc)
  {
        g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
 -               "See http://www.go-mono.com/delegate.html for an explanation and ways to fix this.",
 +               "See http://www.mono-project.com/Diagnostic:Delegate for an explanation and ways to fix this.",
                 desc);
  }
  #endif
@@@ -6106,7 -5792,8 +6106,7 @@@ mono_jit_runtime_invoke (MonoMethod *me
                                }
                        }
  
 -                      if (mono_method_needs_static_rgctx_invoke (method, FALSE))
 -                              info->compiled_method = mono_create_static_rgctx_trampoline (method, info->compiled_method);
 +                      info->compiled_method = mini_add_method_trampoline (NULL, method, info->compiled_method, mono_method_needs_static_rgctx_invoke (method, FALSE));
                }
  
                /*
                                        supported = FALSE;
                        }
  
 -                      if (method->klass->contextbound || !info->compiled_method)
 +                      if (mono_class_is_contextbound (method->klass) || !info->compiled_method)
                                supported = FALSE;
  
                        if (supported)
@@@ -6402,7 -6089,6 +6402,7 @@@ SIG_HANDLER_SIGNATURE (mono_sigint_sign
        mono_arch_handle_exception (ctx, exc);
  }
  
 +#ifndef DISABLE_REMOTING
  /* mono_jit_create_remoting_trampoline:
   * @method: pointer to the method info
   *
@@@ -6423,16 -6109,14 +6423,16 @@@ mono_jit_create_remoting_trampoline (Mo
        }
  
        if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) || 
 -          (mono_method_signature (method)->hasthis && (method->klass->marshalbyref || method->klass == mono_defaults.object_class))) {
 +          (mono_method_signature (method)->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))) {
                nm = mono_marshal_get_remoting_invoke_for_target (method, target);
                addr = mono_compile_method (nm);
 -      } else {
 +      } else
 +      {
                addr = mono_compile_method (method);
        }
        return mono_get_addr_from_ftnptr (addr);
  }
 +#endif
  
  static gpointer *vtable_trampolines;
  static int vtable_trampolines_size;
@@@ -6673,10 -6357,9 +6673,10 @@@ mini_free_jit_domain_info (MonoDomain *
        g_hash_table_destroy (info->runtime_invoke_hash);
        g_hash_table_destroy (info->seq_points);
        g_hash_table_destroy (info->arch_seq_points);
 -
        if (info->agent_info)
                mono_debugger_agent_free_domain_info (domain);
 +      if (info->gsharedvt_arg_tramp_hash)
 +              g_hash_table_destroy (info->gsharedvt_arg_tramp_hash);
  
        g_free (domain->runtime_info);
        domain->runtime_info = NULL;
@@@ -6702,11 -6385,6 +6702,11 @@@ mini_init (const char *filename, const 
        if (!default_opt_set)
                default_opt = mono_parse_default_optimizations (NULL);
  
 +#ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
 +      if (mono_aot_only)
 +              mono_set_generic_sharing_vt_supported (TRUE);
 +#endif
 +
        InitializeCriticalSection (&jit_mutex);
  
  #ifdef MONO_DEBUGGER_SUPPORTED
                g_thread_init (NULL);
  
        mono_native_tls_alloc (&mono_jit_tls_id, NULL);
 -      setup_jit_tls_data ((gpointer)-1, mono_thread_abort);
  
        if (default_opt & MONO_OPT_AOT)
                mono_aot_init ();
        mono_install_free_method (mono_jit_free_method);
        mono_install_trampoline (mono_create_jit_trampoline);
        mono_install_jump_trampoline (mono_create_jump_trampoline);
 +#ifndef DISABLE_REMOTING
        mono_install_remoting_trampoline (mono_jit_create_remoting_trampoline);
 +#endif
        mono_install_delegate_trampoline (mono_create_delegate_trampoline);
        mono_install_create_domain_hook (mini_create_jit_domain_info);
        mono_install_free_domain_hook (mini_free_jit_domain_info);
        mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers", 
                                mono_runtime_install_handlers);
  
 +#ifdef PLATFORM_ANDROID
 +      mono_add_internal_call ("System.Diagnostics.Debugger::Mono_UnhandledException_internal",
 +                              mono_debugger_agent_unhandled_exception);
 +#endif
 +
 +#ifndef DISABLE_JIT
        mono_create_helper_signatures ();
 +#endif
  
        register_jit_stats ();
  
        register_icall (mono_jit_set_domain, "mono_jit_set_domain", "void ptr", TRUE);
        register_icall (mono_domain_get, "mono_domain_get", "ptr", TRUE);
  
 -      register_icall (mono_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE);
 -      register_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
 -      register_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", 
 -                               "void ptr", TRUE);
 +      register_dyn_icall (mono_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE);
 +      register_dyn_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
 +      register_dyn_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", "void ptr", TRUE);
        register_icall (mono_thread_get_undeniable_exception, "mono_thread_get_undeniable_exception", "object", FALSE);
        register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "void", FALSE);
        register_icall (mono_thread_force_interruption_checkpoint, "mono_thread_force_interruption_checkpoint", "void", FALSE);
 +#ifndef DISABLE_REMOTING
        register_icall (mono_load_remote_field_new, "mono_load_remote_field_new", "object object ptr ptr", FALSE);
        register_icall (mono_store_remote_field_new, "mono_store_remote_field_new", "void object ptr ptr object", FALSE);
 +#endif
  
  #if defined(__native_client__) || defined(__native_client_codegen__)
        register_icall (mono_nacl_gc, "mono_nacl_gc", "void", TRUE);
         * rule to the burg files, because we need the arity information to be correct.
         */
  #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
 -      mono_register_opcode_emulation (OP_LMUL, "__emul_lmul", "long long long", mono_llmult, TRUE);
 -      mono_register_opcode_emulation (OP_LDIV, "__emul_ldiv", "long long long", mono_lldiv, FALSE);
 -      mono_register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", "long long long", mono_lldiv_un, FALSE);
 -      mono_register_opcode_emulation (OP_LREM, "__emul_lrem", "long long long", mono_llrem, FALSE);
 -      mono_register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", "long long long", mono_llrem_un, FALSE);
 -      mono_register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", "long long long", mono_llmult_ovf_un, FALSE);
 -      mono_register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", "long long long", mono_llmult_ovf, FALSE);
 +      register_opcode_emulation (OP_LMUL, "__emul_lmul", "long long long", mono_llmult, "mono_llmult", TRUE);
 +      register_opcode_emulation (OP_LDIV, "__emul_ldiv", "long long long", mono_lldiv, "mono_lldiv", FALSE);
 +      register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", "long long long", mono_lldiv_un, "mono_lldiv_un", FALSE);
 +      register_opcode_emulation (OP_LREM, "__emul_lrem", "long long long", mono_llrem, "mono_llrem", FALSE);
 +      register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", "long long long", mono_llrem_un, "mono_llrem_un", FALSE);
 +      register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", "long long long", mono_llmult_ovf_un, "mono_llmult_ovf_un", FALSE);
 +      register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", "long long long", mono_llmult_ovf, "mono_llmult_ovf", FALSE);
  #endif
  
  #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
 -      mono_register_opcode_emulation (OP_LSHL, "__emul_lshl", "long long int32", mono_lshl, TRUE);
 -      mono_register_opcode_emulation (OP_LSHR, "__emul_lshr", "long long int32", mono_lshr, TRUE);
 -      mono_register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", "long long int32", mono_lshr_un, TRUE);
 +      register_opcode_emulation (OP_LSHL, "__emul_lshl", "long long int32", mono_lshl, "mono_lshl", TRUE);
 +      register_opcode_emulation (OP_LSHR, "__emul_lshr", "long long int32", mono_lshr, "mono_lshr", TRUE);
 +      register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", "long long int32", mono_lshr_un, "mono_lshr_un", TRUE);
  #endif
  
  #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
 -      mono_register_opcode_emulation (OP_IDIV, "__emul_op_idiv", "int32 int32 int32", mono_idiv, FALSE);
 -      mono_register_opcode_emulation (OP_IDIV_UN, "__emul_op_idiv_un", "int32 int32 int32", mono_idiv_un, FALSE);
 -      mono_register_opcode_emulation (OP_IREM, "__emul_op_irem", "int32 int32 int32", mono_irem, FALSE);
 -      mono_register_opcode_emulation (OP_IREM_UN, "__emul_op_irem_un", "int32 int32 int32", mono_irem_un, FALSE);
 +      register_opcode_emulation (OP_IDIV, "__emul_op_idiv", "int32 int32 int32", mono_idiv, "mono_idiv", FALSE);
 +      register_opcode_emulation (OP_IDIV_UN, "__emul_op_idiv_un", "int32 int32 int32", mono_idiv_un, "mono_idiv_un", FALSE);
 +      register_opcode_emulation (OP_IREM, "__emul_op_irem", "int32 int32 int32", mono_irem, "mono_irem", FALSE);
 +      register_opcode_emulation (OP_IREM_UN, "__emul_op_irem_un", "int32 int32 int32", mono_irem_un, "mono_irem_un", FALSE);
  #endif
  
  #ifdef MONO_ARCH_EMULATE_MUL_DIV
 -      mono_register_opcode_emulation (OP_IMUL, "__emul_op_imul", "int32 int32 int32", mono_imul, TRUE);
 +      register_opcode_emulation (OP_IMUL, "__emul_op_imul", "int32 int32 int32", mono_imul, "mono_imul", TRUE);
  #endif
  
  #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
 -      mono_register_opcode_emulation (OP_IMUL_OVF, "__emul_op_imul_ovf", "int32 int32 int32", mono_imul_ovf, FALSE);
 -      mono_register_opcode_emulation (OP_IMUL_OVF_UN, "__emul_op_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, FALSE);
 +      register_opcode_emulation (OP_IMUL_OVF, "__emul_op_imul_ovf", "int32 int32 int32", mono_imul_ovf, "mono_imul_ovf", FALSE);
 +      register_opcode_emulation (OP_IMUL_OVF_UN, "__emul_op_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, "mono_imul_ovf_un", FALSE);
  #endif
  
  #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT)
 -      mono_register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, FALSE);
 +      register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, "mono_fdiv", FALSE);
  #endif
  
 -      mono_register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8, FALSE);
 -      mono_register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4, FALSE);
 -      mono_register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8, FALSE);
 -      mono_register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8, FALSE);
 +      register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8, "mono_fconv_u8", FALSE);
 +      register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4, "mono_fconv_u4", FALSE);
 +      register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8, "mono_fconv_ovf_i8", FALSE);
 +      register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8, "mono_fconv_ovf_u8", FALSE);
  
  #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
 -      mono_register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", "long double", mono_fconv_i8, FALSE);
 +      register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", "long double", mono_fconv_i8, "mono_fconv_i8", FALSE);
  #endif
  #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
 -      mono_register_opcode_emulation (OP_ICONV_TO_R_UN, "__emul_iconv_to_r_un", "double int32", mono_conv_to_r8_un, FALSE);
 +      register_opcode_emulation (OP_ICONV_TO_R_UN, "__emul_iconv_to_r_un", "double int32", mono_conv_to_r8_un, "mono_conv_to_r8_un", FALSE);
  #endif
  #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
 -      mono_register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", "double long", mono_lconv_to_r8, FALSE);
 +      register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", "double long", mono_lconv_to_r8, "mono_lconv_to_r8", FALSE);
  #endif
  #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
 -      mono_register_opcode_emulation (OP_LCONV_TO_R4, "__emul_lconv_to_r4", "float long", mono_lconv_to_r4, FALSE);
 +      register_opcode_emulation (OP_LCONV_TO_R4, "__emul_lconv_to_r4", "float long", mono_lconv_to_r4, "mono_lconv_to_r4", FALSE);
  #endif
  #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
 -      mono_register_opcode_emulation (OP_LCONV_TO_R_UN, "__emul_lconv_to_r8_un", "double long", mono_lconv_to_r8_un, FALSE);
 +      register_opcode_emulation (OP_LCONV_TO_R_UN, "__emul_lconv_to_r8_un", "double long", mono_lconv_to_r8_un, "mono_lconv_to_r8_un", FALSE);
  #endif
  #ifdef MONO_ARCH_EMULATE_FREM
  #if defined(__default_codegen__)
 -      mono_register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", fmod, FALSE);
 +      register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", fmod, "fmod", FALSE);
  #elif defined(__native_client_codegen__)
 -      mono_register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", mono_fmod, FALSE);
 +      register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", mono_fmod, "mono_fmod", FALSE);
  #endif
  #endif
  
  #ifdef MONO_ARCH_SOFT_FLOAT
 -      mono_register_opcode_emulation (OP_FSUB, "__emul_fsub", "double double double", mono_fsub, FALSE);
 -      mono_register_opcode_emulation (OP_FADD, "__emul_fadd", "double double double", mono_fadd, FALSE);
 -      mono_register_opcode_emulation (OP_FMUL, "__emul_fmul", "double double double", mono_fmul, FALSE);
 -      mono_register_opcode_emulation (OP_FNEG, "__emul_fneg", "double double", mono_fneg, FALSE);
 -      mono_register_opcode_emulation (OP_ICONV_TO_R8, "__emul_iconv_to_r8", "double int32", mono_conv_to_r8, FALSE);
 -      mono_register_opcode_emulation (OP_ICONV_TO_R4, "__emul_iconv_to_r4", "double int32", mono_conv_to_r4, FALSE);
 -      mono_register_opcode_emulation (OP_FCONV_TO_R4, "__emul_fconv_to_r4", "double double", mono_fconv_r4, FALSE);
 -      mono_register_opcode_emulation (OP_FCONV_TO_I1, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1, FALSE);
 -      mono_register_opcode_emulation (OP_FCONV_TO_I2, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2, FALSE);
 -      mono_register_opcode_emulation (OP_FCONV_TO_I4, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4, FALSE);
 -      mono_register_opcode_emulation (OP_FCONV_TO_U1, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1, FALSE);
 -      mono_register_opcode_emulation (OP_FCONV_TO_U2, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2, FALSE);
 +      register_opcode_emulation (OP_FSUB, "__emul_fsub", "double double double", mono_fsub, "mono_fsub", FALSE);
 +      register_opcode_emulation (OP_FADD, "__emul_fadd", "double double double", mono_fadd, "mono_fadd", FALSE);
 +      register_opcode_emulation (OP_FMUL, "__emul_fmul", "double double double", mono_fmul, "mono_fmul", FALSE);
 +      register_opcode_emulation (OP_FNEG, "__emul_fneg", "double double", mono_fneg, "mono_fneg", FALSE);
 +      register_opcode_emulation (OP_ICONV_TO_R8, "__emul_iconv_to_r8", "double int32", mono_conv_to_r8, "mono_conv_to_r8", FALSE);
 +      register_opcode_emulation (OP_ICONV_TO_R4, "__emul_iconv_to_r4", "double int32", mono_conv_to_r4, "mono_conv_to_r4", FALSE);
 +      register_opcode_emulation (OP_FCONV_TO_R4, "__emul_fconv_to_r4", "double double", mono_fconv_r4, "mono_fconv_r4", FALSE);
 +      register_opcode_emulation (OP_FCONV_TO_I1, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1, "mono_fconv_i1", FALSE);
 +      register_opcode_emulation (OP_FCONV_TO_I2, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2, "mono_fconv_i2", FALSE);
 +      register_opcode_emulation (OP_FCONV_TO_I4, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
 +      register_opcode_emulation (OP_FCONV_TO_U1, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1, "mono_fconv_u1", FALSE);
 +      register_opcode_emulation (OP_FCONV_TO_U2, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2, "mono_fconv_u2", FALSE);
  #if SIZEOF_VOID_P == 4
 -      mono_register_opcode_emulation (OP_FCONV_TO_I, "__emul_fconv_to_i", "int32 double", mono_fconv_i4, FALSE);
 -#endif
 -
 -      mono_register_opcode_emulation (OP_FBEQ, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq, FALSE);
 -      mono_register_opcode_emulation (OP_FBLT, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt, FALSE);
 -      mono_register_opcode_emulation (OP_FBGT, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt, FALSE);
 -      mono_register_opcode_emulation (OP_FBLE, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le, FALSE);
 -      mono_register_opcode_emulation (OP_FBGE, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge, FALSE);
 -      mono_register_opcode_emulation (OP_FBNE_UN, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un, FALSE);
 -      mono_register_opcode_emulation (OP_FBLT_UN, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un, FALSE);
 -      mono_register_opcode_emulation (OP_FBGT_UN, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un, FALSE);
 -      mono_register_opcode_emulation (OP_FBLE_UN, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un, FALSE);
 -      mono_register_opcode_emulation (OP_FBGE_UN, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un, FALSE);
 -
 -      mono_register_opcode_emulation (OP_FCEQ, "__emul_fcmp_ceq", "uint32 double double", mono_fceq, FALSE);
 -      mono_register_opcode_emulation (OP_FCGT, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt, FALSE);
 -      mono_register_opcode_emulation (OP_FCGT_UN, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un, FALSE);
 -      mono_register_opcode_emulation (OP_FCLT, "__emul_fcmp_clt", "uint32 double double", mono_fclt, FALSE);
 -      mono_register_opcode_emulation (OP_FCLT_UN, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un, FALSE);
 +      register_opcode_emulation (OP_FCONV_TO_I, "__emul_fconv_to_i", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
 +#endif
 +
 +      register_opcode_emulation (OP_FBEQ, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq, "mono_fcmp_eq", FALSE);
 +      register_opcode_emulation (OP_FBLT, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt, "mono_fcmp_lt", FALSE);
 +      register_opcode_emulation (OP_FBGT, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt, "mono_fcmp_gt", FALSE);
 +      register_opcode_emulation (OP_FBLE, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le, "mono_fcmp_le", FALSE);
 +      register_opcode_emulation (OP_FBGE, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge, "mono_fcmp_ge", FALSE);
 +      register_opcode_emulation (OP_FBNE_UN, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un, "mono_fcmp_ne_un", FALSE);
 +      register_opcode_emulation (OP_FBLT_UN, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un, "mono_fcmp_lt_un", FALSE);
 +      register_opcode_emulation (OP_FBGT_UN, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un, "mono_fcmp_gt_un", FALSE);
 +      register_opcode_emulation (OP_FBLE_UN, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un, "mono_fcmp_le_un", FALSE);
 +      register_opcode_emulation (OP_FBGE_UN, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un, "mono_fcmp_ge_un", FALSE);
 +
 +      register_opcode_emulation (OP_FCEQ, "__emul_fcmp_ceq", "uint32 double double", mono_fceq, "mono_fceq", FALSE);
 +      register_opcode_emulation (OP_FCGT, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt, "mono_fcgt", FALSE);
 +      register_opcode_emulation (OP_FCGT_UN, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un, "mono_fcgt_un", FALSE);
 +      register_opcode_emulation (OP_FCLT, "__emul_fcmp_clt", "uint32 double double", mono_fclt, "mono_fclt", FALSE);
 +      register_opcode_emulation (OP_FCLT_UN, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un, "mono_fclt_un", FALSE);
  
        register_icall (mono_fload_r4, "mono_fload_r4", "double ptr", FALSE);
        register_icall (mono_fstore_r4, "mono_fstore_r4", "void double ptr", FALSE);
  #endif
  
  #if SIZEOF_REGISTER == 4
 -      mono_register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, TRUE);
 +      register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, "mono_fconv_u4", TRUE);
  #endif
  
        /* other jit icalls */
                "ptr ptr ptr ptr", FALSE);
        register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
        register_icall (mono_ldstr, "mono_ldstr", "object ptr ptr int32", FALSE);
 -      register_icall (mono_helper_stelem_ref_check, "helper_stelem_ref_check", "void object object", FALSE);
 +      register_icall (mono_helper_stelem_ref_check, "mono_helper_stelem_ref_check", "void object object", FALSE);
        register_icall (mono_object_new, "mono_object_new", "object ptr ptr", FALSE);
        register_icall (mono_object_new_specific, "mono_object_new_specific", "object ptr", FALSE);
        register_icall (mono_array_new, "mono_array_new", "object ptr ptr int32", FALSE);
        register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
        register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
        register_icall (mono_ldvirtfn_gshared, "mono_ldvirtfn_gshared", "ptr object ptr", FALSE);
 -      register_icall (mono_helper_compile_generic_method, "compile_generic_method", "ptr object ptr ptr", FALSE);
 -      register_icall (mono_helper_ldstr, "helper_ldstr", "object ptr int", FALSE);
 -      register_icall (mono_helper_ldstr_mscorlib, "helper_ldstr_mscorlib", "object int", FALSE);
 -      register_icall (mono_helper_newobj_mscorlib, "helper_newobj_mscorlib", "object int", FALSE);
 +      register_icall (mono_helper_compile_generic_method, "mono_helper_compile_generic_method", "ptr object ptr ptr", FALSE);
 +      register_icall (mono_helper_ldstr, "mono_helper_ldstr", "object ptr int", FALSE);
 +      register_icall (mono_helper_ldstr_mscorlib, "mono_helper_ldstr_mscorlib", "object int", FALSE);
 +      register_icall (mono_helper_newobj_mscorlib, "mono_helper_newobj_mscorlib", "object int", FALSE);
        register_icall (mono_value_copy, "mono_value_copy", "void ptr ptr ptr", FALSE);
        register_icall (mono_object_castclass, "mono_object_castclass", "object object ptr", FALSE);
        register_icall (mono_break, "mono_break", NULL, TRUE);
        register_icall (mono_array_new_1, "mono_array_new_1", "object ptr int", FALSE);
        register_icall (mono_array_new_2, "mono_array_new_2", "object ptr int int", FALSE);
        register_icall (mono_array_new_3, "mono_array_new_3", "object ptr int int int", FALSE);
 +      register_icall (mono_array_new_4, "mono_array_new_4", "object ptr int int int int", FALSE);
        register_icall (mono_get_native_calli_wrapper, "mono_get_native_calli_wrapper", "ptr ptr ptr ptr", FALSE);
        register_icall (mono_resume_unwind, "mono_resume_unwind", "void", TRUE);
 +      register_icall (mono_object_tostring_gsharedvt, "mono_object_tostring_gsharedvt", "object ptr ptr ptr", TRUE);
 +      register_icall (mono_object_gethashcode_gsharedvt, "mono_object_gethashcode_gsharedvt", "int ptr ptr ptr", TRUE);
  
        register_icall (mono_gc_wbarrier_value_copy_bitmap, "mono_gc_wbarrier_value_copy_bitmap", "void ptr ptr int int", FALSE);
  
        register_icall (mono_object_isinst_with_cache, "mono_object_isinst_with_cache", "object object ptr ptr", FALSE);
  
        register_icall (mono_debugger_agent_user_break, "mono_debugger_agent_user_break", "void", FALSE);
 +#endif
  
 +#ifdef TARGET_IOS
 +      register_icall (pthread_getspecific, "pthread_getspecific", NULL, TRUE);
  #endif
  
        mono_generic_sharing_init ();
@@@ -7155,7 -6818,6 +7155,7 @@@ print_jit_stats (void
                g_print ("Sharable generic methods: %ld\n", mono_stats.generics_sharable_methods);
                g_print ("Unsharable generic methods: %ld\n", mono_stats.generics_unsharable_methods);
                g_print ("Shared generic methods: %ld\n", mono_stats.generics_shared_methods);
 +              g_print ("Shared vtype generic methods: %ld\n", mono_stats.gsharedvt_methods);
  
                g_print ("Dynamic code allocs:    %ld\n", mono_stats.dynamic_code_alloc_count);
                g_print ("Dynamic code bytes:     %ld\n", mono_stats.dynamic_code_bytes_count);
@@@ -7201,12 -6863,9 +7201,9 @@@ mini_cleanup (MonoDomain *domain
  #endif
  
  #ifndef MONO_CROSS_COMPILE    
-       mono_runtime_shutdown ();
        /* 
-        * mono_runtime_cleanup() and mono_domain_finalize () need to
-        * be called early since they need the execution engine still
-        * fully working (mono_domain_finalize may invoke managed finalizers
-        * and mono_runtime_cleanup will wait for other threads to finish).
+        * mono_domain_finalize () needs to be called early since it needs the
+        * execution engine still fully working (it may invoke managed finalizers).
         */
        mono_domain_finalize (domain, 2000);
  #endif
        DeleteCriticalSection (&jit_mutex);
  
        DeleteCriticalSection (&mono_delegate_section);
 +
 +#ifdef USE_JUMP_TABLES
 +      mono_jumptable_cleanup ();
 +#endif
  }
  
  void
  mono_set_defaults (int verbose_level, guint32 opts)
  {
        mini_verbose = verbose_level;
 -      default_opt = opts;
 -      default_opt_set = TRUE;
 +      mono_set_optimizations (opts);
  }
  
  void
@@@ -7290,9 -6946,6 +7287,9 @@@ mono_set_optimizations (guint32 opts
  {
        default_opt = opts;
        default_opt_set = TRUE;
 +#ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
 +      mono_set_generic_sharing_vt_supported (mono_aot_only || ((default_opt & MONO_OPT_GSHAREDVT) != 0));
 +#endif
  }
  
  void
@@@ -7349,12 -7002,10 +7346,12 @@@ mono_precompile_assembly (MonoAssembly 
                        invoke = mono_marshal_get_runtime_invoke (method, FALSE);
                        mono_compile_method (invoke);
                }
 -              if (method->klass->marshalbyref && mono_method_signature (method)->hasthis) {
 +#ifndef DISABLE_REMOTING
 +              if (mono_class_is_marshalbyref (method->klass) && mono_method_signature (method)->hasthis) {
                        invoke = mono_marshal_get_remoting_invoke_with_check (method);
                        mono_compile_method (invoke);
                }
 +#endif
        }
  
        /* Load and precompile referenced assemblies as well */
@@@ -7399,148 -7050,3 +7396,148 @@@ mono_cfg_set_exception (MonoCompile *cf
  }
  
  #endif
 +
 +/* Dummy versions of some arch specific functions to avoid ifdefs at call sites */
 +
 +#ifndef MONO_ARCH_GSHAREDVT_SUPPORTED
 +
 +gboolean
 +mono_arch_gsharedvt_sig_supported (MonoMethodSignature *sig)
 +{
 +      return FALSE;
 +}
 +
 +gpointer
 +mono_arch_get_gsharedvt_call_info (gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, MonoGenericSharingContext *gsctx, gboolean gsharedvt_in, gint32 vcall_offset, gboolean calli)
 +{
 +      g_assert_not_reached ();
 +      return NULL;
 +}
 +
 +gpointer
 +mono_arch_get_gsharedvt_arg_trampoline (MonoDomain *domain, gpointer arg, gpointer addr)
 +{
 +      g_assert_not_reached ();
 +      return NULL;
 +}
 +
 +gpointer
 +mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot)
 +{
 +      g_assert_not_reached ();
 +      return NULL;
 +}
 +
 +#endif
 +
 +#if defined(MONO_ARCH_GSHAREDVT_SUPPORTED) && !defined(MONOTOUCH) && !defined(MONO_EXTENSIONS)
 +
 +gboolean
 +mono_arch_gsharedvt_sig_supported (MonoMethodSignature *sig)
 +{
 +      return FALSE;
 +}
 +
 +gpointer
 +mono_arch_get_gsharedvt_call_info (gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, MonoGenericSharingContext *gsctx, gboolean gsharedvt_in, gint32 vcall_offset, gboolean calli)
 +{
 +      NOT_IMPLEMENTED;
 +      return NULL;
 +}
 +
 +#endif
 +
 +#ifdef USE_JUMP_TABLES
 +#define DEFAULT_JUMPTABLE_CHUNK_ELEMENTS 128
 +
 +typedef struct MonoJumpTableChunk {
 +      guint32 total;
 +      guint32 active;
 +      struct MonoJumpTableChunk *previous;
 +      /* gpointer entries[total]; */
 +} MonoJumpTableChunk;
 +
 +static MonoJumpTableChunk* g_jumptable = NULL;
 +#define mono_jumptable_lock() EnterCriticalSection (&jumptable_mutex)
 +#define mono_jumptable_unlock() LeaveCriticalSection (&jumptable_mutex)
 +static CRITICAL_SECTION jumptable_mutex;
 +
 +static  MonoJumpTableChunk*
 +mono_create_jumptable_chunk (guint32 max_entries)
 +{
 +      guint32 size = sizeof (MonoJumpTableChunk) + max_entries * sizeof(gpointer);
 +      MonoJumpTableChunk *chunk = (MonoJumpTableChunk*) g_new0 (guchar, size);
 +      chunk->total = max_entries;
 +      return chunk;
 +}
 +
 +void
 +mono_jumptable_init (void)
 +{
 +      if (g_jumptable == NULL) {
 +              InitializeCriticalSection (&jumptable_mutex);
 +              g_jumptable = mono_create_jumptable_chunk (DEFAULT_JUMPTABLE_CHUNK_ELEMENTS);
 +      }
 +}
 +
 +gpointer*
 +mono_jumptable_add_entry (void)
 +{
 +      return mono_jumptable_add_entries (1);
 +}
 +
 +gpointer*
 +mono_jumptable_add_entries (guint32 entries)
 +{
 +      guint32 index;
 +      gpointer *result;
 +
 +      mono_jumptable_init ();
 +      mono_jumptable_lock ();
 +      index = g_jumptable->active;
 +      if (index + entries >= g_jumptable->total) {
 +              /*
 +               * Grow jumptable, by adding one more chunk.
 +               * We cannot realloc jumptable, as there could be pointers
 +               * to existing jump table entries in the code, so instead
 +               * we just add one more chunk.
 +               */
 +              guint32 max_entries = entries;
 +              MonoJumpTableChunk *new_chunk;
 +
 +              if (max_entries < DEFAULT_JUMPTABLE_CHUNK_ELEMENTS)
 +                      max_entries = DEFAULT_JUMPTABLE_CHUNK_ELEMENTS;
 +              new_chunk = mono_create_jumptable_chunk (max_entries);
 +              /* Link old jumptable, so that we could free it up later. */
 +              new_chunk->previous = g_jumptable;
 +              g_jumptable = new_chunk;
 +              index = 0;
 +      }
 +      g_jumptable->active = index + entries;
 +      result = (gpointer*)((guchar*)g_jumptable + sizeof(MonoJumpTableChunk)) + index;
 +      mono_jumptable_unlock();
 +
 +      return result;
 +}
 +
 +void
 +mono_jumptable_cleanup (void)
 +{
 +      if (g_jumptable) {
 +              MonoJumpTableChunk *current = g_jumptable, *prev;
 +              while (current != NULL) {
 +                      prev = current->previous;
 +                      g_free (current);
 +                      current = prev;
 +              }
 +              g_jumptable = NULL;
 +              DeleteCriticalSection (&jumptable_mutex);
 +      }
 +}
 +
 +gpointer*
 +mono_jumptable_get_entry (guint8 *code_ptr)
 +{
 +      return mono_arch_jumptable_entry_from_code (code_ptr);
 +}
 +#endif
diff --combined mono/tests/Makefile.am
index d13a92979bc8b9f9880e601c57da40d754683ded,4854e35f83b4bb74ab983c5c9e3d33d5bb9f813c..455a4b159409ec7d342845a5cc1b01e7fb533627
@@@ -1,4 -1,4 +1,4 @@@
 -SUBDIRS = cas assemblyresolve
 +SUBDIRS = cas assemblyresolve gc-descriptors
  
  check-local: test
  
@@@ -44,7 -44,6 +44,7 @@@ STRESS_TESTS_SRC=     
  # Disabled until ?mcs is fixed
  #     bug-331958.cs
  BASE_TEST_CS_SRC=             \
 +      bug-2907.cs             \
        array-init.cs           \
        arraylist.cs            \
        assemblyresolve_event.cs        \
        gchandles.cs    \
        interlocked-3.cs        \
        interlocked-4.2.cs      \
 -      finalizer-wait.cs       \
 -      critical-finalizers.cs  \
        appdomain-thread-abort.cs \
        xdomain-threads.cs      \
        w32message.cs   \
        bug-3903.cs     \
        async-with-cb-throws.cs \
        appdomain-unload-doesnot-raise-pending-events.cs        \
 -      bug-6148.cs
 +      bug-6148.cs     \
 +      assembly_append_ordering.cs     \
 +      bug-10127.cs    \
 +      allow-synchronous-major.cs
  
  TEST_CS_SRC_DIST=     \
        $(BASE_TEST_CS_SRC)     \
@@@ -446,14 -444,21 +446,14 @@@ PLATFORM_DISABLED_TESTS=dynamic-method-
  #PLATFORM_DISABLED_TESTS=dynamic-method-resurrection.exe exception17.exe
  endif
  
 -# The two finalizer tests only work under sgen
 -# gc-altstack.exe fails under boehm because it has no support for altstack
  # bug-459094.exe creates an extremely deep directory tree
  # delegate-invoke.exe depends on 929c6bc9b6d76a273f251e6f5dfacac36e9c38bd which was
  # reverted.
 -# generic_type_definition.2.exe depends on COMPILER_ACCESS which is no longer supported.
  DISABLED_TESTS=                       \
        delegate-async-exception.exe    \
        bug-348522.2.exe        \
 -      finalizer-wait.exe      \
 -      critical-finalizers.exe \
 -      gc-altstack.exe \
        bug-459094.exe \
        delegate-invoke.exe \
 -      generic_type_definition.2.exe \
        $(PLATFORM_DISABLED_TESTS)
  
  DISABLED_TESTS_WRENCH=        \
@@@ -542,10 -547,7 +542,10 @@@ TEST_IL_SRC=                     
        bug-515884.il   \
        bug-633291.il   \
        delegate-with-null-target.il    \
 -      bug-318677.il
 +      bug-318677.il   \
 +      gsharing-valuetype-layout.il    \
 +      invalid_generic_instantiation.il
 +
  
  # pre-requisite test sources: files that are not test themselves
  # but that need to be compiled
@@@ -633,7 -635,7 +633,7 @@@ endi
  endif
  endif
  
 -test: assemblyresolve/test/asm.dll testjit test-type-load test-generic-sharing test_platform test_2_1 test-messages
 +test: assemblyresolve/test/asm.dll testjit test-generic-sharing test-type-load test_platform test_2_1 test-process-exit test-sgen test-messages rm-empty-logs
  test-wrench: assemblyresolve/test/asm.dll testjit-wrench test-generic-sharing test-type-load test_platform test_2_1 test-process-exit test-sgen test-messages rm-empty-logs
  
  # Remove empty .stdout and .stderr files for wrench
@@@ -651,7 -653,7 +651,7 @@@ test_cs: $(TEST_PROG) $(TESTSI_CS) libt
        @failed=0; \
        passed=0; \
        for i in $(TESTSI_CS); do       \
 -              if $(srcdir)/test-driver '$(with_mono_path) $(TEST_PROG_RUN)' $$i '$(DISABLED_TESTS)' $(RUNTIME_ARGS); \
 +              if $(srcdir)/test-driver '$(with_mono_path) $(TEST_PROG_RUN)' $$i '$(DISABLED_TESTS)' 'no-dump' $(RUNTIME_ARGS); \
                then \
                        passed=`expr $${passed} + 1`; \
                else \
@@@ -665,7 -667,7 +665,7 @@@ test_il: $(TEST_PROG) $(TESTSI_IL) libt
        @failed=0; \
        passed=0; \
        for i in $(TESTSI_IL); do       \
 -              if $(srcdir)/test-driver '$(with_mono_path) $(TEST_PROG_RUN)' $$i "$(DISABLED_TESTS)" $(RUNTIME_ARGS); \
 +              if $(srcdir)/test-driver '$(with_mono_path) $(TEST_PROG_RUN)' $$i "$(DISABLED_TESTS)" 'no-dump' $(RUNTIME_ARGS); \
                then \
                        passed=`expr $${passed} + 1`; \
                else \
  
  testb: $(TEST_PROG) $(TESTBS)
        for i in $(TESTBS); do  \
 -              $(srcdir)/test-driver '$(with_mono_path) $(TEST_PROG_RUN)' $$i '$(DISABLED_TESTS)' $(RUNTIME_ARGS);     \
 +              $(srcdir)/test-driver '$(with_mono_path) $(TEST_PROG_RUN)' $$i '$(DISABLED_TESTS)' 'no-dump' $(RUNTIME_ARGS);   \
        done
  
  runtest-wrench: $(TESTSI_CS) $(TESTSI_IL) $(TESTBS) libtest.la $(PREREQSI_IL) $(PREREQSI_CS)
        for i in $(TESTSI_CS) $(TESTBS) $(TESTSI_IL); do        \
                rm -f $${i}.so; \
                if [ x$(AOT) = x1 ]; then if echo $(AOT_DISABLED_TESTS) | grep -v -q $${i}; then $(with_mono_path) $(JITTEST_PROG_RUN) --aot --debug $${i} > $${i}.aotlog 2>&1 || exit 1; fi; fi; \
 -              if $(srcdir)/test-driver '$(with_mono_path) $(JITTEST_PROG_RUN)' $$i '$(DISABLED_TESTS_WRENCH)' $(RUNTIME_ARGS); \
 +              if $(srcdir)/test-driver '$(with_mono_path) $(JITTEST_PROG_RUN)' $$i '$(DISABLED_TESTS_WRENCH)' 'dump-output' $(RUNTIME_ARGS); \
                then \
                        passed=`expr $${passed} + 1`; \
                else \
@@@ -713,7 -715,7 +713,7 @@@ runtest: $(TESTSI_CS) $(TESTSI_IL) $(TE
        for i in $(TESTSI_CS) $(TESTBS) $(TESTSI_IL); do        \
                rm -f $${i}.so; \
                if [ x$(AOT) = x1 ]; then if echo $(AOT_DISABLED_TESTS) | grep -v -q $${i}; then $(with_mono_path) $(JITTEST_PROG_RUN) --aot --debug $${i} > $${i}.aotlog 2>&1 || exit 1; fi; fi; \
 -              if $(srcdir)/test-driver '$(with_mono_path) $(JITTEST_PROG_RUN)' $$i '$(DISABLED_TESTS)' $(RUNTIME_ARGS); \
 +              if $(srcdir)/test-driver '$(with_mono_path) $(JITTEST_PROG_RUN)' $$i '$(DISABLED_TESTS)' 'no-dump' $(RUNTIME_ARGS); \
                then \
                        passed=`expr $${passed} + 1`; \
                else \
@@@ -786,85 -788,33 +786,85 @@@ test-type-load: TestDriver.dl
        @$(RUNTIME) load-exceptions.exe > load-exceptions.exe.stdout 2> load-exceptions.exe.stderr
  
  
 -EXTRA_DIST += sgen-bridge.cs sgen-descriptors.cs sgen-gshared-vtype.cs sgen-bridge-major-fragmentation.cs
 +EXTRA_DIST += sgen-bridge.cs sgen-descriptors.cs sgen-gshared-vtype.cs sgen-bridge-major-fragmentation.cs sgen-domain-unload.cs sgen-weakref-stress.cs sgen-cementing-stress.cs sgen-case-23400.cs    finalizer-wait.cs critical-finalizers.cs
 +
 +
 +#those are actually configurations, eg plain_sgen-descriptors.exe
 +#DISABLE_SGEN_TESTS =
  
  SGEN_TESTS =  \
 +      finalizer-wait.exe      \
 +      critical-finalizers.exe \
        sgen-descriptors.exe    \
 -      sgen-gshared-vtype.exe
 +      sgen-gshared-vtype.exe  \
 +      sgen-domain-unload.exe  \
 +      sgen-weakref-stress.exe \
 +      sgen-cementing-stress.exe       \
 +      sgen-case-23400.exe
 +
 +SGEN_CONFIGURATIONS = \
 +      "|plain"        \
 +      "major=marksweep-par|ms-par"    \
 +      "major=marksweep-conc|ms-conc"  \
 +      "major=marksweep-conc,minor=split|ms-conc-split"        \
 +      "minor=split|ms-split"  \
 +      "minor=split,alloc-ratio=95|ms-split-95"
 +
 +#FIXME We should move to use SGEN_CONFIGURATIONS once sgen supports trailling commas or its argument list.
 +SGEN_BRIDGE_CONFIGURATIONS =  \
 +      "|plain"        \
 +      ",major=marksweep-conc|ms-conc" \
 +      ",minor=split|ms-split"
  
  sgen-regular-tests: $(SGEN_TESTS)
 -      @for fn in $+ ; do      \
 -              echo "Testing $$fn ...";        \
 -              MONO_GC_PARAMS=major=marksweep-par MONO_ENV_OPTIONS="--gc=sgen" $(RUNTIME) $$fn > $$fn.stdout 2> $$fn.stderr || exit 1; \
 -              MONO_ENV_OPTIONS="--gc=sgen"                                    $(RUNTIME) $$fn > $$fn.stdout 2> $$fn.stderr || exit 1; \
 -              MONO_GC_PARAMS=major=marksweep-par,minor=split MONO_ENV_OPTIONS="--gc=sgen" $(RUNTIME) $$fn > $$fn.stdout 2> $$fn.stderr || exit 1;     \
 -              MONO_GC_PARAMS=minor=split MONO_ENV_OPTIONS="--gc=sgen"                     $(RUNTIME) $$fn > $$fn.stdout 2> $$fn.stderr || exit 1;     \
 -              MONO_GC_PARAMS=major=marksweep,concurrent-sweep MONO_ENV_OPTIONS="--gc=sgen" $(RUNTIME) $$fn > $$fn.stdout 2> $$fn.stderr || exit 1;    \
 -              MONO_GC_PARAMS=minor=split,major=marksweep,concurrent-sweep MONO_ENV_OPTIONS="--gc=sgen" $(RUNTIME) $$fn > $$fn.stdout 2> $$fn.stderr || exit 1;        \
 -              MONO_GC_PARAMS=major=marksweep-par,minor=split,alloc-ratio=95 MONO_ENV_OPTIONS="--gc=sgen" $(RUNTIME) $$fn > $$fn.stdout 2> $$fn.stderr || exit 1;      \
 -              MONO_GC_PARAMS=minor=split,alloc-ratio=95 MONO_ENV_OPTIONS="--gc=sgen"                     $(RUNTIME) $$fn > $$fn.stdout 2> $$fn.stderr || exit 1;      \
 -      done
 +      @failed=0; \
 +      passed=0; \
 +      failed_tests="";\
 +      for test in $+; do      \
 +              echo "...$$test";       \
 +              for conf in $(SGEN_CONFIGURATIONS); do  \
 +                      name=`echo $$conf | cut -d\| -f 2`;     \
 +                      params=`echo $$conf | cut -d\| -f 1`;   \
 +                      test_name="$${test}|$${name}";  \
 +                      if MONO_GC_PARAMS="$$params" MONO_ENV_OPTIONS="--gc=sgen" $(srcdir)/test-driver '$(with_mono_path) $(JITTEST_PROG_RUN)' $$test_name "$(DISABLED_TESTS_SGEN)" 'dump-output' $(RUNTIME_ARGS);     \
 +                      then \
 +                              passed=`expr $${passed} + 1`; \
 +                      else \
 +                              if [ $$? = 2 ]; then break; fi; \
 +                              failed=`expr $${failed} + 1`; \
 +                              failed_tests="$${failed_tests} $$test_name"; \
 +                      fi \
 +              done    \
 +      done;   \
 +      echo "$${passed} test(s) passed. $${failed} test(s) did not pass."; \
 +      if [ $${failed} != 0 ]; then echo -e "\nFailed tests:\n"; \
 +        for i in $${failed_tests}; do echo $${i}; done; exit 1; fi
  
 +sgen-bridge-tests: sgen-bridge.exe sgen-bridge-major-fragmentation.exe
 +      @failed=0; \
 +      passed=0; \
 +      failed_tests="";\
 +      for test in $+; do      \
 +              echo "...$$test";       \
 +              for conf in $(SGEN_BRIDGE_CONFIGURATIONS); do   \
 +                      name=`echo $$conf | cut -d\| -f 2`;     \
 +                      params=`echo $$conf | cut -d\| -f 1`;   \
 +                      test_name="$${test}|$${name}";  \
 +                      if MONO_GC_PARAMS="bridge=Bridge$${params}" MONO_ENV_OPTIONS="--gc=sgen" $(srcdir)/test-driver '$(with_mono_path) $(JITTEST_PROG_RUN)' $$test_name "$(DISABLED_TESTS_SGEN)" 'dump-output' $(RUNTIME_ARGS);      \
 +                      then \
 +                              passed=`expr $${passed} + 1`; \
 +                      else \
 +                              if [ $$? = 2 ]; then break; fi; \
 +                              failed=`expr $${failed} + 1`; \
 +                              failed_tests="$${failed_tests} $$test_name"; \
 +                      fi \
 +              done    \
 +      done;   \
 +      echo "$${passed} test(s) passed. $${failed} test(s) did not pass."; \
 +      if [ $${failed} != 0 ]; then echo -e "\nFailed tests:\n"; \
 +        for i in $${failed_tests}; do echo $${i}; done; exit 1; fi
  
 -sgen-tests: sgen-regular-tests sgen-bridge.exe sgen-bridge-major-fragmentation.exe
 -      @echo "Testing sgen-bridge.exe ...";    \
 -      MONO_GC_PARAMS=bridge=Bridge MONO_ENV_OPTIONS="--gc=sgen" $(RUNTIME) sgen-bridge.exe > sgen-bridge.exe.stdout 2> sgen-bridge.exe.stderr || exit 1;      \
 -      MONO_GC_PARAMS=bridge=Bridge,minor=split MONO_ENV_OPTIONS="--gc=sgen" $(RUNTIME) sgen-bridge.exe > sgen-bridge.exe.stdout 2> sgen-bridge.exe.stderr || exit 1;  \
 -      echo "Testing sgen-bridge-major-fragmentation.exe ..."; \
 -      MONO_GC_PARAMS=bridge=Bridge MONO_ENV_OPTIONS="--gc=sgen" $(RUNTIME) sgen-bridge-major-fragmentation.exe > sgen-bridge-major-fragmentation.exe.stdout 2> sgen-bridge-major-fragmentation.exe.stderr || exit 1;  \
 -      MONO_GC_PARAMS=bridge=Bridge,minor=split MONO_ENV_OPTIONS="--gc=sgen" $(RUNTIME) sgen-bridge-major-fragmentation.exe > sgen-bridge-major-fragmentation.exe.stdout 2> sgen-bridge-major-fragmentation.exe.stderr || exit 1;
 +sgen-tests: sgen-regular-tests sgen-bridge-tests
  
  
  # Generated tests for runtime invoke
@@@ -1062,12 -1012,16 +1062,16 @@@ patch-libtool
        sed -e 's,LIBTOOL =,LIBTOOL2 =,g' Makefile > 2 && echo "LIBTOOL = bash ./libtool" > 1 && cat 1 2 > Makefile
        touch libtest.c
  
- EXTRA_DIST += bug-438454.cs bug-438454.exe.stdout.expected
+ EXTRA_DIST += bug-438454.cs bug-438454.exe.stdout.expected threadpool-in-processexit.cs threadpool-in-processexit.exe.stdout.expected
  test-process-exit:
        @$(MCS) $(srcdir)/bug-438454.cs -out:bug-438454.exe
        @echo "Testing bug-438454.exe..."
        @$(RUNTIME) bug-438454.exe > bug-438454.exe.stdout
        @diff -w bug-438454.exe.stdout $(srcdir)/bug-438454.exe.stdout.expected
+       @$(MCS) $(srcdir)/threadpool-in-processexit.cs -out:threadpool-in-processexit.exe
+       @echo "Testing threadpool-in-processexit.exe..."
+       @$(RUNTIME) threadpool-in-processexit.exe > threadpool-in-processexit.exe.stdout
+       @diff -w threadpool-in-processexit.exe.stdout $(srcdir)/threadpool-in-processexit.exe.stdout.expected
  
  OOM_TESTS =   \
        gc-oom-handling.exe     \