Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion external/api-snapshot
12 changes: 12 additions & 0 deletions mcs/class/corlib/System/WeakAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System;

#if MOBILE
namespace System {

[AttributeUsage(AttributeTargets.Field)]
public sealed class WeakAttribute : Attribute
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still think the name is very common, this can be easily breaking change due to ambiguity. We should rename it to WeakReferenceAttribute

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might also be useful to add sample into this file how it's intended to be used

{
}

}
#endif
1 change: 1 addition & 0 deletions mcs/class/corlib/corlib.dll.sources
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 7 additions & 0 deletions mono/metadata/boehm-gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
31 changes: 30 additions & 1 deletion mono/metadata/class-accessors.c
Original file line number Diff line number Diff line change
Expand Up @@ -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*/
Expand Down Expand Up @@ -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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should embed the bitmap at the end of WeakBitmapData and avoid the extra allocation and indirection.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The assumption is that weak fields are not common, so the storage doesn't need to be optimized too much.


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;
}
8 changes: 8 additions & 0 deletions mono/metadata/class-internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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>

Expand Down
26 changes: 25 additions & 1 deletion mono/metadata/class.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does it have to keep scanning?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A class can have multiple weak fields.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure but we are looking only for the first one, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are also printing out the trace message. Since these fields are not common, I don't think continuing the loop is a problem.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's still the issue that we're iterating over the parents multiple times.
This info should be cached in class and not recomputed multiple times for the same class.

Plus, this breaks SRE if it has a parent with a Weak field.

}
}
}
}

/* 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 ();
Expand Down
6 changes: 6 additions & 0 deletions mono/metadata/custom-attrs-internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -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__ */
178 changes: 178 additions & 0 deletions mono/metadata/custom-attrs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is quite inefficient. The member ref table can be as big as 10x of the typedef table.
We should first scan the typeref table for a type in corlib or "Mono.Runtime.Testing" assembly before delving into the memberef table.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will add that.


/* 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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check is assumes that WeakAttribute will only have one constructor. This must be documented in the type definition otherwise things will magically break for no good reason.

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;
}
2 changes: 2 additions & 0 deletions mono/metadata/gc-internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions mono/metadata/image.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
4 changes: 4 additions & 0 deletions mono/metadata/metadata-internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions mono/metadata/object-internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading