2008-06-17 Mark Probst <mark.probst@gmail.com>
authorMark Probst <mark.probst@gmail.com>
Tue, 17 Jun 2008 14:52:31 +0000 (14:52 -0000)
committerMark Probst <mark.probst@gmail.com>
Tue, 17 Jun 2008 14:52:31 +0000 (14:52 -0000)
* object.c, class-internals.h: New function for checking whether
an individual field is special static.

2008-06-17  Mark Probst  <mark.probst@gmail.com>

* mini.c: Don't compute the vtable to determine whether a field is
special static, because it might not work for open types.

2008-06-17  Mark Probst  <mark.probst@gmail.com>

* generic-special.2.cs: Test case for static special fields in
generic classes.

* Makefile.am: Test added.

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

mono/metadata/ChangeLog
mono/metadata/class-internals.h
mono/metadata/object.c
mono/mini/ChangeLog
mono/mini/mini.c
mono/tests/ChangeLog
mono/tests/Makefile.am
mono/tests/generic-special.2.cs [new file with mode: 0644]

index 098360cc2c907e461255f8f097a06900572f6b4a..9b83f712003074eea09e0c2e2652534c3f4943f0 100644 (file)
@@ -1,3 +1,8 @@
+2008-06-17  Mark Probst  <mark.probst@gmail.com>
+
+       * object.c, class-internals.h: New function for checking whether
+       an individual field is special static.
+
 2008-06-15  Zoltan Varga  <vargaz@gmail.com>
 
        * metadata.c (mono_metadata_get_generic_param_row): Use bsearch instead of
index 5ba44b169f0c939bea99e500653e47938d45a62a..46b56608d96c3d9ec564df45578f907100296754 100644 (file)
@@ -725,6 +725,9 @@ mono_class_get_finalizer (MonoClass *klass) MONO_INTERNAL;
 gboolean
 mono_class_needs_cctor_run (MonoClass *klass, MonoMethod *caller) MONO_INTERNAL;
 
+gboolean
+mono_class_field_is_special_static (MonoClassField *field) MONO_INTERNAL;
+
 gboolean
 mono_class_has_special_static_fields (MonoClass *klass) MONO_INTERNAL;
 
index dac23b4a82eb334cbf98cf0b7e4addf8e16c8a70..423651cd9960074df4532565c55480a702174e45 100644 (file)
@@ -1729,6 +1729,25 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
        return pvt;
 }
 
+/**
+ * mono_class_field_is_special_static:
+ *
+ *   Returns whether @field is a thread/context static field.
+ */
+gboolean
+mono_class_field_is_special_static (MonoClassField *field)
+{
+       if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
+               return FALSE;
+       if (mono_field_is_deleted (field))
+               return FALSE;
+       if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
+               if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
+                       return TRUE;
+       }
+       return FALSE;
+}
+
 /**
  * mono_class_has_special_static_fields:
  * 
@@ -1742,14 +1761,9 @@ mono_class_has_special_static_fields (MonoClass *klass)
 
        iter = NULL;
        while ((field = mono_class_get_fields (klass, &iter))) {
-               if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
-                       continue;
-               if (mono_field_is_deleted (field))
-                       continue;
-               if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
-                       if (field_is_special_static (klass, field) != SPECIAL_STATIC_NONE)
-                               return TRUE;
-               }
+               g_assert (field->parent == klass);
+               if (mono_class_field_is_special_static (field))
+                       return TRUE;
        }
 
        return FALSE;
index 8de0f2f556693ed971007b9daee5139246005b78..e8b2c940ffa81f2a943a6358a8a0211b2373cf1b 100644 (file)
@@ -1,3 +1,8 @@
+2008-06-17  Mark Probst  <mark.probst@gmail.com>
+
+       * mini.c: Don't compute the vtable to determine whether a field is
+       special static, because it might not work for open types.
+
 2008-06-17  Mark Probst  <mark.probst@gmail.com>
 
        * mini.c: Removed the unused token_type and token_source arguments
index aeaecfeacc2a6b67c340e362e85f757c0ed7281c..c03be111d059b4b98f4f3b8f0a4b3afa1c1af37d 100644 (file)
@@ -7400,6 +7400,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                case CEE_LDSFLDA:
                case CEE_STSFLD: {
                        MonoClassField *field;
+                       gboolean is_special_static;
                        gpointer addr = NULL;
 
                        CHECK_OPSIZE (5);
@@ -7439,27 +7440,23 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if ((*ip) == CEE_STSFLD)
                                handle_loaded_temps (cfg, bblock, stack_start, sp);
 
-                       /* The special_static_fields field is init'd in mono_class_vtable, so it needs
-                        * to be called here.
-                        */
-                       if (!(cfg->opt & MONO_OPT_SHARED)) {
-                               mono_class_vtable (cfg->domain, klass);
-                               CHECK_TYPELOAD (klass);
-                       }
-                       mono_domain_lock (cfg->domain);
-                       if (cfg->domain->special_static_fields)
-                               addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
-                       mono_domain_unlock (cfg->domain);
+                       is_special_static = mono_class_field_is_special_static (field);
 
-                       if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
+                       if ((cfg->opt & MONO_OPT_SHARED) ||
+                                       (cfg->compile_aot && is_special_static) ||
+                                       (context_used && is_special_static)) {
                                int temp;
                                MonoInst *iargs [2];
-                               MonoInst *domain_var;
 
                                g_assert (field->parent);
-                               /* avoid depending on undefined C behavior in sequence points */
-                               domain_var = mono_get_domainvar (cfg);
-                               NEW_TEMPLOAD (cfg, iargs [0], domain_var->inst_c0);
+                               if ((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) {
+                                       MonoInst *domain_var;
+                                       /* avoid depending on undefined C behavior in sequence points */
+                                       domain_var = mono_get_domainvar (cfg);
+                                       NEW_TEMPLOAD (cfg, iargs [0], domain_var->inst_c0);
+                               } else {
+                                       NEW_DOMAINCONST (cfg, iargs [0]);
+                               }
                                if (context_used) {
                                        MonoInst *rgctx;
 
@@ -7526,7 +7523,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                vtable = mono_class_vtable (cfg->domain, klass);
                                CHECK_TYPELOAD (klass);
-                               if (!addr) {
+                               if (!is_special_static) {
                                        if (mini_field_access_needs_cctor_run (cfg, method, vtable) && !(g_slist_find (class_inits, vtable))) {
                                                guint8 *tramp = mono_create_class_init_trampoline (vtable);
                                                mono_emit_native_call (cfg, bblock, tramp, 
@@ -7552,13 +7549,28 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        else
                                                NEW_PCONST (cfg, ins, addr);
                                } else {
+                                       int temp;
+                                       MonoInst *iargs [1];
+
+                                       /* The special_static_fields
+                                        * field is init'd in
+                                        * mono_class_vtable, so it
+                                        * needs to be called here.
+                                        */
+                                       if (!(cfg->opt & MONO_OPT_SHARED)) {
+                                               mono_class_vtable (cfg->domain, klass);
+                                               CHECK_TYPELOAD (klass);
+                                       }
+                                       mono_domain_lock (cfg->domain);
+                                       if (cfg->domain->special_static_fields)
+                                               addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
+                                       mono_domain_unlock (cfg->domain);
+
                                        /* 
                                         * insert call to mono_threads_get_static_data (GPOINTER_TO_UINT (addr)) 
                                         * This could be later optimized to do just a couple of
                                         * memory dereferences with constant offsets.
                                         */
-                                       int temp;
-                                       MonoInst *iargs [1];
                                        NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
                                        temp = mono_emit_jit_icall (cfg, bblock, mono_get_special_static_data, iargs, ip);
                                        NEW_TEMPLOAD (cfg, ins, temp);
@@ -7590,7 +7602,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        MONO_ADD_INS (bblock, store);
                        } else {
                                gboolean is_const = FALSE;
-                               MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
+                               MonoVTable *vtable = NULL;
+
+                               if (!context_used)
+                                       vtable = mono_class_vtable (cfg->domain, klass);
 
                                CHECK_TYPELOAD (klass);
                                if (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && 
index 6047ea7396bd1f3745033cdfd91c632015dea001..3a2909cdbe8f3dccb4967e3b15839d0f76482ae1 100644 (file)
@@ -1,3 +1,10 @@
+2008-06-17  Mark Probst  <mark.probst@gmail.com>
+
+       * generic-special.2.cs: Test case for static special fields in
+       generic classes.
+
+       * Makefile.am: Test added.
+
 2008-06-17  Mark Probst  <mark.probst@gmail.com>
 
        * Makefile.am: Also run generic sharing tests with inlining
index f4cc570b30290be3801e19799d0208401523268f..cebfa05498bf4b155c6059c766c3ef77fdbc1c09 100644 (file)
@@ -273,6 +273,7 @@ BASE_TEST_CS_SRC=           \
        generic-method-patching.2.cs    \
        generic-static-methods.2.cs     \
        generic-null-call.2.cs  \
+       generic-special.2.cs    \
        recursive-generics.2.cs \
        bug-80392.2.cs          \
        dynamic-method-access.2.cs      \
@@ -705,7 +706,7 @@ test-generic-sharing : generics-sharing.2.exe shared-generic-methods.2.exe  \
                generic-interface-methods.2.exe generic-array-type.2.exe        \
                generic-method-patching.2.exe generic-static-methods.2.exe      \
                generic-null-call.2.exe generic-tailcall2.2.exe                 \
-               generic-array-exc.2.exe
+               generic-array-exc.2.exe generic-special.2.exe
        for fn in $+ ; do       \
                echo "Testing $$fn ...";        \
                MONO_GENERIC_SHARING=all $(RUNTIME) -O=gshared                $$fn || exit 1;   \
diff --git a/mono/tests/generic-special.2.cs b/mono/tests/generic-special.2.cs
new file mode 100644 (file)
index 0000000..dc66a7a
--- /dev/null
@@ -0,0 +1,42 @@
+using System;
+using System.Threading;
+
+public class IntClass {
+       public int i;
+
+       public IntClass (int val) { i = val; }
+
+       public int get () { return i; }
+}
+
+public class Gen<T> {
+       [ThreadStaticAttribute]
+       static T field;
+
+       public static void setField (T t) { field = t; }
+       public static T getField () { return field; }
+}
+
+public class main {
+       static int i1;
+       static int i2;
+
+       public static void otherThread () {
+               Gen<IntClass>.setField (new IntClass (2));
+               i2 = Gen<IntClass>.getField ().get ();
+       }
+
+       public static int Main () {
+               Gen<IntClass>.setField (new IntClass (1));
+
+               Thread thread = new Thread (main.otherThread);
+               thread.Start ();
+               thread.Join ();
+
+               i1 = Gen<IntClass>.getField ().get ();
+
+               if (i1 != 1 || i2 != 2)
+                       return 1;
+               return 0;
+       }
+}