Skip to content

Commit 88633ae

Browse files
authored
[hot_reload] ignore modified MONO_TABLE_TYPEDEF rows in update (#90166)
* Add test that deletes a custom attribute from a class * just ignore modified MONO_TABLE_TYPEDEF rows in updates We may want to validate that Parent, Interfaces and Attributes columns haven't changed, but it's tricky and might be overly restrictive
1 parent 2e7d531 commit 88633ae

File tree

4 files changed

+59
-11
lines changed

4 files changed

+59
-11
lines changed

src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.CustomAttributeDelete/CustomAttributeDelete.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
namespace System.Reflection.Metadata.ApplyUpdate.Test
77
{
8-
[AttributeUsage (AttributeTargets.Method, AllowMultiple=true)]
8+
[AttributeUsage (AttributeTargets.Method | AttributeTargets.Class, AllowMultiple=true)]
99
public class MyDeleteAttribute : Attribute
1010
{
1111
public MyDeleteAttribute (string stringValue) { StringValue = stringValue; }
@@ -19,6 +19,7 @@ public class MyDeleteAttribute : Attribute
1919
public int IntValue {get; set; }
2020
}
2121

22+
[MyDeleteAttribute ("xyz")]
2223
public class ClassWithCustomAttributeDelete
2324
{
2425
[MyDeleteAttribute ("abcd")]

src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.CustomAttributeDelete/CustomAttributeDelete_v1.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
namespace System.Reflection.Metadata.ApplyUpdate.Test
77
{
8-
[AttributeUsage (AttributeTargets.Method, AllowMultiple=true)]
8+
[AttributeUsage (AttributeTargets.Method | AttributeTargets.Class, AllowMultiple=true)]
99
public class MyDeleteAttribute : Attribute
1010
{
1111
public MyDeleteAttribute (string stringValue) { StringValue = stringValue; }

src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -198,18 +198,33 @@ public void CustomAttributeDelete()
198198
{
199199
var assm = typeof(System.Reflection.Metadata.ApplyUpdate.Test.ClassWithCustomAttributeDelete).Assembly;
200200

201+
Type attrType = typeof(System.Reflection.Metadata.ApplyUpdate.Test.MyDeleteAttribute);
202+
203+
Type preUpdateTy = assm.GetType("System.Reflection.Metadata.ApplyUpdate.Test.ClassWithCustomAttributeDelete");
204+
Assert.NotNull(preUpdateTy);
205+
206+
// before the update the type has a MyDeleteAttribute on it
207+
Attribute[] cattrs = Attribute.GetCustomAttributes(preUpdateTy, attrType);
208+
Assert.NotNull(cattrs);
209+
Assert.Equal(1, cattrs.Length);
210+
201211
ApplyUpdateUtil.ApplyUpdate(assm);
202212
ApplyUpdateUtil.ClearAllReflectionCaches();
203213

204-
// Just check the updated value on one method
205214

206-
Type attrType = typeof(System.Reflection.Metadata.ApplyUpdate.Test.MyDeleteAttribute);
207215
Type ty = assm.GetType("System.Reflection.Metadata.ApplyUpdate.Test.ClassWithCustomAttributeDelete");
208216
Assert.NotNull(ty);
209217

218+
// After the update, the type has no MyDeleteAttribute on it anymore
219+
cattrs = Attribute.GetCustomAttributes(ty, attrType);
220+
Assert.NotNull(cattrs);
221+
Assert.Equal(0, cattrs.Length);
222+
223+
// Just check the updated value on one method
224+
210225
MethodInfo mi1 = ty.GetMethod(nameof(System.Reflection.Metadata.ApplyUpdate.Test.ClassWithCustomAttributeDelete.Method1), BindingFlags.Public | BindingFlags.Static);
211226
Assert.NotNull(mi1);
212-
Attribute[] cattrs = Attribute.GetCustomAttributes(mi1, attrType);
227+
cattrs = Attribute.GetCustomAttributes(mi1, attrType);
213228
Assert.NotNull(cattrs);
214229
Assert.Equal(0, cattrs.Length);
215230

src/mono/mono/component/hot_reload.c

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1668,7 +1668,13 @@ apply_enclog_pass1 (MonoImage *image_base, MonoImage *image_dmeta, DeltaInfo *de
16681668
i++; /* skip the next record */
16691669
continue;
16701670
}
1671-
/* fallthru */
1671+
// don't expect to see any other func codes with this table
1672+
g_assert (func_code == ENC_FUNC_DEFAULT);
1673+
// If it's an addition, it's an added type definition, continue.
1674+
1675+
// If it's a modification, Roslyn sometimes sends this when a custom
1676+
// attribute is deleted from a type definition.
1677+
break;
16721678
}
16731679
default:
16741680
if (!is_addition) {
@@ -2279,16 +2285,42 @@ apply_enclog_pass2 (Pass2Context *ctx, MonoImage *image_base, BaselineInfo *base
22792285
* especially since from the next generation's point of view
22802286
* that's what adding a field/method will be. */
22812287
break;
2282-
case ENC_FUNC_ADD_EVENT:
2283-
g_assert_not_reached (); /* FIXME: implement me */
22842288
default:
22852289
g_assert_not_reached (); /* unknown func_code */
22862290
}
22872291
break;
2292+
} else {
2293+
switch (func_code) {
2294+
case ENC_FUNC_DEFAULT:
2295+
// Roslyn sends this sometimes when it deletes a custom
2296+
// attribute. In this case no rows of the table def have
2297+
// should have changed from the previous generation.
2298+
2299+
// Note: we may want to check that Parent and Interfaces
2300+
// haven't changed. But note that's tricky to do: we can't
2301+
// just compare tokens: the parent could be a TypeRef token,
2302+
// and roslyn does send a new typeref row (that ends up
2303+
// referencing the same type definition). But we also don't
2304+
// want to convert to a `MonoClass*` too eagerly - if the
2305+
// class hasn't been used yet we don't want to kick off
2306+
// class initialization (which could mention the current
2307+
// class thanks to generic arguments - see class-init.c)
2308+
// Same with Interfaces. Fields and Methods in an EnC
2309+
// updated row are zero. So that only really leaves
2310+
// Attributes as the only column we can compare, which
2311+
// wouldn't tell us much (and perhaps in the future Roslyn
2312+
// could allow changing visibility, so we wouldn't want to
2313+
// compare for equality, anyway) So... we're done.
2314+
break;
2315+
case ENC_FUNC_ADD_METHOD:
2316+
case ENC_FUNC_ADD_FIELD:
2317+
/* modifying an existing class by adding a method or field, etc. */
2318+
break;
2319+
default:
2320+
/* not expecting anything else */
2321+
g_assert_not_reached ();
2322+
}
22882323
}
2289-
/* modifying an existing class by adding a method or field, etc. */
2290-
g_assert (!is_addition);
2291-
g_assert (func_code != ENC_FUNC_DEFAULT);
22922324
break;
22932325
}
22942326
case MONO_TABLE_NESTEDCLASS: {

0 commit comments

Comments
 (0)