Merge pull request #2940 from xmcclure/disable-jit-gsharedvt
authormonojenkins <jo.shields+jenkins@xamarin.com>
Thu, 21 Apr 2016 20:40:20 +0000 (21:40 +0100)
committermonojenkins <jo.shields+jenkins@xamarin.com>
Thu, 21 Apr 2016 20:40:20 +0000 (21:40 +0100)
Fix gsharedvt compile on DISABLE_JIT platforms

23 files changed:
mcs/class/I18N/CJK/ISO2022JP.cs
mcs/class/I18N/CJK/Test/texts/japanese-50221.txt
mcs/class/I18N/CJK/Test/texts/japanese-50222.txt
mcs/class/I18N/CJK/Test/texts/japanese-51932.txt
mcs/class/I18N/CJK/Test/texts/japanese-932.txt
mcs/class/I18N/CJK/Test/texts/japanese-utf8.txt
mcs/class/System.Data.OracleClient/System.Data.OracleClient/OracleConnection.cs
mcs/class/System.Net.Http/Documentation/en/index.xml
mcs/class/corlib/System.Threading/Monitor.cs
mcs/class/corlib/System.Threading/WaitHandle.cs
mcs/class/corlib/System/Environment.cs
mcs/class/corlib/Test/System/DelegateTest.cs
mono/metadata/appdomain.c
mono/metadata/class.c
mono/metadata/sgen-bridge.c
mono/metadata/threads-types.h
mono/metadata/threads.c
mono/mini/aot-compiler.c
mono/sgen/sgen-gchandles.c
mono/sgen/sgen-los.c
mono/sgen/sgen-marksweep.c
mono/tests/Makefile.am
mono/tests/sgen-bridge-gchandle.cs [new file with mode: 0644]

index 753b2a36b14bdea8a29b5da3bfbad8f556803c47..3ace52300071ba004f33be384f5ad5842c827f8a 100644 (file)
@@ -690,7 +690,7 @@ namespace I18N.CJK
                                                // am so lazy, so reusing jis2sjis
                                                int s1 = ((bytes [i] - 1) >> 1) + ((bytes [i] <= 0x5e) ? 0x71 : 0xb1);
                                                int s2 = bytes [i + 1] + (((bytes [i] & 1) != 0) ? 0x20 : 0x7e);
-                                               int v = (s1 - 0x81) * 0xBC;
+                                               int v = (s1 <= 0x9F ? (s1 - 0x81) : (s1 - 0xc1)) * 0xBC;
                                                v += s2 - 0x41;
 
                                                int ch = ToChar (v);
index ccfe7f457eb559f210a084a5e378651cf861b3c8..afe619503c1b9ba6c784b874839a17953f9f2c8e 100644 (file)
@@ -1,4 +1,5 @@
 \e$BF|K\8lJQ49$N\e(IC=B\e$B"+H>3Q\e(I6E\e$B$b\e(I!T/B9@^H\e(B
+[\e$BlM\e(B]
 
 Mono Directions
 
index da85bfa269d622e8c4968edd3a81236f84d8f3f3..fb2df61a8416d2f2945758685b7636da40942a7d 100644 (file)
@@ -1,4 +1,5 @@
 \e$BF|K\8lJQ49$N\ eC=B\ f"+H>3Q\ e6E\ f$b\ e!T/B9@^H\ f\e(B
+[\e$BlM\e(B]
 
 Mono Directions
 
index c1f06116fbd6452e4dd6448577df1ce0f45992ee..0fd82733278b67a285ecd48da57500e4b27de5e0 100644 (file)
@@ -1,4 +1,5 @@
 ÆüËܸìÊÑ´¹¤Î\8eÃ\8e½\8e¢«È¾³Ñ\8e\8eŤâ\8e¡\8eÔ\8e¯\8eÂ\8e¹\8eÀ\8eÞ\8eÈ
+[ìÍ]
 
 Mono Directions
 
index 596ca1c897f1372164d4602758529a14eb486f1e..21a41ba30e5b319391868f7df5b08666e8e88e33 100644 (file)
@@ -1,4 +1,5 @@
 \93ú\96{\8cê\95Ï\8a·\82ÌýÂ\81©\94¼\8ap¶Å\82à¡Ô¯Â¹ÀÞÈ
+[æË]
 
 Mono Directions
 
index 3b8c4bdcae341bbed3fde8d36dfc06f914a1a65a..bfb79bf6098d6b0bdebac49e81a907d1b74f54d6 100644 (file)
@@ -1,4 +1,5 @@
 日本語変換のテスツ←半角カナも。ヤッツケダネ
+[賤]
 
 Mono Directions
 
index e0af49f576e0178654e470b213f8688a198a0e94..6ff30b0bc856cceeeed5a815b549e2e76f1f6664 100644 (file)
@@ -964,7 +964,7 @@ namespace System.Data.OracleClient
                {
                        OracleCommand cmd = CreateCommand ();
 
-                       cmd.CommandText = "SSELECT OWNER, OBJECT_NAME, SUBOBJECT_NAME, OBJECT_ID, DATA_OBJECT_ID, LAST_DDL_TIME, " +
+                       cmd.CommandText = "SELECT OWNER, OBJECT_NAME, SUBOBJECT_NAME, OBJECT_ID, DATA_OBJECT_ID, LAST_DDL_TIME, " +
                                "    TIMESTAMP, STATUS, TEMPORARY, GENERATED, SECONDARY, CREATED " +
                                " FROM ALL_OBJECTS " +
                                " WHERE OBJECT_TYPE = '" + objType + "' " +
index eb70cc576c78dd095f011ab76dde239e0dc78642..08925bbaf2dec3812ae4d53b2780d9a9aec621ec 100644 (file)
@@ -56,6 +56,7 @@
   <Types>
     <Namespace Name="System.Net.Http">
       <Type Name="ByteArrayContent" Kind="Class" />
+      <Type Name="CFNetworkHandler" Kind="Class" />
       <Type Name="ClientCertificateOption" Kind="Enumeration" />
       <Type Name="DelegatingHandler" Kind="Class" />
       <Type Name="FormUrlEncodedContent" Kind="Class" />
index c5cda6920d2edc3729e325bd3228629350ef94ae..b76c35d2d88324116507e97faef0a68db4969c08 100644 (file)
@@ -159,33 +159,33 @@ namespace System.Threading
 
                public static bool Wait(object obj, int millisecondsTimeout, bool exitContext) {
                        try {
-                               if (exitContext) {
-#if MONOTOUCH
-                                       throw new NotSupportedException ("exitContext == true is not supported");
-#else
+#if !DISABLE_REMOTING
+                               if (exitContext)
                                        SynchronizationAttribute.ExitContext ();
 #endif
-                               }
                                return Wait (obj, millisecondsTimeout);
                        }
                        finally {
-                               if (exitContext) SynchronizationAttribute.EnterContext ();
+#if !DISABLE_REMOTING
+                               if (exitContext)
+                                       SynchronizationAttribute.EnterContext ();
+#endif
                        }
                }
 
                public static bool Wait(object obj, TimeSpan timeout, bool exitContext) {
                        try {
-                               if (exitContext) {
-#if MONOTOUCH
-                                       throw new NotSupportedException ("exitContext == true is not supported");
-#else
+#if !DISABLE_REMOTING
+                               if (exitContext)
                                        SynchronizationAttribute.ExitContext ();
 #endif
-                               }
                                return Wait (obj, timeout);
                        }
                        finally {
-                               if (exitContext) SynchronizationAttribute.EnterContext ();
+#if !DISABLE_REMOTING
+                               if (exitContext)
+                                       SynchronizationAttribute.EnterContext ();
+#endif
                        }
                }
 
index 019647bc0bd85170bb18b74ae176517b3f1b1ad9..f09b9fe7e551c33a006f27bf3fa1300258b73e04 100644 (file)
@@ -47,16 +47,13 @@ namespace System.Threading
 
                static int WaitMultiple(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext, bool WaitAll)
                {
-#if MONOTOUCH
-                       if (exitContext)
-                               throw new NotSupportedException ("exitContext == true is not supported");
-#endif
-
                        int release_last = -1;
 
                        try {
+#if !DISABLE_REMOTING
                                if (exitContext)
                                        SynchronizationAttribute.ExitContext ();
+#endif
 
                                for (int i = 0; i < waitHandles.Length; ++i) {
                                        try {
@@ -70,51 +67,52 @@ namespace System.Threading
                                }
 
                                if (WaitAll)
-                                       return WaitAll_internal (waitHandles, millisecondsTimeout, exitContext);
+                                       return WaitAll_internal (waitHandles, millisecondsTimeout);
                                else
-                                       return WaitAny_internal (waitHandles, millisecondsTimeout, exitContext);
+                                       return WaitAny_internal (waitHandles, millisecondsTimeout);
                        } finally {
                                for (int i = release_last; i >= 0; --i) {
                                        waitHandles [i].SafeWaitHandle.DangerousRelease ();
                                }
 
+#if !DISABLE_REMOTING
                                if (exitContext)
                                        SynchronizationAttribute.EnterContext ();
+#endif
                        }
                }
 
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               private static extern int WaitAll_internal(WaitHandle[] handles, int ms, bool exitContext);
+               private static extern int WaitAll_internal(WaitHandle[] handles, int ms);
 
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               private static extern int WaitAny_internal(WaitHandle[] handles, int ms, bool exitContext);
+               private static extern int WaitAny_internal(WaitHandle[] handles, int ms);
 
                static int WaitOneNative (SafeHandle waitableSafeHandle, uint millisecondsTimeout, bool hasThreadAffinity, bool exitContext)
                {
-#if MONOTOUCH
-                       if (exitContext)
-                               throw new NotSupportedException ("exitContext == true is not supported");
-#endif
-
                        bool release = false;
                        try {
+#if !DISABLE_REMOTING
                                if (exitContext)
                                        SynchronizationAttribute.ExitContext ();
+#endif
 
                                waitableSafeHandle.DangerousAddRef (ref release);
 
-                               return WaitOne_internal (waitableSafeHandle.DangerousGetHandle (), (int) millisecondsTimeout, exitContext);
+                               return WaitOne_internal (waitableSafeHandle.DangerousGetHandle (), (int) millisecondsTimeout);
                        } finally {
                                if (release)
                                        waitableSafeHandle.DangerousRelease ();
 
+#if !DISABLE_REMOTING
                                if (exitContext)
                                        SynchronizationAttribute.EnterContext ();
+#endif
                        }
                }
 
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               static extern int WaitOne_internal(IntPtr handle, int ms, bool exitContext);
+               static extern int WaitOne_internal(IntPtr handle, int ms);
 
                static int SignalAndWaitOne (SafeWaitHandle waitHandleToSignal,SafeWaitHandle waitHandleToWaitOn, int millisecondsTimeout, bool hasThreadAffinity,  bool exitContext)
                {
@@ -123,7 +121,7 @@ namespace System.Threading
                                waitHandleToSignal.DangerousAddRef (ref releaseHandleToSignal);
                                waitHandleToWaitOn.DangerousAddRef (ref releaseHandleToWaitOn);
 
-                               return SignalAndWait_Internal (waitHandleToSignal.DangerousGetHandle (), waitHandleToWaitOn.DangerousGetHandle (), millisecondsTimeout, exitContext);
+                               return SignalAndWait_Internal (waitHandleToSignal.DangerousGetHandle (), waitHandleToWaitOn.DangerousGetHandle (), millisecondsTimeout);
                        } finally {
                                if (releaseHandleToSignal)
                                        waitHandleToSignal.DangerousRelease ();
@@ -133,6 +131,6 @@ namespace System.Threading
                }
 
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               static extern int SignalAndWait_Internal (IntPtr toSignal, IntPtr toWaitOn, int ms, bool exitContext);
+               static extern int SignalAndWait_Internal (IntPtr toSignal, IntPtr toWaitOn, int ms);
        }
 }
index 88a0a1baea92e501087f9f81a7c40bf428a3bef8..73fef7906bb639c401e1f481c212ddd2a20d0e5c 100644 (file)
@@ -57,7 +57,7 @@ namespace System {
                 * of icalls, do not require an increment.
                 */
 #pragma warning disable 169
-               private const int mono_corlib_version = 145;
+               private const int mono_corlib_version = 146;
 #pragma warning restore 169
 
                [ComVisible (true)]
index ae5a82908c861894674a758b8ba8496d5027da2a..e1d95dc93f00f563a4a7415708b3714d5a107a4f 100644 (file)
@@ -1251,7 +1251,7 @@ namespace MonoTests.System
                        }
                }
        
-               delegate int IntNoArgs ();
+               public delegate int IntNoArgs ();
 
                [Test]
                public void CreateDelegateWithAbstractMethods ()
index 3c52aa7da3ac9004b9fed79f168516418514a163..effa46abdd1d93de67209e08d95a85a33301d450 100644 (file)
@@ -81,7 +81,7 @@
  * Changes which are already detected at runtime, like the addition
  * of icalls, do not require an increment.
  */
-#define MONO_CORLIB_VERSION 145
+#define MONO_CORLIB_VERSION 146
 
 typedef struct
 {
index 17da478b5e9c1f089d76de0bc275da6ab5e21077..91d31b60cc5eece43d13deef99d9933319b734b9 100644 (file)
@@ -10017,6 +10017,8 @@ is_nesting_type (MonoClass *outer_klass, MonoClass *inner_klass)
        return FALSE;
 }
 
+static gboolean debug_check;
+
 MonoClass *
 mono_class_get_generic_type_definition (MonoClass *klass)
 {
@@ -10160,6 +10162,9 @@ can_access_type (MonoClass *access_klass, MonoClass *member_klass)
 {
        int access_level;
 
+       if (access_klass == member_klass)
+               return TRUE;
+
        if (access_klass->image->assembly && access_klass->image->assembly->corlib_internal)
                return TRUE;
 
@@ -10308,26 +10313,15 @@ mono_method_can_access_field (MonoMethod *method, MonoClassField *field)
 gboolean
 mono_method_can_access_method (MonoMethod *method, MonoMethod *called)
 {
-       int can = can_access_member (method->klass, called->klass, NULL, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
-       if (!can) {
-               MonoClass *nested = method->klass->nested_in;
-               while (nested) {
-                       can = can_access_member (nested, called->klass, NULL, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
-                       if (can)
-                               return TRUE;
-                       nested = nested->nested_in;
-               }
+       gboolean res = mono_method_can_access_method_full (method, called, NULL);
+       if (!res) {
+               printf ("FAILED TO VERIFY %s calling %s\n", mono_method_full_name (method, 1), mono_method_full_name (called, 1));
+               debug_check = TRUE;
+               mono_method_can_access_method_full (method, called, NULL);
+               debug_check = FALSE;
        }
-       /* 
-        * FIXME:
-        * with generics calls to explicit interface implementations can be expressed
-        * directly: the method is private, but we must allow it. This may be opening
-        * a hole or the generics code should handle this differently.
-        * Maybe just ensure the interface type is public.
-        */
-       if ((called->flags & METHOD_ATTRIBUTE_VIRTUAL) && (called->flags & METHOD_ATTRIBUTE_FINAL))
-               return TRUE;
-       return can;
+
+       return res;
 }
 
 /*
@@ -10344,10 +10338,12 @@ mono_method_can_access_method (MonoMethod *method, MonoMethod *called)
 gboolean
 mono_method_can_access_method_full (MonoMethod *method, MonoMethod *called, MonoClass *context_klass)
 {
+       if (debug_check) printf ("CHECKING %s -> %s (%p)\n", mono_method_full_name (method, 1), mono_method_full_name (called, 1), context_klass);
        MonoClass *access_class = method->klass;
        MonoClass *member_class = called->klass;
        int can = can_access_member (access_class, member_class, context_klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
        if (!can) {
+               if (debug_check) printf ("\tcan_access_member failed\n");
                MonoClass *nested = access_class->nested_in;
                while (nested) {
                        can = can_access_member (nested, member_class, context_klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
@@ -10355,13 +10351,18 @@ mono_method_can_access_method_full (MonoMethod *method, MonoMethod *called, Mono
                                break;
                        nested = nested->nested_in;
                }
+               if (!can && debug_check) printf ("\tcan_access_member nest check failed\n");
        }
 
        if (!can)
                return FALSE;
 
+       if (debug_check) printf ("\ttype checking %s(%p) -> %s(%p)\n", 
+               mono_type_get_full_name (access_class), access_class,
+               mono_type_get_full_name (member_class), member_class);
        can = can_access_type (access_class, member_class);
        if (!can) {
+               if (debug_check) printf ("\tcan_access_type check failed\n");
                MonoClass *nested = access_class->nested_in;
                while (nested) {
                        can = can_access_type (nested, member_class);
@@ -10369,6 +10370,7 @@ mono_method_can_access_method_full (MonoMethod *method, MonoMethod *called, Mono
                                break;
                        nested = nested->nested_in;
                }
+               if (!can && debug_check) printf ("\tcan_access_type nest check failed\n");
        }
 
        if (!can)
@@ -10376,8 +10378,10 @@ mono_method_can_access_method_full (MonoMethod *method, MonoMethod *called, Mono
 
        if (called->is_inflated) {
                MonoMethodInflated * infl = (MonoMethodInflated*)called;
-               if (infl->context.method_inst && !can_access_instantiation (access_class, infl->context.method_inst))
+               if (infl->context.method_inst && !can_access_instantiation (access_class, infl->context.method_inst)) {
+                       if (debug_check) printf ("\tginst check failed\n");
                        return FALSE;
+               }
        }
                
        return TRUE;
index 3b0487c9243afe496a0f5d842a592cdf5e7dd459..74630b2c973afd4027dae0aac1c84b2515fe747f 100644 (file)
@@ -526,6 +526,30 @@ bridge_test_cross_reference2 (int num_sccs, MonoGCBridgeSCC **sccs, int num_xref
                sccs [i]->is_alive = TRUE;
 }
 
+/* This bridge keeps all peers with __test > 0 */
+static void
+bridge_test_positive_status (int num_sccs, MonoGCBridgeSCC **sccs, int num_xrefs, MonoGCBridgeXRef *xrefs)
+{
+       int i;
+
+       if (!mono_bridge_test_field) {
+               mono_bridge_test_field = mono_class_get_field_from_name (mono_object_get_class (sccs[0]->objs [0]), "__test");
+               g_assert (mono_bridge_test_field);
+       }
+
+       /*We mark all objects in a scc with live objects as reachable by scc*/
+       for (i = 0; i < num_sccs; ++i) {
+               int j;
+               for (j = 0; j < sccs [i]->num_objs; ++j) {
+                       if (test_scc (sccs [i], j)) {
+                               sccs [i]->is_alive = TRUE;
+                               break;
+                       }
+               }
+       }
+}
+
+
 static void
 register_test_bridge_callbacks (const char *bridge_class_name)
 {
@@ -533,9 +557,21 @@ register_test_bridge_callbacks (const char *bridge_class_name)
        callbacks.bridge_version = SGEN_BRIDGE_VERSION;
        callbacks.bridge_class_kind = bridge_test_bridge_class_kind;
        callbacks.is_bridge_object = bridge_test_is_bridge_object;
-       callbacks.cross_references = bridge_class_name[0] == '2' ? bridge_test_cross_reference2 : bridge_test_cross_reference;
+
+       switch (bridge_class_name [0]) {
+       case '2':
+               bridge_class = bridge_class_name + 1;
+               callbacks.cross_references = bridge_test_cross_reference2;
+               break;
+       case '3':
+               bridge_class = bridge_class_name + 1;
+               callbacks.cross_references = bridge_test_positive_status;
+               break;
+       default:
+               bridge_class = bridge_class_name;
+               callbacks.cross_references = bridge_test_cross_reference;
+       }
        mono_gc_register_bridge_callbacks (&callbacks);
-       bridge_class = bridge_class_name + (bridge_class_name[0] == '2' ? 1 : 0);
 }
 
 gboolean
index f767247435aa25f7ebe39c62836cf651692fa93e..7e740b72b53dfadb97736debbc8ef1807e1c87f7 100644 (file)
@@ -96,10 +96,10 @@ gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle);
 void ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle);
 HANDLE ves_icall_System_Threading_Events_OpenEvent_internal (MonoString *name, gint32 rights, gint32 *error);
 
-gint32 ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext);
-gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext);
-gint32 ves_icall_System_Threading_WaitHandle_WaitOne_internal(HANDLE handle, gint32 ms, gboolean exitContext);
-gint32 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms, gboolean exitContext);
+gint32 ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms);
+gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms);
+gint32 ves_icall_System_Threading_WaitHandle_WaitOne_internal(HANDLE handle, gint32 ms);
+gint32 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms);
 
 MonoArray* ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr);
 MonoArray* ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr);
index ee8b209392e91fe9c577cd82510d9f7c01820019..a7fd6491a226ccac6081cceea0fb6a313d510890 100644 (file)
@@ -1607,8 +1607,7 @@ mono_wait_uninterrupted (MonoInternalThread *thread, gboolean multiple, guint32
        return ret;
 }
 
-/* FIXME: exitContext isnt documented */
-gint32 ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
+gint32 ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms)
 {
        HANDLE *handles;
        guint32 numhandles;
@@ -1645,8 +1644,7 @@ gint32 ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_ha
        return ret == WAIT_FAILED ? 0x7fffffff : ret;
 }
 
-/* FIXME: exitContext isnt documented */
-gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
+gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms)
 {
        HANDLE handles [MAXIMUM_WAIT_OBJECTS];
        uintptr_t numhandles;
@@ -1694,8 +1692,7 @@ gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_ha
        }
 }
 
-/* FIXME: exitContext isnt documented */
-gint32 ves_icall_System_Threading_WaitHandle_WaitOne_internal(HANDLE handle, gint32 ms, gboolean exitContext)
+gint32 ves_icall_System_Threading_WaitHandle_WaitOne_internal(HANDLE handle, gint32 ms)
 {
        guint32 ret;
        MonoInternalThread *thread = mono_thread_internal_current ();
@@ -1719,7 +1716,7 @@ gint32 ves_icall_System_Threading_WaitHandle_WaitOne_internal(HANDLE handle, gin
 }
 
 gint32
-ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms, gboolean exitContext)
+ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms)
 {
        guint32 ret;
        MonoInternalThread *thread = mono_thread_internal_current ();
index 0217ba5b29cc92e9e8c223b86a9a72570a0c850f..318c4293d01da0b7c00f2b80c8beaaba4db9fb07 100644 (file)
@@ -379,18 +379,87 @@ report_loader_error (MonoAotCompile *acfg, MonoError *error, const char *format,
 
 /* Wrappers around the image writer functions */
 
+#define MAX_SYMBOL_SIZE 256
+
+static inline const char *
+mangle_symbol (const char * symbol, char * mangled_symbol, gsize length)
+{
+       gsize needed_size = length;
+
+       g_assert (NULL != symbol);
+       g_assert (NULL != mangled_symbol);
+       g_assert (0 != length);
+
+#if defined(TARGET_WIN32) && defined(TARGET_X86)
+       if (symbol && '_' != symbol [0]) {
+               needed_size = g_snprintf (mangled_symbol, length, "_%s", symbol);
+       } else {
+               needed_size = g_snprintf (mangled_symbol, length, "%s", symbol);
+       }
+#else
+       needed_size = g_snprintf (mangled_symbol, length, "%s", symbol);
+#endif
+
+       g_assert (0 <= needed_size && needed_size < length);
+       return mangled_symbol;
+}
+
+static inline char *
+mangle_symbol_alloc (const char * symbol)
+{
+       g_assert (NULL != symbol);
+
+#if defined(TARGET_WIN32) && defined(TARGET_X86)
+       if (symbol && '_' != symbol [0]) {
+               return g_strdup_printf ("_%s", symbol);
+       }
+       else {
+               return g_strdup_printf ("%s", symbol);
+       }
+#else
+       return g_strdup_printf ("%s", symbol);
+#endif
+}
+
 static inline void
 emit_section_change (MonoAotCompile *acfg, const char *section_name, int subsection_index)
 {
        mono_img_writer_emit_section_change (acfg->w, section_name, subsection_index);
 }
 
+#if defined(TARGET_WIN32) && defined(TARGET_X86)
+
+static inline void
+emit_local_symbol (MonoAotCompile *acfg, const char *name, const char *end_label, gboolean func)
+{
+       const char * mangled_symbol_name = name;
+       char * mangled_symbol_name_alloc = NULL;
+
+       if (TRUE == func) {
+               mangled_symbol_name_alloc = mangle_symbol_alloc (name);
+               mangled_symbol_name = mangled_symbol_name_alloc;
+       }
+
+       if (name != mangled_symbol_name && 0 != g_strcasecmp (name, mangled_symbol_name)) {
+               mono_img_writer_emit_label (acfg->w, mangled_symbol_name);
+       }
+       mono_img_writer_emit_local_symbol (acfg->w, mangled_symbol_name, end_label, func);
+
+       if (NULL != mangled_symbol_name_alloc) {
+               g_free (mangled_symbol_name_alloc);
+       }
+}
+
+#else
+
 static inline void
 emit_local_symbol (MonoAotCompile *acfg, const char *name, const char *end_label, gboolean func) 
 { 
-       mono_img_writer_emit_local_symbol (acfg->w, name, end_label, func); 
+       mono_img_writer_emit_local_symbol (acfg->w, name, end_label, func);
 }
 
+#endif
+
 static inline void
 emit_label (MonoAotCompile *acfg, const char *name) 
 { 
@@ -507,12 +576,37 @@ emit_nacl_call_alignment (MonoAotCompile *acfg)
 }
 #endif
 
+#if defined(TARGET_WIN32) && defined(TARGET_X86)
+
+static G_GNUC_UNUSED void
+emit_global_inner (MonoAotCompile *acfg, const char *name, gboolean func)
+{
+       const char * mangled_symbol_name = name;
+       char * mangled_symbol_name_alloc = NULL;
+
+       mangled_symbol_name_alloc = mangle_symbol_alloc (name);
+       mangled_symbol_name = mangled_symbol_name_alloc;
+       
+       if (0 != g_strcasecmp (name, mangled_symbol_name)) {
+               mono_img_writer_emit_label (acfg->w, mangled_symbol_name);
+       }
+       mono_img_writer_emit_global (acfg->w, mangled_symbol_name, func);
+
+       if (NULL != mangled_symbol_name_alloc) {
+               g_free (mangled_symbol_name_alloc);
+       }
+}
+
+#else
+
 static G_GNUC_UNUSED void
 emit_global_inner (MonoAotCompile *acfg, const char *name, gboolean func)
 {
        mono_img_writer_emit_global (acfg->w, name, func);
 }
 
+#endif
+
 static void
 emit_global (MonoAotCompile *acfg, const char *name, gboolean func)
 {
@@ -520,7 +614,7 @@ emit_global (MonoAotCompile *acfg, const char *name, gboolean func)
                g_ptr_array_add (acfg->globals, g_strdup (name));
                mono_img_writer_emit_local_symbol (acfg->w, name, NULL, func);
        } else {
-               mono_img_writer_emit_global (acfg->w, name, func);
+               emit_global_inner (acfg, name, func);
        }
 }
 
@@ -534,7 +628,7 @@ emit_symbol_size (MonoAotCompile *acfg, const char *name, const char *end_label)
 static void
 emit_info_symbol (MonoAotCompile *acfg, const char *name)
 {
-       char symbol [256];
+       char symbol [MAX_SYMBOL_SIZE];
 
        if (acfg->llvm) {
                emit_label (acfg, name);
@@ -1362,8 +1456,8 @@ static void
 arch_emit_objc_selector_ref (MonoAotCompile *acfg, guint8 *code, int index, int *code_size)
 {
 #if defined(TARGET_ARM)
-       char symbol1 [256];
-       char symbol2 [256];
+       char symbol1 [MAX_SYMBOL_SIZE];
+       char symbol2 [MAX_SYMBOL_SIZE];
        int lindex = acfg->objc_selector_index_2 ++;
 
        /* Emit ldr.imm/b */
@@ -5562,6 +5656,11 @@ get_debug_sym (MonoMethod *method, const char *prefix, GHashTable *cache)
                prefix = "_";
 #endif
 
+#if defined(TARGET_WIN32) && defined(TARGET_X86)
+       char adjustedPrefix [MAX_SYMBOL_SIZE];
+       prefix = mangle_symbol (prefix, adjustedPrefix, G_N_ELEMENTS (adjustedPrefix));
+#endif
+
        len = strlen (name1);
        name2 = (char *)malloc (strlen (prefix) + len + 16);
        memcpy (name2, prefix, strlen (prefix));
@@ -6375,7 +6474,11 @@ get_plt_entry_debug_sym (MonoAotCompile *acfg, MonoJumpInfo *ji, GHashTable *cac
                /* Need to add a prefix to create unique symbols */
                prefix = g_strdup_printf ("plt_%s_", acfg->assembly_name_sym);
        } else {
+#if defined(TARGET_WIN32) && defined(TARGET_X86)
+               prefix = mangle_symbol_alloc ("plt_");
+#else
                prefix = g_strdup ("plt_");
+#endif
        }
 
        switch (ji->type) {
@@ -6543,9 +6646,9 @@ emit_plt (MonoAotCompile *acfg)
 static G_GNUC_UNUSED void
 emit_trampoline_full (MonoAotCompile *acfg, int got_offset, MonoTrampInfo *info, gboolean emit_tinfo)
 {
-       char start_symbol [256];
-       char end_symbol [256];
-       char symbol [256];
+       char start_symbol [MAX_SYMBOL_SIZE];
+       char end_symbol [MAX_SYMBOL_SIZE];
+       char symbol [MAX_SYMBOL_SIZE];
        guint32 buf_size, info_offset;
        MonoJumpInfo *patch_info;
        guint8 *buf, *p;
@@ -6637,7 +6740,7 @@ emit_trampoline_full (MonoAotCompile *acfg, int got_offset, MonoTrampInfo *info,
 
        /* Emit debug info */
        if (unwind_ops) {
-               char symbol2 [256];
+               char symbol2 [MAX_SYMBOL_SIZE];
 
                sprintf (symbol, "%s", name);
                sprintf (symbol2, "%snamed_%s", acfg->temp_prefix, name);
@@ -6656,8 +6759,8 @@ emit_trampoline (MonoAotCompile *acfg, int got_offset, MonoTrampInfo *info)
 static void
 emit_trampolines (MonoAotCompile *acfg)
 {
-       char symbol [256];
-       char end_symbol [256];
+       char symbol [MAX_SYMBOL_SIZE];
+       char end_symbol [MAX_SYMBOL_SIZE];
        int i, tramp_got_offset;
        int ntype;
 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
@@ -8403,7 +8506,7 @@ emit_code (MonoAotCompile *acfg)
 {
        int oindex, i, prev_index;
        gboolean saved_unbox_info = FALSE;
-       char symbol [256];
+       char symbol [MAX_SYMBOL_SIZE];
 
        if (acfg->aot_opts.llvm_only)
                return;
@@ -8524,6 +8627,7 @@ emit_code (MonoAotCompile *acfg)
         * To work around linker issues, we emit a table of branches, and disassemble them at runtime.
         * This is PIE code, and the linker can update it if needed.
         */
+       
        sprintf (symbol, "method_addresses");
        emit_section_change (acfg, ".text", 1);
        emit_alignment_code (acfg, 8);
@@ -8540,11 +8644,11 @@ emit_code (MonoAotCompile *acfg)
                if (acfg->cfgs [i]) {
                        if (acfg->aot_opts.llvm_only && acfg->cfgs [i]->compile_llvm)
                                /* Obtained by calling a generated function in the LLVM image */
-                               arch_emit_direct_call (acfg, "method_addresses", FALSE, FALSE, NULL, &call_size);
+                               arch_emit_direct_call (acfg, symbol, FALSE, FALSE, NULL, &call_size);
                        else
                                arch_emit_direct_call (acfg, acfg->cfgs [i]->asm_symbol, FALSE, acfg->thumb_mixed && acfg->cfgs [i]->compile_llvm, NULL, &call_size);
                } else {
-                       arch_emit_direct_call (acfg, "method_addresses", FALSE, FALSE, NULL, &call_size);
+                       arch_emit_direct_call (acfg, symbol, FALSE, FALSE, NULL, &call_size);
                }
 #endif
        }
@@ -9269,7 +9373,7 @@ emit_got_info (MonoAotCompile *acfg, gboolean llvm)
 static void
 emit_got (MonoAotCompile *acfg)
 {
-       char symbol [256];
+       char symbol [MAX_SYMBOL_SIZE];
 
        if (acfg->aot_opts.llvm_only)
                return;
@@ -9468,7 +9572,7 @@ init_aot_file_info (MonoAotCompile *acfg, MonoAotFileInfo *info)
 static void
 emit_aot_file_info (MonoAotCompile *acfg, MonoAotFileInfo *info)
 {
-       char symbol [256];
+       char symbol [MAX_SYMBOL_SIZE];
        int i, sindex;
        const char **symbols;
 
@@ -9629,7 +9733,7 @@ emit_file_info (MonoAotCompile *acfg)
        init_aot_file_info (acfg, info);
 
        if (acfg->aot_opts.static_link) {
-               char symbol [256];
+               char symbol [MAX_SYMBOL_SIZE];
                char *p;
 
                /*
@@ -10046,7 +10150,13 @@ compile_asm (MonoAotCompile *acfg)
        }
 #endif
 
-       rename (tmp_outfile_name, outfile_name);
+       if (0 != rename (tmp_outfile_name, outfile_name)) {
+               if (G_FILE_ERROR_EXIST == g_file_error_from_errno (errno)) {
+                       /* Since we are rebuilding the module we need to be able to replace any old copies. Remove old file and retry rename operation. */
+                       unlink (outfile_name);
+                       rename (tmp_outfile_name, outfile_name);
+               }
+       }
 
 #if defined(TARGET_MACH)
        command = g_strdup_printf ("dsymutil \"%s\"", outfile_name);
index 223116861a66974e1139928cbb335f127254da88..6fc24a2151a8e4b464f94cb5724afe32af392a6e 100644 (file)
@@ -477,7 +477,7 @@ null_link_if (gpointer hidden, GCHandleType handle_type, int max_generation, gpo
                return hidden;
 
        if (closure->predicate (obj, closure->data))
-               return NULL;
+               return MONO_GC_HANDLE_METADATA_POINTER (sgen_client_default_metadata (), GC_HANDLE_TYPE_IS_WEAK (handle_type));
 
        return hidden;
 }
index 5cb3c71253d1bb6ce1cced697b7affe438d61067..c22afd22f21d01c67998ee4e75dadedc444eb737 100644 (file)
@@ -307,7 +307,8 @@ free_los_section_memory (LOSObject *obj, size_t size)
 void
 sgen_los_free_object (LOSObject *obj)
 {
-       SGEN_ASSERT (0, !obj->cardtable_mod_union, "We should never free a LOS object with a mod-union table.");
+       if (obj->cardtable_mod_union)
+               sgen_card_table_free_mod_union (obj->cardtable_mod_union, (char*)obj->data, sgen_los_object_size (obj));
 
 #ifndef LOS_DUMMY
        mword size = sgen_los_object_size (obj);
@@ -433,12 +434,13 @@ sgen_los_sweep (void)
        for (bigobj = los_object_list; bigobj;) {
                SGEN_ASSERT (0, !SGEN_OBJECT_IS_PINNED (bigobj->data), "Who pinned a LOS object?");
 
-               if (bigobj->cardtable_mod_union) {
-                       sgen_card_table_free_mod_union (bigobj->cardtable_mod_union, (char*)bigobj->data, sgen_los_object_size (bigobj));
-                       bigobj->cardtable_mod_union = NULL;
-               }
-
                if (sgen_los_object_is_pinned (bigobj->data)) {
+                       if (bigobj->cardtable_mod_union) {
+                               mword obj_size = sgen_los_object_size (bigobj);
+                               mword num_cards = sgen_card_table_number_of_cards_in_range ((mword) bigobj->data, obj_size);
+                               memset (bigobj->cardtable_mod_union, 0, num_cards);
+                       }
+
                        sgen_los_unpin_object (bigobj->data);
                        sgen_update_heap_boundaries ((mword)bigobj->data, (mword)bigobj->data + sgen_los_object_size (bigobj));
                } else {
index d2e3ccdd0093dcc9e68432ef1e8f20b9198651a2..4c63191ad447d0ea5c9fb76bf44f9eba3ee19b46 100644 (file)
@@ -375,11 +375,14 @@ ms_get_empty_block (void)
  * list, where it will either be freed later on, or reused in nursery collections.
  */
 static void
-ms_free_block (void *block)
+ms_free_block (MSBlockInfo *info)
 {
        void *empty;
+       char *block = MS_BLOCK_FOR_BLOCK_INFO (info);
 
        sgen_memgov_release_space (MS_BLOCK_SIZE, SPACE_MAJOR);
+       if (info->cardtable_mod_union)
+               sgen_card_table_free_mod_union (info->cardtable_mod_union, block, MS_BLOCK_SIZE);
        memset (block, 0, MS_BLOCK_SIZE);
 
        do {
@@ -1507,10 +1510,8 @@ ensure_block_is_checked_for_sweeping (guint32 block_index, gboolean wait, gboole
 
        count = MS_BLOCK_FREE / block->obj_size;
 
-       if (block->cardtable_mod_union) {
-               sgen_card_table_free_mod_union (block->cardtable_mod_union, MS_BLOCK_FOR_BLOCK_INFO (block), MS_BLOCK_SIZE);
-               block->cardtable_mod_union = NULL;
-       }
+       if (block->cardtable_mod_union)
+               memset (block->cardtable_mod_union, 0, CARDS_PER_BLOCK);
 
        /* Count marked objects in the block */
        for (i = 0; i < MS_NUM_MARK_WORDS; ++i)
@@ -2484,10 +2485,21 @@ update_cardtable_mod_union (void)
        MSBlockInfo *block;
 
        FOREACH_BLOCK_NO_LOCK (block) {
-               size_t num_cards;
-               guint8 *mod_union = get_cardtable_mod_union_for_block (block, TRUE);
-               sgen_card_table_update_mod_union (mod_union, MS_BLOCK_FOR_BLOCK_INFO (block), MS_BLOCK_SIZE, &num_cards);
-               SGEN_ASSERT (6, num_cards == CARDS_PER_BLOCK, "Number of cards calculation is wrong");
+               gpointer *card_start = (gpointer*) sgen_card_table_get_card_address ((mword)MS_BLOCK_FOR_BLOCK_INFO (block));
+               gboolean has_dirty_cards = FALSE;
+               int i;
+               for (i = 0; i < CARDS_PER_BLOCK / sizeof(gpointer); i++) {
+                       if (card_start [i]) {
+                               has_dirty_cards = TRUE;
+                               break;
+                       }
+               }
+               if (has_dirty_cards) {
+                       size_t num_cards;
+                       guint8 *mod_union = get_cardtable_mod_union_for_block (block, TRUE);
+                       sgen_card_table_update_mod_union (mod_union, MS_BLOCK_FOR_BLOCK_INFO (block), MS_BLOCK_SIZE, &num_cards);
+                       SGEN_ASSERT (6, num_cards == CARDS_PER_BLOCK, "Number of cards calculation is wrong");
+               }
        } END_FOREACH_BLOCK_NO_LOCK;
 }
 
index 03bae54e17a22799cc20b98346b97d18dac1af84..86a740ca0579e5dc75f60f5025acf3b457ca0959 100644 (file)
@@ -964,7 +964,7 @@ debug-casts:
        @$(MCS) -r:TestDriver.dll $(srcdir)/debug-casts.cs
        @$(RUNTIME) --debug=casts debug-casts.exe
 
-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 sgen-domain-unload-2.cs sgen-suspend.cs sgen-new-threads-dont-join-stw.cs sgen-bridge-xref.cs bug-17590.cs sgen-toggleref.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 sgen-domain-unload-2.cs sgen-suspend.cs sgen-new-threads-dont-join-stw.cs sgen-bridge-xref.cs bug-17590.cs sgen-toggleref.cs sgen-bridge-gchandle.cs
 
 
 sgen-tests:
@@ -1105,6 +1105,38 @@ sgen-bridge2-tests-plain-tarjan-bridge: $(SGEN_BRIDGE2_TESTS) test-runner.exe
 sgen-bridge2-tests-ms-split-tarjan-bridge: $(SGEN_BRIDGE2_TESTS) test-runner.exe
        MONO_ENV_OPTIONS="--gc=sgen" MONO_GC_DEBUG="bridge=2Bridge" MONO_GC_PARAMS="bridge-implementation=tarjan,minor=split" $(RUNTIME) ./test-runner.exe --testsuite-name $@ --timeout 900 $(SGEN_BRIDGE2_TESTS)
 
+
+SGEN_BRIDGE3_TESTS=    \
+       sgen-bridge-gchandle.exe
+
+sgen-bridge3-tests: $(SGEN_BRIDGE3_TESTS)
+       $(MAKE) sgen-bridge3-tests-plain
+       $(MAKE) sgen-bridge3-tests-ms-conc
+       $(MAKE) sgen-bridge3-tests-ms-split
+       $(MAKE) sgen-bridge3-tests-plain-new-bridge
+       $(MAKE) sgen-bridge3-tests-ms-conc-new-bridge
+       $(MAKE) sgen-bridge3-tests-ms-split-new-bridge
+       $(MAKE) sgen-bridge3-tests-plain-tarjan-bridge
+       $(MAKE) sgen-bridge3-tests-ms-split-tarjan-bridge
+
+sgen-bridge3-tests-plain: $(SGEN_bridge3_TESTS) test-runner.exe
+       MONO_ENV_OPTIONS="--gc=sgen" MONO_GC_DEBUG="bridge=3Bridge" MONO_GC_PARAMS="" $(RUNTIME) ./test-runner.exe --testsuite-name $@ --timeout 900 $(SGEN_BRIDGE3_TESTS)
+sgen-bridge3-tests-ms-conc: $(SGEN_BRIDGE3_TESTS) test-runner.exe
+       MONO_ENV_OPTIONS="--gc=sgen" MONO_GC_DEBUG="bridge=3Bridge" MONO_GC_PARAMS="major=marksweep-conc" $(RUNTIME) ./test-runner.exe --testsuite-name $@ --timeout 900 $(SGEN_BRIDGE3_TESTS)
+sgen-bridge3-tests-ms-split: $(SGEN_BRIDGE3_TESTS) test-runner.exe
+       MONO_ENV_OPTIONS="--gc=sgen" MONO_GC_DEBUG="bridge=3Bridge" MONO_GC_PARAMS="minor=split" $(RUNTIME) ./test-runner.exe --testsuite-name $@ --timeout 900 $(SGEN_BRIDGE3_TESTS)
+sgen-bridge3-tests-plain-new-bridge: $(SGEN_BRIDGE3_TESTS) test-runner.exe
+       MONO_ENV_OPTIONS="--gc=sgen" MONO_GC_DEBUG="bridge=3Bridge" MONO_GC_PARAMS="bridge-implementation=new" $(RUNTIME) ./test-runner.exe --testsuite-name $@ --timeout 900 $(SGEN_BRIDGE3_TESTS)
+sgen-bridge3-tests-ms-conc-new-bridge: $(SGEN_BRIDGE3_TESTS) test-runner.exe
+       MONO_ENV_OPTIONS="--gc=sgen" MONO_GC_DEBUG="bridge=3Bridge" MONO_GC_PARAMS="bridge-implementation=new,major=marksweep-conc" $(RUNTIME) ./test-runner.exe --testsuite-name $@ --timeout 900 $(SGEN_BRIDGE3_TESTS)
+sgen-bridge3-tests-ms-split-new-bridge: $(SGEN_BRIDGE3_TESTS) test-runner.exe
+       MONO_ENV_OPTIONS="--gc=sgen" MONO_GC_DEBUG="bridge=3Bridge" MONO_GC_PARAMS="bridge-implementation=new,minor=split" $(RUNTIME) ./test-runner.exe --testsuite-name $@ --timeout 900 $(SGEN_BRIDGE3_TESTS)
+sgen-bridge3-tests-plain-tarjan-bridge: $(SGEN_BRIDGE3_TESTS) test-runner.exe
+       MONO_ENV_OPTIONS="--gc=sgen" MONO_GC_DEBUG="bridge=3Bridge" MONO_GC_PARAMS="bridge-implementation=tarjan" $(RUNTIME) ./test-runner.exe --testsuite-name $@ --timeout 900 $(SGEN_BRIDGE3_TESTS)
+sgen-bridge3-tests-ms-split-tarjan-bridge: $(SGEN_BRIDGE3_TESTS) test-runner.exe
+       MONO_ENV_OPTIONS="--gc=sgen" MONO_GC_DEBUG="bridge=3Bridge" MONO_GC_PARAMS="bridge-implementation=tarjan,minor=split" $(RUNTIME) ./test-runner.exe --testsuite-name $@ --timeout 900 $(SGEN_BRIDGE3_TESTS)
+
+
 AOT_CONFIGURATIONS=    \
        "|regular"      \
        "--gc=boehm|boehm"
diff --git a/mono/tests/sgen-bridge-gchandle.cs b/mono/tests/sgen-bridge-gchandle.cs
new file mode 100644 (file)
index 0000000..c9a7064
--- /dev/null
@@ -0,0 +1,78 @@
+using System;
+using System.Collections;
+using System.Threading;
+using System.Runtime.InteropServices;
+
+
+public class Bridge {
+       public int __test;
+       public string id;
+       
+       ~Bridge () {
+               try {Console.WriteLine ("bridge {0} gone", id);} catch (Exception) {}
+       }
+}
+
+
+/*
+Test scenario:
+       Alloc a bridge and create a gc handle to it
+       Get it collected.
+       Create another one and see it steal the handle of the previous one.
+
+
+*/
+class Driver {
+       public static GCHandle weak_track_handle;
+       public static GCHandle weak_track_handle2;
+
+       static void CreateFirstBridge () {
+               Bridge b = new Bridge() {
+                       __test = 0,
+                       id = "first",
+               };
+               weak_track_handle = GCHandle.Alloc (b, GCHandleType.WeakTrackResurrection);
+       }
+
+       static void CreateSecondBridge () {
+               Bridge b = new Bridge() {
+                       __test = 1,
+                       id = "second",
+               };
+               weak_track_handle2 = GCHandle.Alloc (b, GCHandleType.WeakTrackResurrection);
+       }
+
+       static void DumpHandle (GCHandle h, string name) {
+               Console.WriteLine ("{0}:{1:X} alloc:{2} hasValue:{2}", name, (IntPtr)h, h.IsAllocated, h.Target == null);
+       }
+
+       static int Main () {
+               var t = new Thread (CreateFirstBridge);
+               t.Start ();
+               t.Join ();
+
+               GC.Collect ();
+               GC.WaitForPendingFinalizers ();
+               Console.WriteLine ("GC DONE");
+
+               DumpHandle (weak_track_handle, "weak-track1");
+
+               t = new Thread (CreateSecondBridge);
+               t.Start ();
+               t.Join ();
+
+               GC.Collect ();
+               GC.WaitForPendingFinalizers ();
+               Console.WriteLine ("GC DONE");
+               DumpHandle (weak_track_handle, "weak-track1");
+               DumpHandle (weak_track_handle2, "weak-track2");
+               Console.WriteLine ("DONE");
+
+               if ((IntPtr)weak_track_handle == (IntPtr)weak_track_handle2) {
+                       Console.WriteLine ("FIRST HANDLE GOT DEALLOCATED!");
+                       return 1;
+               }
+
+               return 0;
+       }
+}