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

Skip to content

Conversation

@vargaz
Copy link
Contributor

@vargaz vargaz commented Nov 9, 2017

Fields marked with the newly added [Weak] attribute will have weakref semantics, they will be null-ed out when
the object they point to is collected.

This is implemented as follows:

  • We check for fields with the attribute named WeakAttribute.
    To avoid repeated scans for custom attributes, we scan the customattr table once per image,
    collecting the field table indexes of weak fields.
  • We clear the gc bit of these fields so they are not considered gc references.
  • When an object with weak fields is allocated, we create a gc handle for it with type WEAK_FIELDS.
  • When processing gc handles, we process handles of type WEAK_FIELDS by checking that
    the weak fields point to a live object. If not, we set them to null.

Copy link
Contributor

@kumpera kumpera left a comment

Choose a reason for hiding this comment

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

There are multiple blockers with this PR:

  • The GC code gets both generational and moving heap assumptions wrong.

  • It's missing boehm support.

  • The metadata code can be potentially slow due to scanning a few big tables upfront. We should measure the memory and time costs of this PR before merging it.

  • There's no AOT caching of that info nor does the patch handles cached AOT metadata.

  • It doesn't handle generic instances, structs, static or thread-local variables. It doesn't fail the type either when finding those unsupported types.

  • The JIT incorrectly generates write barriers to weak field stores. Either that or make use of remset info to scan those old gen objects.

  • The test suite needs to be expanded to include at least this scenarios:

  • old gen obj with weak field pointing to young gen object. Have the young gen object get promoted and verify that it remains ok.
  • LOS obj with weak field (array of structs with a weak field) pointing to young gen object. Get the young gen object promoted and verify that it remains ok.
  • Pass a weak field byref, load/store from it and verify.
  • A weak field in a struct or a generic class.

Copy link
Contributor

Choose a reason for hiding this comment

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

Did you check that interfaces_inited, has_finalize_inited, fields_inited and has_failure are all modified with the loader lock held?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

MonoClass has this comment:
/* ALL BITFIELDS SHOULD BE WRITTEN WHILE HOLDING THE LOADER LOCK */

Copy link
Contributor

Choose a reason for hiding this comment

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

Missing a mono_error_cleanup.

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 fix.

Copy link
Contributor

Choose a reason for hiding this comment

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

This will recompute the weak layout of base types multiple times and this could be quite inefficient.
Since we compute the layout of the parent type first, we could just check klass->has_weak_fields and bootstrap from that bitmap instead of doing all of this heavy weight lookup.

Copy link
Contributor

Choose a reason for hiding this comment

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

How will this interact with AOT cached info that won't call mono_class_layout_fields for cached classes?

Copy link
Contributor

Choose a reason for hiding this comment

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

How will this work for generic instances?

Copy link
Contributor

Choose a reason for hiding this comment

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

How will this handle a struct with a weak field?

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.

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.

Copy link
Contributor

Choose a reason for hiding this comment

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

Can't null-gc behavior be of just asserting?

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 wrong. An old gen object might have a weak field pointing to an young gen object that got promoted.

Copy link
Contributor

@kumpera kumpera Nov 9, 2017

Choose a reason for hiding this comment

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

This is wrong, the object can move and we must update the value in the gchandle table

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 wrong, since weak fields are not scanned as part of remset processing, we must scan all of those objects.

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.

Copy link
Contributor

Choose a reason for hiding this comment

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

We must check if the object moved and update the field.

{
//
// We use a gc handle to be able to do some processing for these objects at every gc
//
Copy link
Contributor

Choose a reason for hiding this comment

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

I would add a note here that this handle is freed by scan_for_weak.

@joncham
Copy link
Contributor

joncham commented Nov 10, 2017

Is this a new feature in .NET, or a mono specific extension?

@vargaz
Copy link
Contributor Author

vargaz commented Nov 11, 2017

Currently, its a mono extension intended to be used on ios, similar to the weak references in swift.

@ghost ghost removed the cla-already-signed label Nov 16, 2017
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.

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


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)) {
Copy link
Member

Choose a reason for hiding this comment

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

We should also check for readonly flag

Copy link
Contributor

Choose a reason for hiding this comment

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

why the readonly flag matters for this?

Copy link
Member

Choose a reason for hiding this comment

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

It just feels wrong to me to have Weak on readonly field, the value should not be ever unset

Copy link
Contributor

Choose a reason for hiding this comment

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

This PR doesn't include any form of error handling for bad field configurations. It's left for the C# compiler to eventually do it.

A readonly weak ref will work as advertised, only inited in the constructor and eventually zero'd when the object is gone. It's weird but kinda makes sense?

Copy link
Member

Choose a reason for hiding this comment

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

I don't think C# work will be done anytime soon if ever. Maybe I misunderstand but [Weak] readonly Foo f = Other.Value; can be set back to null after initialization and Other.Value as an unique reference is gone which just looks odd to me.

Copy link
Contributor

Choose a reason for hiding this comment

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

Hey Marek,

This PR is not the right medium to discuss semantics and scope. I support us discussing it all just not here.

@marek-safar
Copy link
Member

commit apidiff

monojenkins added a commit to mono/api-snapshot that referenced this pull request Nov 29, 2017
@marek-safar
Copy link
Member

@vargaz there are many tests failures could you investigate

@vargaz
Copy link
Contributor Author

vargaz commented Nov 29, 2017

build

@marek-safar
Copy link
Member

@vargaz it's still failing with following on all lanes

MONO_PATH=D:/j/workspace/x/mcs/class/lib/net_4_x /cygdrive/d/j/workspace/x/tools/pedump/pedump --verify error test-runner.exe
make[4]: *** [Makefile:2341: test-pedump] Error 255

vargaz and others added 5 commits November 30, 2017 23:44
Fields marked with the newly added [Weak] attribute will have weakref semantics, they will be null-ed out when
the object they point to is collected.

This is implemented as follows:
- We check for fields with the attribute named WeakAttribute.
  To avoid repeated scans for custom attributes, we scan the customattr table once per image,
  collecting the field table indexes of weak fields.
- We clear the gc bit of these fields so they are not considered gc references.
- When an object with weak fields is allocated, we create a gc handle for it with type WEAK_FIELDS.
- When processing gc handles, we process handles of type WEAK_FIELDS by checking that
  the weak fields point to a live object. If not, we set them to null.
…criptor (), only computed klass->has_weak_fields in mono_class_layout_fields ().
@marek-safar
Copy link
Member

@monojenkins build Linux x64 Acceptance Tests

@marek-safar marek-safar merged commit 5bdaef7 into mono:master Dec 3, 2017
akoeplinger added a commit that referenced this pull request Dec 4, 2017
marek-safar pushed a commit to marek-safar/mono that referenced this pull request Jan 10, 2018
marek-safar pushed a commit to marek-safar/mono that referenced this pull request Jan 11, 2018
picenka21 pushed a commit to picenka21/runtime that referenced this pull request Feb 18, 2022
picenka21 pushed a commit to picenka21/runtime that referenced this pull request Feb 18, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants