Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
m---------external/api-snapshot0
-rw-r--r--mcs/class/corlib/System/WeakAttribute.cs12
-rw-r--r--mcs/class/corlib/corlib.dll.sources1
-rw-r--r--mono/metadata/boehm-gc.c7
-rw-r--r--mono/metadata/class-accessors.c31
-rw-r--r--mono/metadata/class-internals.h8
-rw-r--r--mono/metadata/class.c26
-rw-r--r--mono/metadata/custom-attrs-internals.h6
-rw-r--r--mono/metadata/custom-attrs.c178
-rw-r--r--mono/metadata/gc-internals.h2
-rw-r--r--mono/metadata/image.c1
-rw-r--r--mono/metadata/metadata-internals.h4
-rw-r--r--mono/metadata/object-internals.h1
-rw-r--r--mono/metadata/object.c62
-rw-r--r--mono/metadata/sgen-mono.c16
-rw-r--r--mono/mini/aot-compiler.c32
-rw-r--r--mono/mini/aot-runtime.c18
-rw-r--r--mono/mini/aot-runtime.h7
-rw-r--r--mono/mini/mini-runtime.c1
-rw-r--r--mono/sgen/gc-internal-agnostic.h2
-rw-r--r--mono/sgen/sgen-client.h5
-rw-r--r--mono/sgen/sgen-gc.c15
-rw-r--r--mono/sgen/sgen-gc.h19
-rw-r--r--mono/sgen/sgen-gchandles.c53
-rwxr-xr-xmono/tests/Makefile.am12
-rw-r--r--mono/tests/weak-fields.cs71
-rw-r--r--mono/tests/weakattribute.cs10
27 files changed, 569 insertions, 31 deletions
diff --git a/external/api-snapshot b/external/api-snapshot
-Subproject be0a9a9bc303b5c5b225c49b2502582589573d8
+Subproject 8482d12f298a01284c2d54921ae21b4487997a5
diff --git a/mcs/class/corlib/System/WeakAttribute.cs b/mcs/class/corlib/System/WeakAttribute.cs
new file mode 100644
index 00000000000..72de431d172
--- /dev/null
+++ b/mcs/class/corlib/System/WeakAttribute.cs
@@ -0,0 +1,12 @@
+using System;
+
+#if MOBILE
+namespace System {
+
+[AttributeUsage(AttributeTargets.Field)]
+public sealed class WeakAttribute : Attribute
+{
+}
+
+}
+#endif
diff --git a/mcs/class/corlib/corlib.dll.sources b/mcs/class/corlib/corlib.dll.sources
index 6bb7532991a..fa940530add 100644
--- a/mcs/class/corlib/corlib.dll.sources
+++ b/mcs/class/corlib/corlib.dll.sources
@@ -151,6 +151,7 @@ System/UIntPtr.cs
System/ValueType.cs
System/Variant.cs
System/Void.cs
+System/WeakAttribute.cs
System/WeakReference.cs
System/WeakReference_T.cs
System/WindowsConsoleDriver.cs
diff --git a/mono/metadata/boehm-gc.c b/mono/metadata/boehm-gc.c
index 2bc3052ae69..0f3832ce0e1 100644
--- a/mono/metadata/boehm-gc.c
+++ b/mono/metadata/boehm-gc.c
@@ -2003,6 +2003,13 @@ mono_gchandle_free_domain (MonoDomain *domain)
}
}
+
+void
+mono_gc_register_obj_with_weak_fields (void *obj)
+{
+ g_error ("Weak fields not supported by boehm gc");
+}
+
#else
MONO_EMPTY_SOURCE_FILE (boehm_gc);
diff --git a/mono/metadata/class-accessors.c b/mono/metadata/class-accessors.c
index cb13369b44f..189cfbba3fb 100644
--- a/mono/metadata/class-accessors.c
+++ b/mono/metadata/class-accessors.c
@@ -16,7 +16,8 @@ typedef enum {
PROP_PROPERTY_INFO = 5, /* MonoClassPropertyInfo* */
PROP_EVENT_INFO = 6, /* MonoClassEventInfo* */
PROP_FIELD_DEF_VALUES = 7, /* MonoFieldDefaultValue* */
- PROP_DECLSEC_FLAGS = 8 /* guint32 */
+ PROP_DECLSEC_FLAGS = 8, /* guint32 */
+ PROP_WEAK_BITMAP = 9
} InfrequentDataKind;
/* Accessors based on class kind*/
@@ -390,3 +391,31 @@ mono_class_gtd_get_canonical_inst (MonoClass *klass)
g_assert (mono_class_is_gtd (klass));
return &((MonoClassGtd*)klass)->canonical_inst;
}
+
+typedef struct {
+ MonoPropertyBagItem head;
+
+ int nbits;
+ gsize *bits;
+} WeakBitmapData;
+
+void
+mono_class_set_weak_bitmap (MonoClass *klass, int nbits, gsize *bits)
+{
+ WeakBitmapData *info = mono_class_alloc (klass, sizeof (WeakBitmapData));
+ info->nbits = nbits;
+ info->bits = bits;
+
+ info->head.tag = PROP_WEAK_BITMAP;
+ mono_property_bag_add (&klass->infrequent_data, info);
+}
+
+gsize*
+mono_class_get_weak_bitmap (MonoClass *klass, int *nbits)
+{
+ WeakBitmapData *prop = mono_property_bag_get (&klass->infrequent_data, PROP_WEAK_BITMAP);
+
+ g_assert (prop);
+ *nbits = prop->nbits;
+ return prop->bits;
+}
diff --git a/mono/metadata/class-internals.h b/mono/metadata/class-internals.h
index a789b208965..b5769cd1661 100644
--- a/mono/metadata/class-internals.h
+++ b/mono/metadata/class-internals.h
@@ -328,6 +328,7 @@ struct _MonoClass {
guint has_finalize_inited : 1; /* has_finalize is initialized */
guint fields_inited : 1; /* setup_fields () has finished */
guint has_failure : 1; /* See mono_class_get_exception_data () for a MonoErrorBoxed with the details */
+ guint has_weak_fields : 1; /* class has weak reference fields */
MonoClass *parent;
MonoClass *nested_in;
@@ -700,6 +701,7 @@ typedef struct MonoCachedClassInfo {
guint has_static_refs : 1;
guint no_special_static_fields : 1;
guint is_generic_container : 1;
+ guint has_weak_fields : 1;
guint32 cctor_token;
MonoImage *finalize_image;
guint32 finalize_token;
@@ -1529,6 +1531,12 @@ mono_class_set_declsec_flags (MonoClass *klass, guint32 value);
void
mono_class_set_is_com_object (MonoClass *klass);
+void
+mono_class_set_weak_bitmap (MonoClass *klass, int nbits, gsize *bits);
+
+gsize*
+mono_class_get_weak_bitmap (MonoClass *klass, int *nbits);
+
/*Now that everything has been defined, let's include the inline functions */
#include <mono/metadata/class-inlines.h>
diff --git a/mono/metadata/class.c b/mono/metadata/class.c
index ce2e1532faf..4c39099b40e 100644
--- a/mono/metadata/class.c
+++ b/mono/metadata/class.c
@@ -40,6 +40,7 @@
#include <mono/metadata/gc-internals.h>
#include <mono/metadata/verify-internals.h>
#include <mono/metadata/mono-debug.h>
+#include <mono/metadata/custom-attrs-internals.h>
#include <mono/utils/mono-counters.h>
#include <mono/utils/mono-string.h>
#include <mono/utils/mono-error-internals.h>
@@ -1666,6 +1667,7 @@ init_sizes_with_info (MonoClass *klass, MonoCachedClassInfo *cached_info)
klass->has_references = cached_info->has_references;
klass->has_static_refs = cached_info->has_static_refs;
klass->no_special_static_fields = cached_info->no_special_static_fields;
+ klass->has_weak_fields = cached_info->has_weak_fields;
mono_loader_unlock ();
}
else {
@@ -2204,18 +2206,40 @@ mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_
mono_class_set_type_load_failure (klass, "Value type instance size (%d) cannot be zero, negative, or bigger than 1Mb", klass->instance_size);
}
+ // Weak field support
+ //
+ // FIXME:
+ // - generic instances
+ // - Disallow on structs/static fields/nonref fields
+ gboolean has_weak_fields = FALSE;
+
+ if (mono_class_has_static_metadata (klass)) {
+ for (MonoClass *p = klass; p != NULL; p = p->parent) {
+ gpointer iter = NULL;
+ guint32 first_field_idx = mono_class_get_first_field_idx (p);
+
+ while ((field = mono_class_get_fields (p, &iter))) {
+ guint32 field_idx = first_field_idx + (field - p->fields);
+ if (MONO_TYPE_IS_REFERENCE (field->type) && mono_assembly_is_weak_field (p->image, field_idx + 1)) {
+ has_weak_fields = TRUE;
+ mono_trace_message (MONO_TRACE_TYPE, "Field %s:%s at offset %x is weak.", field->parent->name, field->name, field->offset);
+ }
+ }
+ }
+ }
+
/* Publish the data */
mono_loader_lock ();
if (!klass->rank)
klass->sizes.class_size = class_size;
klass->has_static_refs = has_static_refs;
+ klass->has_weak_fields = has_weak_fields;
for (i = 0; i < top; ++i) {
field = &klass->fields [i];
if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
field->offset = field_offsets [i];
}
-
mono_memory_barrier ();
klass->fields_inited = 1;
mono_loader_unlock ();
diff --git a/mono/metadata/custom-attrs-internals.h b/mono/metadata/custom-attrs-internals.h
index 1f9150c33e3..a848c0b0e37 100644
--- a/mono/metadata/custom-attrs-internals.h
+++ b/mono/metadata/custom-attrs-internals.h
@@ -16,4 +16,10 @@ typedef gboolean (*MonoAssemblyMetadataCustomAttrIterFunc) (MonoImage *image, gu
void
mono_assembly_metadata_foreach_custom_attr (MonoAssembly *assembly, MonoAssemblyMetadataCustomAttrIterFunc func, gpointer user_data);
+gboolean
+mono_assembly_is_weak_field (MonoImage *image, guint32 field_idx);
+
+void
+mono_assembly_init_weak_fields (MonoImage *image);
+
#endif /* __MONO_METADATA_REFLECTION_CUSTOM_ATTRS_INTERNALS_H__ */
diff --git a/mono/metadata/custom-attrs.c b/mono/metadata/custom-attrs.c
index 7c160a84867..e58f0fedfe2 100644
--- a/mono/metadata/custom-attrs.c
+++ b/mono/metadata/custom-attrs.c
@@ -2155,3 +2155,181 @@ mono_assembly_metadata_foreach_custom_attr (MonoAssembly *assembly, MonoAssembly
stop_iterating = func (image, assembly_token, nspace, name, mtoken, user_data);
}
}
+
+static void
+init_weak_fields_inner (MonoImage *image, GHashTable *indexes)
+{
+ MonoTableInfo *tdef;
+ MonoError error;
+ MonoClass *klass = NULL;
+ guint32 memberref_index = -1;
+ int first_method_idx = -1;
+ int method_count = -1;
+
+ if (image == mono_get_corlib ()) {
+ /* Typedef */
+ klass = mono_class_from_name_checked (image, "System", "WeakAttribute", &error);
+ if (!is_ok (&error)) {
+ mono_error_cleanup (&error);
+ return;
+ }
+ if (!klass)
+ return;
+ first_method_idx = mono_class_get_first_method_idx (klass);
+ method_count = mono_class_get_method_count (klass);
+
+ tdef = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
+ guint32 parent, field_idx, col, mtoken, idx;
+ for (int i = 0; i < tdef->rows; ++i) {
+ parent = mono_metadata_decode_row_col (tdef, i, MONO_CUSTOM_ATTR_PARENT);
+ if ((parent & MONO_CUSTOM_ATTR_MASK) != MONO_CUSTOM_ATTR_FIELDDEF)
+ continue;
+
+ col = mono_metadata_decode_row_col (tdef, i, MONO_CUSTOM_ATTR_TYPE);
+ mtoken = col >> MONO_CUSTOM_ATTR_TYPE_BITS;
+ /* 1 based index */
+ idx = mtoken - 1;
+ if ((col & MONO_CUSTOM_ATTR_TYPE_MASK) == MONO_CUSTOM_ATTR_TYPE_METHODDEF) {
+ field_idx = parent >> MONO_CUSTOM_ATTR_BITS;
+ if (idx >= first_method_idx && idx < first_method_idx + method_count)
+ g_hash_table_insert (indexes, GUINT_TO_POINTER (field_idx), GUINT_TO_POINTER (1));
+ }
+ }
+ } else {
+ /* Memberref pointing to a typeref */
+ tdef = &image->tables [MONO_TABLE_MEMBERREF];
+
+ /* Check whenever the assembly references the WeakAttribute type */
+ gboolean found = FALSE;
+ tdef = &image->tables [MONO_TABLE_TYPEREF];
+ for (int i = 0; i < tdef->rows; ++i) {
+ guint32 string_offset = mono_metadata_decode_row_col (tdef, i, MONO_TYPEREF_NAME);
+ const char *name = mono_metadata_string_heap (image, string_offset);
+ if (!strcmp (name, "WeakAttribute")) {
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (!found)
+ return;
+
+ /* Find the memberref pointing to a typeref */
+ tdef = &image->tables [MONO_TABLE_MEMBERREF];
+ for (int i = 0; i < tdef->rows; ++i) {
+ guint32 cols [MONO_MEMBERREF_SIZE];
+ const char *sig;
+
+ mono_metadata_decode_row (tdef, i, cols, MONO_MEMBERREF_SIZE);
+ sig = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
+ mono_metadata_decode_blob_size (sig, &sig);
+
+ guint32 nindex = cols [MONO_MEMBERREF_CLASS] >> MONO_MEMBERREF_PARENT_BITS;
+ guint32 class_index = cols [MONO_MEMBERREF_CLASS] & MONO_MEMBERREF_PARENT_MASK;
+ const char *fname = mono_metadata_string_heap (image, cols [MONO_MEMBERREF_NAME]);
+
+ if (!strcmp (fname, ".ctor") && class_index == MONO_MEMBERREF_PARENT_TYPEREF) {
+ MonoTableInfo *typeref_table = &image->tables [MONO_TABLE_TYPEREF];
+ guint32 cols [MONO_TYPEREF_SIZE];
+
+ mono_metadata_decode_row (typeref_table, nindex - 1, cols, MONO_TYPEREF_SIZE);
+
+ const char *name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
+ const char *nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
+
+ if (!strcmp (nspace, "System") && !strcmp (name, "WeakAttribute")) {
+ MonoClass *klass = mono_class_from_typeref (image, MONO_TOKEN_TYPE_REF | nindex);
+ g_assert (!strcmp (klass->name, "WeakAttribute"));
+ /* Allow a testing dll as well since some profiles don't have WeakAttribute */
+ if (klass && (klass->image == mono_get_corlib () || strstr (klass->image->name, "Mono.Runtime.Testing"))) {
+ /* Sanity check that it only has 1 ctor */
+ gpointer iter = NULL;
+ int count = 0;
+ MonoMethod *method;
+ while ((method = mono_class_get_methods (klass, &iter))) {
+ if (!strcmp (method->name, ".ctor"))
+ count ++;
+ }
+ count ++;
+ memberref_index = i;
+ break;
+ }
+ }
+ }
+ }
+ if (memberref_index == -1)
+ return;
+
+ tdef = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
+ guint32 parent, field_idx, col, mtoken, idx;
+ for (int i = 0; i < tdef->rows; ++i) {
+ parent = mono_metadata_decode_row_col (tdef, i, MONO_CUSTOM_ATTR_PARENT);
+ if ((parent & MONO_CUSTOM_ATTR_MASK) != MONO_CUSTOM_ATTR_FIELDDEF)
+ continue;
+
+ col = mono_metadata_decode_row_col (tdef, i, MONO_CUSTOM_ATTR_TYPE);
+ mtoken = col >> MONO_CUSTOM_ATTR_TYPE_BITS;
+ /* 1 based index */
+ idx = mtoken - 1;
+ field_idx = parent >> MONO_CUSTOM_ATTR_BITS;
+ if ((col & MONO_CUSTOM_ATTR_TYPE_MASK) == MONO_CUSTOM_ATTR_TYPE_MEMBERREF) {
+ if (idx == memberref_index)
+ g_hash_table_insert (indexes, GUINT_TO_POINTER (field_idx), GUINT_TO_POINTER (1));
+ }
+ }
+ }
+}
+
+/*
+ * mono_assembly_init_weak_fields:
+ *
+ * Initialize the image->weak_field_indexes hash.
+ */
+void
+mono_assembly_init_weak_fields (MonoImage *image)
+{
+ if (image->weak_fields_inited)
+ return;
+
+ GHashTable *indexes = NULL;
+
+ if (mono_get_runtime_callbacks ()->get_weak_field_indexes)
+ indexes = mono_get_runtime_callbacks ()->get_weak_field_indexes (image);
+ if (!indexes) {
+ indexes = g_hash_table_new (NULL, NULL);
+
+ /*
+ * To avoid lookups for every field, we scan the customattr table for entries whose
+ * parent is a field and whose type is WeakAttribute.
+ */
+ init_weak_fields_inner (image, indexes);
+ }
+
+ mono_image_lock (image);
+ if (!image->weak_fields_inited) {
+ image->weak_field_indexes = indexes;
+ mono_memory_barrier ();
+ image->weak_fields_inited = TRUE;
+ } else {
+ g_hash_table_destroy (indexes);
+ }
+ mono_image_unlock (image);
+}
+
+/*
+ * mono_assembly_is_weak_field:
+ *
+ * Return whenever the FIELD table entry with the 1-based index FIELD_IDX has
+ * a [Weak] attribute.
+ */
+gboolean
+mono_assembly_is_weak_field (MonoImage *image, guint32 field_idx)
+{
+ if (image->dynamic)
+ return FALSE;
+
+ mono_assembly_init_weak_fields (image);
+
+ /* The hash is not mutated, no need to lock */
+ return g_hash_table_lookup (image->weak_field_indexes, GINT_TO_POINTER (field_idx)) != NULL;
+}
diff --git a/mono/metadata/gc-internals.h b/mono/metadata/gc-internals.h
index d87746dee36..2a19c304945 100644
--- a/mono/metadata/gc-internals.h
+++ b/mono/metadata/gc-internals.h
@@ -138,6 +138,8 @@ void* mono_gc_alloc_string (MonoVTable *vtable, size_t size, gint32 len);
void* mono_gc_alloc_mature (MonoVTable *vtable, size_t size);
MonoGCDescriptor mono_gc_make_descr_for_string (gsize *bitmap, int numbits);
+void mono_gc_register_obj_with_weak_fields (void *obj);
+
void mono_gc_register_for_finalization (MonoObject *obj, void *user_data);
void mono_gc_add_memory_pressure (gint64 value);
MONO_API int mono_gc_register_root (char *start, size_t size, MonoGCDescriptor descr, MonoGCRootSource source, const char *msg);
diff --git a/mono/metadata/image.c b/mono/metadata/image.c
index 31f5d237c60..548e52715e1 100644
--- a/mono/metadata/image.c
+++ b/mono/metadata/image.c
@@ -2084,6 +2084,7 @@ mono_image_close_except_pools (MonoImage *image)
free_hash (image->pinvoke_scope_filenames);
free_hash (image->native_func_wrapper_cache);
mono_conc_hashtable_destroy (image->typespec_cache);
+ free_hash (image->weak_field_indexes);
mono_wrapper_caches_free (&image->wrapper_caches);
diff --git a/mono/metadata/metadata-internals.h b/mono/metadata/metadata-internals.h
index 2b2e414f01e..e849706e19e 100644
--- a/mono/metadata/metadata-internals.h
+++ b/mono/metadata/metadata-internals.h
@@ -416,6 +416,10 @@ struct _MonoImage {
MonoGenericContainer *anonymous_generic_class_container;
MonoGenericContainer *anonymous_generic_method_container;
+ gboolean weak_fields_inited;
+ /* Contains 1 based indexes */
+ GHashTable *weak_field_indexes;
+
/*
* No other runtime locks must be taken while holding this lock.
* It's meant to be used only to mutate and query structures part of this image.
diff --git a/mono/metadata/object-internals.h b/mono/metadata/object-internals.h
index f5c6ef3ccd1..cb42761d6c2 100644
--- a/mono/metadata/object-internals.h
+++ b/mono/metadata/object-internals.h
@@ -630,6 +630,7 @@ typedef struct {
gpointer (*create_remoting_trampoline) (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error);
gpointer (*create_delegate_trampoline) (MonoDomain *domain, MonoClass *klass);
gpointer (*interp_get_remoting_invoke) (gpointer imethod, MonoError *error);
+ GHashTable *(*get_weak_field_indexes) (MonoImage *image);
} MonoRuntimeCallbacks;
typedef gboolean (*MonoInternalStackWalk) (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data);
diff --git a/mono/metadata/object.c b/mono/metadata/object.c
index e23a3f9b6e6..5378f08afc0 100644
--- a/mono/metadata/object.c
+++ b/mono/metadata/object.c
@@ -40,6 +40,7 @@
#include <mono/metadata/verify-internals.h>
#include <mono/metadata/reflection-internals.h>
#include <mono/metadata/w32event.h>
+#include <mono/metadata/custom-attrs-internals.h>
#include <mono/utils/strenc.h>
#include <mono/utils/mono-counters.h>
#include <mono/utils/mono-error-internals.h>
@@ -47,6 +48,7 @@
#include <mono/utils/checked-build.h>
#include <mono/utils/mono-threads.h>
#include <mono/utils/mono-threads-coop.h>
+#include <mono/utils/mono-logger-internals.h>
#include "cominterop.h"
#include <mono/utils/w32api.h>
#include <mono/utils/unlocked.h>
@@ -1001,7 +1003,14 @@ ves_icall_string_alloc (int length)
return str;
}
+#define BITMAP_EL_SIZE (sizeof (gsize) * 8)
+
/* LOCKING: Acquires the loader lock */
+/*
+ * Sets the following fields in KLASS:
+ * - gc_desc
+ * - gc_descr_inited
+ */
void
mono_class_compute_gc_descriptor (MonoClass *klass)
{
@@ -1034,24 +1043,59 @@ mono_class_compute_gc_descriptor (MonoClass *klass)
gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, bitmap, mono_array_element_size (klass) / sizeof (gpointer), mono_array_element_size (klass));
/*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
class->name_space, class->name);*/
- if (bitmap != default_bitmap)
- g_free (bitmap);
}
} else {
/*static int count = 0;
if (count++ > 58)
return;*/
bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
- gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
/*
if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
*/
/*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
- if (bitmap != default_bitmap)
- g_free (bitmap);
+
+ if (klass->has_weak_fields) {
+ gsize *weak_bitmap = NULL;
+ int weak_bitmap_nbits = 0;
+
+ weak_bitmap = (gsize *)mono_class_alloc0 (klass, klass->instance_size / sizeof (gsize));
+ if (mono_class_has_static_metadata (klass)) {
+ for (MonoClass *p = klass; p != NULL; p = p->parent) {
+ gpointer iter = NULL;
+ guint32 first_field_idx = mono_class_get_first_field_idx (p);
+ MonoClassField *field;
+
+ while ((field = mono_class_get_fields (p, &iter))) {
+ guint32 field_idx = first_field_idx + (field - p->fields);
+ if (MONO_TYPE_IS_REFERENCE (field->type) && mono_assembly_is_weak_field (p->image, field_idx + 1)) {
+ int pos = field->offset / sizeof (gpointer);
+ if (pos + 1 > weak_bitmap_nbits)
+ weak_bitmap_nbits = pos + 1;
+ weak_bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
+ }
+ }
+ }
+ }
+
+ for (int pos = 0; pos < weak_bitmap_nbits; ++pos) {
+ if (weak_bitmap [pos / BITMAP_EL_SIZE] & ((gsize)1) << (pos % BITMAP_EL_SIZE)) {
+ /* Clear the normal bitmap so these refs don't keep an object alive */
+ bitmap [pos / BITMAP_EL_SIZE] &= ~((gsize)1) << (pos % BITMAP_EL_SIZE);
+ }
+ }
+
+ mono_loader_lock ();
+ mono_class_set_weak_bitmap (klass, weak_bitmap_nbits, weak_bitmap);
+ mono_loader_unlock ();
+ }
+
+ gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
}
+ if (bitmap != default_bitmap)
+ g_free (bitmap);
+
/* Publish the data */
mono_loader_lock ();
klass->gc_descr = gc_descr;
@@ -5435,8 +5479,12 @@ mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
if (G_UNLIKELY (!o))
mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
- else if (G_UNLIKELY (vtable->klass->has_finalize))
- mono_object_register_finalizer (o);
+ else if (G_UNLIKELY (vtable->klass->has_finalize || vtable->klass->has_weak_fields)) {
+ if (vtable->klass->has_finalize)
+ mono_object_register_finalizer (o);
+ if (vtable->klass->has_weak_fields)
+ mono_gc_register_obj_with_weak_fields (o);
+ }
return o;
}
diff --git a/mono/metadata/sgen-mono.c b/mono/metadata/sgen-mono.c
index e16f2c869d2..6ad19b1d76a 100644
--- a/mono/metadata/sgen-mono.c
+++ b/mono/metadata/sgen-mono.c
@@ -1501,7 +1501,7 @@ mono_gc_get_managed_allocator (MonoClass *klass, gboolean for_box, gboolean know
return NULL;
if (known_instance_size && ALIGN_TO (klass->instance_size, SGEN_ALLOC_ALIGN) >= SGEN_MAX_SMALL_OBJ_SIZE)
return NULL;
- if (mono_class_has_finalizer (klass) || mono_class_is_marshalbyref (klass))
+ if (mono_class_has_finalizer (klass) || mono_class_is_marshalbyref (klass) || klass->has_weak_fields)
return NULL;
if (klass->rank)
return NULL;
@@ -2643,6 +2643,12 @@ mono_gc_make_descr_for_string (gsize *bitmap, int numbits)
return SGEN_DESC_STRING;
}
+void
+mono_gc_register_obj_with_weak_fields (void *obj)
+{
+ return sgen_register_obj_with_weak_fields (obj);
+}
+
void*
mono_gc_get_nursery (int *shift_bits, size_t *size)
{
@@ -3095,4 +3101,12 @@ mono_gc_is_null (void)
return FALSE;
}
+gsize *
+sgen_client_get_weak_bitmap (MonoVTable *vt, int *nbits)
+{
+ MonoClass *klass = vt->klass;
+
+ return mono_class_get_weak_bitmap (klass, nbits);
+}
+
#endif
diff --git a/mono/mini/aot-compiler.c b/mono/mini/aot-compiler.c
index 7d16506e7a5..cd6627f9a22 100644
--- a/mono/mini/aot-compiler.c
+++ b/mono/mini/aot-compiler.c
@@ -49,6 +49,7 @@
#include <mono/metadata/mempool-internals.h>
#include <mono/metadata/mono-endian.h>
#include <mono/metadata/threads-types.h>
+#include <mono/metadata/custom-attrs-internals.h>
#include <mono/utils/mono-logger-internals.h>
#include <mono/utils/mono-compiler.h>
#include <mono/utils/mono-time.h>
@@ -6543,7 +6544,7 @@ emit_klass_info (MonoAotCompile *acfg, guint32 token)
} else {
gboolean has_nested = mono_class_get_nested_classes_property (klass) != NULL;
encode_value (klass->vtable_size, p, &p);
- encode_value ((mono_class_is_gtd (klass) ? (1 << 8) : 0) | (no_special_static << 7) | (klass->has_static_refs << 6) | (klass->has_references << 5) | ((klass->blittable << 4) | (has_nested ? 1 : 0) << 3) | (klass->has_cctor << 2) | (klass->has_finalize << 1) | klass->ghcimpl, p, &p);
+ encode_value ((klass->has_weak_fields << 9) | (mono_class_is_gtd (klass) ? (1 << 8) : 0) | (no_special_static << 7) | (klass->has_static_refs << 6) | (klass->has_references << 5) | ((klass->blittable << 4) | (has_nested ? 1 : 0) << 3) | (klass->has_cctor << 2) | (klass->has_finalize << 1) | klass->ghcimpl, p, &p);
if (klass->has_cctor)
encode_method_ref (acfg, mono_class_get_cctor (klass), p, &p);
if (klass->has_finalize)
@@ -9889,6 +9890,32 @@ emit_image_table (MonoAotCompile *acfg)
}
static void
+emit_weak_field_indexes (MonoAotCompile *acfg)
+{
+ char symbol [128];
+ GHashTable *indexes;
+ GHashTableIter iter;
+ gpointer key, value;
+
+ /* Emit a table of weak field indexes, since computing these at runtime is expensive */
+ sprintf (symbol, "weak_field_indexes");
+ emit_section_change (acfg, ".text", 0);
+ emit_alignment_code (acfg, 8);
+ emit_info_symbol (acfg, symbol);
+
+ mono_assembly_init_weak_fields (acfg->image);
+ indexes = acfg->image->weak_field_indexes;
+ g_assert (indexes);
+
+ emit_int32 (acfg, g_hash_table_size (indexes));
+ g_hash_table_iter_init (&iter, indexes);
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ guint32 index = GPOINTER_TO_UINT (key);
+ emit_int32 (acfg, index);
+ }
+}
+
+static void
emit_got_info (MonoAotCompile *acfg, gboolean llvm)
{
int i, first_plt_got_patch = 0, buf_size;
@@ -10286,6 +10313,7 @@ emit_aot_file_info (MonoAotCompile *acfg, MonoAotFileInfo *info)
symbols [sindex ++] = NULL;
symbols [sindex ++] = NULL;
}
+ symbols [sindex ++] = "weak_field_indexes";
g_assert (sindex == MONO_AOT_FILE_INFO_NUM_SYMBOLS);
@@ -12764,6 +12792,8 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options,
emit_image_table (acfg);
+ emit_weak_field_indexes (acfg);
+
emit_got (acfg);
{
diff --git a/mono/mini/aot-runtime.c b/mono/mini/aot-runtime.c
index cd442ed7c1a..baa8be47468 100644
--- a/mono/mini/aot-runtime.c
+++ b/mono/mini/aot-runtime.c
@@ -2424,6 +2424,7 @@ decode_cached_class_info (MonoAotModule *module, MonoCachedClassInfo *info, guin
info->has_static_refs = (flags >> 6) & 0x1;
info->no_special_static_fields = (flags >> 7) & 0x1;
info->is_generic_container = (flags >> 8) & 0x1;
+ info->has_weak_fields = (flags >> 9) & 0x1;
if (info->has_cctor) {
res = decode_method_ref (module, &ref, buf, &buf, &error);
@@ -2626,6 +2627,23 @@ mono_aot_get_class_from_name (MonoImage *image, const char *name_space, const ch
return TRUE;
}
+GHashTable *
+mono_aot_get_weak_field_indexes (MonoImage *image)
+{
+ MonoAotModule *amodule = (MonoAotModule *)image->aot_module;
+
+ if (!amodule)
+ return NULL;
+
+ /* Initialize weak field indexes from the cached copy */
+ guint32 *indexes = amodule->info.weak_field_indexes;
+ int len = indexes [0];
+ GHashTable *indexes_hash = g_hash_table_new (NULL, NULL);
+ for (int i = 0; i < len; ++i)
+ g_hash_table_insert (indexes_hash, GUINT_TO_POINTER (indexes [i + 1]), GUINT_TO_POINTER (1));
+ return indexes_hash;
+}
+
/* Compute the boundaries of the LLVM code for AMODULE. */
static void
compute_llvm_code_range (MonoAotModule *amodule, guint8 **code_start, guint8 **code_end)
diff --git a/mono/mini/aot-runtime.h b/mono/mini/aot-runtime.h
index d593b6df7cb..8be8862058e 100644
--- a/mono/mini/aot-runtime.h
+++ b/mono/mini/aot-runtime.h
@@ -11,7 +11,7 @@
#include "mini.h"
/* Version number of the AOT file format */
-#define MONO_AOT_FILE_VERSION 141
+#define MONO_AOT_FILE_VERSION 142
#define MONO_AOT_TRAMP_PAGE_SIZE 16384
@@ -148,7 +148,9 @@ typedef struct MonoAotFileInfo
gpointer unbox_trampolines_end;
/* Points to a table of unbox trampoline addresses/offsets */
gpointer unbox_trampoline_addresses;
-#define MONO_AOT_FILE_INFO_LAST_SYMBOL unbox_trampoline_addresses
+ /* Points to an array of weak field indexes */
+ gpointer weak_field_indexes;
+#define MONO_AOT_FILE_INFO_LAST_SYMBOL weak_field_indexes
/* Scalars */
/* The index of the first GOT slot used by the PLT */
@@ -234,6 +236,7 @@ void mono_aot_init_llvm_method (gpointer aot_module, guint32 method
void mono_aot_init_gshared_method_this (gpointer aot_module, guint32 method_index, MonoObject *this_ins);
void mono_aot_init_gshared_method_mrgctx (gpointer aot_module, guint32 method_index, MonoMethodRuntimeGenericContext *rgctx);
void mono_aot_init_gshared_method_vtable (gpointer aot_module, guint32 method_index, MonoVTable *vtable);
+GHashTable *mono_aot_get_weak_field_indexes (MonoImage *image);
/* This is an exported function */
MONO_API void mono_aot_register_module (gpointer *aot_info);
diff --git a/mono/mini/mini-runtime.c b/mono/mini/mini-runtime.c
index 9a22af5d4a1..6a27b69fc12 100644
--- a/mono/mini/mini-runtime.c
+++ b/mono/mini/mini-runtime.c
@@ -3879,6 +3879,7 @@ mini_init (const char *filename, const char *runtime_version)
if (mono_use_interpreter)
callbacks.interp_get_remoting_invoke = mini_get_interp_callbacks ()->get_remoting_invoke;
#endif
+ callbacks.get_weak_field_indexes = mono_aot_get_weak_field_indexes;
mono_install_callbacks (&callbacks);
diff --git a/mono/sgen/gc-internal-agnostic.h b/mono/sgen/gc-internal-agnostic.h
index f1c887b5754..1bc27c711c6 100644
--- a/mono/sgen/gc-internal-agnostic.h
+++ b/mono/sgen/gc-internal-agnostic.h
@@ -45,12 +45,14 @@
#define MONO_GC_HANDLE_IS_OBJECT_POINTER(slot) (MONO_GC_HANDLE_TAG (slot) == (MONO_GC_HANDLE_OCCUPIED_MASK | MONO_GC_HANDLE_VALID_MASK))
#define MONO_GC_HANDLE_IS_METADATA_POINTER(slot) (MONO_GC_HANDLE_TAG (slot) == MONO_GC_HANDLE_OCCUPIED_MASK)
+/* These should match System.Runtime.InteropServices.GCHandleType */
typedef enum {
HANDLE_TYPE_MIN = 0,
HANDLE_WEAK = HANDLE_TYPE_MIN,
HANDLE_WEAK_TRACK,
HANDLE_NORMAL,
HANDLE_PINNED,
+ HANDLE_WEAK_FIELDS,
HANDLE_TYPE_MAX
} GCHandleType;
diff --git a/mono/sgen/sgen-client.h b/mono/sgen/sgen-client.h
index 4137cacc3c2..a0045184bd1 100644
--- a/mono/sgen/sgen-client.h
+++ b/mono/sgen/sgen-client.h
@@ -224,6 +224,11 @@ gpointer sgen_client_get_provenance (void);
void sgen_client_describe_invalid_pointer (GCObject *ptr);
/*
+ * Return the weak bitmap for a class
+ */
+gsize *sgen_client_get_weak_bitmap (GCVTable vt, int *nbits);
+
+/*
* These client binary protocol functions are called from the respective binary protocol
* functions. No action is necessary. We suggest implementing them as inline functions in
* the client header file so that no overhead is incurred if they don't actually do
diff --git a/mono/sgen/sgen-gc.c b/mono/sgen/sgen-gc.c
index fb3be3507b1..0cfcf2904df 100644
--- a/mono/sgen/sgen-gc.c
+++ b/mono/sgen/sgen-gc.c
@@ -2657,21 +2657,6 @@ report_internal_mem_usage (void)
*/
/*
- * If the object has been forwarded it means it's still referenced from a root.
- * If it is pinned it's still alive as well.
- * A LOS object is only alive if we have pinned it.
- * Return TRUE if @obj is ready to be finalized.
- */
-static inline gboolean
-sgen_is_object_alive (GCObject *object)
-{
- if (ptr_in_nursery (object))
- return sgen_nursery_is_object_alive (object);
-
- return sgen_major_is_object_alive (object);
-}
-
-/*
* This function returns true if @object is either alive and belongs to the
* current collection - major collections are full heap, so old gen objects
* are never alive during a minor collection.
diff --git a/mono/sgen/sgen-gc.h b/mono/sgen/sgen-gc.h
index 8cdec588b66..4850b334231 100644
--- a/mono/sgen/sgen-gc.h
+++ b/mono/sgen/sgen-gc.h
@@ -794,6 +794,8 @@ gboolean sgen_object_is_live (GCObject *obj);
void sgen_init_fin_weak_hash (void);
+void sgen_register_obj_with_weak_fields (GCObject *obj);
+
/* FIXME: move the toggleref stuff out of here */
void sgen_mark_togglerefs (char *start, char *end, ScanCopyContext ctx);
void sgen_clear_togglerefs (char *start, char *end, ScanCopyContext ctx);
@@ -962,6 +964,23 @@ sgen_major_is_object_alive (GCObject *object)
return major_collector.is_object_live (object);
}
+
+/*
+ * If the object has been forwarded it means it's still referenced from a root.
+ * If it is pinned it's still alive as well.
+ * A LOS object is only alive if we have pinned it.
+ * Return TRUE if @obj is ready to be finalized.
+ */
+static inline gboolean
+sgen_is_object_alive (GCObject *object)
+{
+ if (sgen_ptr_in_nursery (object))
+ return sgen_nursery_is_object_alive (object);
+
+ return sgen_major_is_object_alive (object);
+}
+
+
/*
* This function returns true if @object is either alive or it belongs to the old gen
* and we're currently doing a minor collection.
diff --git a/mono/sgen/sgen-gchandles.c b/mono/sgen/sgen-gchandles.c
index 4a140e53668..7be066fb248 100644
--- a/mono/sgen/sgen-gchandles.c
+++ b/mono/sgen/sgen-gchandles.c
@@ -103,7 +103,8 @@ static HandleData gc_handles [] = {
{ SGEN_ARRAY_LIST_INIT (NULL, is_slot_set, try_occupy_slot, -1), (HANDLE_WEAK) },
{ SGEN_ARRAY_LIST_INIT (NULL, is_slot_set, try_occupy_slot, -1), (HANDLE_WEAK_TRACK) },
{ SGEN_ARRAY_LIST_INIT (NULL, is_slot_set, try_occupy_slot, -1), (HANDLE_NORMAL) },
- { SGEN_ARRAY_LIST_INIT (bucket_alloc_callback, is_slot_set, try_occupy_slot, -1), (HANDLE_PINNED) }
+ { SGEN_ARRAY_LIST_INIT (bucket_alloc_callback, is_slot_set, try_occupy_slot, -1), (HANDLE_PINNED) },
+ { SGEN_ARRAY_LIST_INIT (NULL, is_slot_set, try_occupy_slot, -1), (HANDLE_WEAK_FIELDS) },
};
static HandleData *
@@ -394,11 +395,52 @@ null_link_if_necessary (gpointer hidden, GCHandleType handle_type, int max_gener
return MONO_GC_HANDLE_OBJECT_POINTER (copy, is_weak);
}
+static gpointer
+scan_for_weak (gpointer hidden, GCHandleType handle_type, int max_generation, gpointer user)
+{
+ const gboolean is_weak = GC_HANDLE_TYPE_IS_WEAK (handle_type);
+ ScanCopyContext *ctx = (ScanCopyContext *)user;
+
+ if (!MONO_GC_HANDLE_VALID (hidden))
+ return hidden;
+
+ GCObject *obj = (GCObject *)MONO_GC_REVEAL_POINTER (hidden, is_weak);
+
+ /* If the object is dead we free the gc handle */
+ if (!sgen_is_object_alive (obj))
+ return NULL;
+
+ /* Relocate it */
+ ctx->ops->copy_or_mark_object (&obj, ctx->queue);
+
+ int nbits;
+ gsize *weak_bitmap = sgen_client_get_weak_bitmap (SGEN_LOAD_VTABLE (obj), &nbits);
+ for (int i = 0; i < nbits; ++i) {
+ if (weak_bitmap [i / (sizeof (gsize) * 8)] & ((gsize)1 << (i % (sizeof (gsize) * 8)))) {
+ GCObject **addr = (GCObject **)((char*)obj + (i * sizeof (gpointer)));
+ GCObject *field = *addr;
+
+ /* if the object in the weak field is alive, we relocate it */
+ if (field && sgen_is_object_alive (field))
+ ctx->ops->copy_or_mark_object (addr, ctx->queue);
+ else
+ *addr = NULL;
+ }
+ }
+
+ /* Update link if object was moved. */
+ return MONO_GC_HANDLE_OBJECT_POINTER (obj, is_weak);
+}
+
/* LOCKING: requires that the GC lock is held */
void
sgen_null_link_in_range (int generation, ScanCopyContext ctx, gboolean track)
{
sgen_gchandle_iterate (track ? HANDLE_WEAK_TRACK : HANDLE_WEAK, generation, null_link_if_necessary, &ctx);
+
+ //we're always called for gen zero. !track means short ref
+ if (generation == 0 && !track)
+ sgen_gchandle_iterate (HANDLE_WEAK_FIELDS, generation, scan_for_weak, &ctx);
}
typedef struct {
@@ -436,6 +478,15 @@ sgen_null_links_if (SgenObjectPredicateFunc predicate, void *data, int generatio
}
void
+sgen_register_obj_with_weak_fields (GCObject *obj)
+{
+ //
+ // We use a gc handle to be able to do some processing for these objects at every gc
+ //
+ alloc_handle (gc_handles_for_type (HANDLE_WEAK_FIELDS), obj, FALSE);
+}
+
+void
sgen_init_gchandles (void)
{
#ifdef HEAVY_STATISTICS
diff --git a/mono/tests/Makefile.am b/mono/tests/Makefile.am
index ff7ac6eb445..15cfe188a8a 100755
--- a/mono/tests/Makefile.am
+++ b/mono/tests/Makefile.am
@@ -528,8 +528,8 @@ TESTS_CS_SRC= \
bug-58782-capture-and-throw.cs \
recursive-struct-arrays.cs \
bug-59281.cs \
- init_array_with_lazy_type.cs
-
+ init_array_with_lazy_type.cs \
+ weak-fields.cs
if AMD64
TESTS_CS_SRC += async-exc-compilation.cs finally_guard.cs finally_block_ending_in_dead_bb.cs
@@ -2071,5 +2071,13 @@ internalsvisibleto-correctcase-2-sign2048.dll internalsvisibleto-wrongcase-2-sig
$(Q) $(MCS_NO_UNSAFE) -out:internalsvisibleto-wrongcase-2-sign2048.dll -target:library -d:WRONG_CASE -d:SIGN2048 internalsvisibleto-library.cs
$(Q) $(MCS_NO_UNSAFE) -out:internalsvisibleto-compilertest-sign2048.exe -warn:0 -r:internalsvisibleto-correctcase-2-sign2048.dll -r:internalsvisibleto-wrongcase-2-sign2048.dll -d:SIGN2048 internalsvisibleto-compilertest.cs
+EXTRA_DIST += weakattribute.cs
+
+# Contains copies of types which don't exist in the desktop profile so tests can use them
+Mono.Runtime.Testing.dll: weakattribute.cs
+ $(MCS) -target:library -out:$@ $<
+
+weak-fields.exe: weak-fields.cs Mono.Runtime.Testing.dll
+ $(MCS) -r:Mono.Runtime.Testing.dll -r:$(CLASS)/System.dll -r:$(CLASS)/System.Xml.dll -r:$(CLASS)/System.Core.dll -r:TestDriver.dll $(TEST_DRIVER_HARD_KILL_FEATURE) -out:$@ $<
CLEANFILES = $(TESTS_CS) $(TESTS_IL) $(TESTS_BENCH) $(TESTS_STRESS) $(TESTSAOT_CS) $(TESTSAOT_IL) $(TESTSAOT_BENCH) $(TESTSAOT_STRESS) *.dll *.stdout *.aotlog *.exe stest.dat LeafAssembly.dll MidAssembly.dll appdomain-marshalbyref-assemblyload2/*.dll
diff --git a/mono/tests/weak-fields.cs b/mono/tests/weak-fields.cs
new file mode 100644
index 00000000000..1bd8337c09b
--- /dev/null
+++ b/mono/tests/weak-fields.cs
@@ -0,0 +1,71 @@
+using System;
+using System.Threading;
+
+[AttributeUsage(AttributeTargets.Field)]
+public sealed class Weak2Attribute : Attribute
+{
+}
+
+public class Finalizable {
+ public int a;
+
+ ~Finalizable () {
+ Console.WriteLine ("Finalized. {0}", a);
+ }
+}
+
+public class OneField {
+ int x;
+}
+public class Tests
+{
+ static Finalizable retain;
+
+ [Weak]
+ public object Obj;
+ [Weak2]
+ public object Obj3;
+ [Weak]
+ public object Obj2;
+ [Weak]
+ public Finalizable Obj4;
+
+ public static int Main (String[] args) {
+ var t = new Tests ();
+ var thread = new Thread (delegate () {
+ t.Obj = new Finalizable ();
+ t.Obj2 = new Finalizable ();
+ t.Obj3 = new Finalizable ();
+ t.Obj4 = retain = new Finalizable ();
+ retain.a = 0x1029458;
+ });
+ thread.Start ();
+ thread.Join ();
+ GC.Collect (0);
+ GC.Collect ();
+ GC.WaitForPendingFinalizers ();
+ GC.WaitForPendingFinalizers ();
+ if (t.Obj != null)
+ return 1;
+ if (t.Obj2 != null)
+ return 2;
+ if (t.Obj3 == null)
+ return 3;
+ //overflow the nursery, make sure we fill it
+ for (int i = 0; i < 1000 * 1000 * 10; ++i)
+ new OneField ();
+
+ if (retain.a != 0x1029458)
+ return 4;
+
+ retain = null;
+ GC.Collect ();
+ GC.WaitForPendingFinalizers ();
+ GC.WaitForPendingFinalizers ();
+ if (t.Obj4 != null)
+ return 5;
+
+ return 0;
+ }
+
+}
diff --git a/mono/tests/weakattribute.cs b/mono/tests/weakattribute.cs
new file mode 100644
index 00000000000..ed1875cb952
--- /dev/null
+++ b/mono/tests/weakattribute.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace System {
+
+[AttributeUsage(AttributeTargets.Field)]
+public sealed class WeakAttribute : Attribute
+{
+}
+
+}