diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddInstanceField/AddInstanceField.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddInstanceField/AddInstanceField.cs index 0b10a8b11fc9c5..327014d8069361 100644 --- a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddInstanceField/AddInstanceField.cs +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddInstanceField/AddInstanceField.cs @@ -47,5 +47,7 @@ public double FireEvents() { return Accumulator; } + + public DateTime GetDateTime() => default(DateTime); } } diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddInstanceField/AddInstanceField_v1.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddInstanceField/AddInstanceField_v1.cs index 51768ff26f2a0d..04e3fdafda548b 100644 --- a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddInstanceField/AddInstanceField_v1.cs +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddInstanceField/AddInstanceField_v1.cs @@ -85,6 +85,11 @@ public double FireEvents() { return Accumulator; } + public DateTime GetDateTime() => default(DateTime); + public double AddedFirstProp {get => 0.0; set { Console.WriteLine (value); } } + + public DateTime AddedDateTime; + } } diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddInstanceField/AddInstanceField_v2.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddInstanceField/AddInstanceField_v2.cs index 87ad6f32526f0a..3958f12dc11eca 100644 --- a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddInstanceField/AddInstanceField_v2.cs +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddInstanceField/AddInstanceField_v2.cs @@ -85,7 +85,12 @@ public double FireEvents() { return Accumulator; } + public DateTime GetDateTime() => AddedDateTime; + public double AddedFirstProp {get => 0.0; set { Console.WriteLine (value+value); } } public short AddedSecondProp {get; set; } + + public DateTime AddedDateTime; + } } diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.GenericAddInstanceField/GenericAddInstanceField.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.GenericAddInstanceField/GenericAddInstanceField.cs new file mode 100644 index 00000000000000..98a07ef78fba03 --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.GenericAddInstanceField/GenericAddInstanceField.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +using System; + + +namespace System.Reflection.Metadata.ApplyUpdate.Test +{ + public class GenericAddInstanceField + { + public GenericAddInstanceField (T p) { + } + + public T GetIt() + { + return default(T); + } + } +} diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.GenericAddInstanceField/GenericAddInstanceField_v1.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.GenericAddInstanceField/GenericAddInstanceField_v1.cs new file mode 100644 index 00000000000000..a333e7372d94c7 --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.GenericAddInstanceField/GenericAddInstanceField_v1.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +using System; + + +namespace System.Reflection.Metadata.ApplyUpdate.Test +{ + public class GenericAddInstanceField + { + public GenericAddInstanceField (T p) { + } + + T myAddedField; + + public T GetIt() + { + return default(T); + } + } +} diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.GenericAddInstanceField/GenericAddInstanceField_v2.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.GenericAddInstanceField/GenericAddInstanceField_v2.cs new file mode 100644 index 00000000000000..39bf3ff0b896b8 --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.GenericAddInstanceField/GenericAddInstanceField_v2.cs @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +using System; + + +namespace System.Reflection.Metadata.ApplyUpdate.Test +{ + public class GenericAddInstanceField + { + public GenericAddInstanceField (T p) { + myAddedField = p; + } + + T myAddedField; + + public T GetIt() + { + return myAddedField; + } + } +} diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.GenericAddInstanceField/System.Reflection.Metadata.ApplyUpdate.Test.GenericAddInstanceField.csproj b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.GenericAddInstanceField/System.Reflection.Metadata.ApplyUpdate.Test.GenericAddInstanceField.csproj new file mode 100644 index 00000000000000..9779fa6c9f6622 --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.GenericAddInstanceField/System.Reflection.Metadata.ApplyUpdate.Test.GenericAddInstanceField.csproj @@ -0,0 +1,11 @@ + + + System.Runtime.Loader.Tests + $(NetCoreAppCurrent) + true + deltascript.json + + + + + diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.GenericAddInstanceField/deltascript.json b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.GenericAddInstanceField/deltascript.json new file mode 100644 index 00000000000000..885807f5d1dd5c --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.GenericAddInstanceField/deltascript.json @@ -0,0 +1,7 @@ +{ + "changes": [ + {"document": "GenericAddInstanceField.cs", "update": "GenericAddInstanceField_v1.cs"}, + {"document": "GenericAddInstanceField.cs", "update": "GenericAddInstanceField_v2.cs"}, + ] +} + diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.GenericAddStaticField/GenericAddStaticField.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.GenericAddStaticField/GenericAddStaticField.cs new file mode 100644 index 00000000000000..ecea62abb4ad75 --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.GenericAddStaticField/GenericAddStaticField.cs @@ -0,0 +1,22 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +using System; + + +namespace System.Reflection.Metadata.ApplyUpdate.Test +{ + public class GenericAddStaticField + { + public GenericAddStaticField () { + } + + public T GetField () => s_field; + + private static T s_field; + + public void TestMethod () { + s_field = (T)(object)"abcd"; + } + + } +} diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.GenericAddStaticField/GenericAddStaticField_v1.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.GenericAddStaticField/GenericAddStaticField_v1.cs new file mode 100644 index 00000000000000..ab6c8ebc2ba769 --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.GenericAddStaticField/GenericAddStaticField_v1.cs @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +using System; + + +namespace System.Reflection.Metadata.ApplyUpdate.Test +{ + public class GenericAddStaticField + { + public GenericAddStaticField () { + } + + public T GetField () => s_field; + + private static T s_field; + + public static T s_field2; + + public void TestMethod () { + s_field = (T)(object)"spqr"; + //s_field2 = (T)(object)"4567"; + } + + } +} diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.GenericAddStaticField/GenericAddStaticField_v2.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.GenericAddStaticField/GenericAddStaticField_v2.cs new file mode 100644 index 00000000000000..2257051d7f70e7 --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.GenericAddStaticField/GenericAddStaticField_v2.cs @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +using System; + + +namespace System.Reflection.Metadata.ApplyUpdate.Test +{ + public class GenericAddStaticField + { + public GenericAddStaticField () { + } + + public T GetField () => s_field2; + + private static T s_field; + + public static T s_field2; + + public void TestMethod () { + s_field = (T)(object)"spqr"; + s_field2 = (T)(object)"4567"; + } + + } +} diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.GenericAddStaticField/System.Reflection.Metadata.ApplyUpdate.Test.GenericAddStaticField.csproj b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.GenericAddStaticField/System.Reflection.Metadata.ApplyUpdate.Test.GenericAddStaticField.csproj new file mode 100644 index 00000000000000..2a9400c53dda6b --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.GenericAddStaticField/System.Reflection.Metadata.ApplyUpdate.Test.GenericAddStaticField.csproj @@ -0,0 +1,11 @@ + + + System.Runtime.Loader.Tests + $(NetCoreAppCurrent) + true + deltascript.json + + + + + diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.GenericAddStaticField/deltascript.json b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.GenericAddStaticField/deltascript.json new file mode 100644 index 00000000000000..d167f0b39a281b --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.GenericAddStaticField/deltascript.json @@ -0,0 +1,8 @@ +{ + "capabilities": ["Baseline", "AddStaticFieldToExistingType", "AddInstanceFieldToExistingType", "GenericUpdateMethod", "GenericAddFieldToExistingType"], + "changes": [ + {"document": "GenericAddStaticField.cs", "update": "GenericAddStaticField_v1.cs"}, + {"document": "GenericAddStaticField.cs", "update": "GenericAddStaticField_v2.cs"}, + ] +} + diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs index e4f39888aeb07c..3593c5588eee70 100644 --- a/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs @@ -408,6 +408,11 @@ public static void TestAddInstanceField() Assert.True ((addedEventToken & 0x00ffffff) < 4); + fi = x2.GetType().GetField("AddedDateTime"); + Assert.NotNull(fi); + var dt = DateTime.Now; + fi.SetValue(x2, dt); + Assert.Equal(dt, fi.GetValue(x2)); ApplyUpdateUtil.ApplyUpdate(assm); @@ -419,6 +424,8 @@ public static void TestAddInstanceField() var secondPropGetter = addedSecondPropInfo.GetGetMethod(); Assert.NotNull (secondPropGetter); + Assert.Equal(dt, x2.GetDateTime()); + }); } @@ -753,7 +760,7 @@ public static void TestReflectionAddNewMethod() var ty = typeof(System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewMethod); var assm = ty.Assembly; - var bindingFlags = BindingFlags.Instance | BindingFlags.Public; + var bindingFlags = BindingFlags.Instance | BindingFlags.Public; var allMethods = ty.GetMethods(bindingFlags); int objectMethods = typeof(object).GetMethods(bindingFlags).Length; @@ -799,32 +806,120 @@ public static void TestReflectionAddNewMethod() parmPos++; } - var parmAttrs = parms[4].GetCustomAttributes(false); + var parmAttrs = parms[4].GetCustomAttributes(false); Assert.Equal (2, parmAttrs.Length); - bool foundCallerMemberName = false; - bool foundOptional = false; - foreach (var pa in parmAttrs) { - if (typeof (CallerMemberNameAttribute).Equals(pa.GetType())) - { - foundCallerMemberName = true; - } - if (typeof (OptionalAttribute).Equals(pa.GetType())) - { - foundOptional = true; - } - } - Assert.True(foundCallerMemberName); - Assert.True(foundOptional); - - // n.b. this typeof() also makes the rest of the test work on Wasm with aggressive trimming. - Assert.Equal (typeof(System.Threading.CancellationToken), parms[3].ParameterType); + bool foundCallerMemberName = false; + bool foundOptional = false; + foreach (var pa in parmAttrs) { + if (typeof (CallerMemberNameAttribute).Equals(pa.GetType())) + { + foundCallerMemberName = true; + } + if (typeof (OptionalAttribute).Equals(pa.GetType())) + { + foundOptional = true; + } + } + Assert.True(foundCallerMemberName); + Assert.True(foundOptional); + + // n.b. this typeof() also makes the rest of the test work on Wasm with aggressive trimming. + Assert.Equal (typeof(System.Threading.CancellationToken), parms[3].ParameterType); Assert.True(parms[3].HasDefaultValue); - Assert.True(parms[4].HasDefaultValue); + Assert.True(parms[4].HasDefaultValue); + + Assert.Null(parms[3].DefaultValue); + Assert.Equal(string.Empty, parms[4].DefaultValue); + }); + } + + [ActiveIssue("https://github.com/dotnet/runtime/issues/87574", TestRuntimes.CoreCLR)] + [ConditionalFact(typeof(ApplyUpdateUtil), nameof(ApplyUpdateUtil.IsSupported))] + public static void TestGenericAddStaticField() + { + ApplyUpdateUtil.TestCase(static () => + { + var assm = typeof(System.Reflection.Metadata.ApplyUpdate.Test.GenericAddStaticField<>).Assembly; + + var x = new System.Reflection.Metadata.ApplyUpdate.Test.GenericAddStaticField(); + + x.TestMethod(); + + Assert.Equal ("abcd", x.GetField()); + + var y = new System.Reflection.Metadata.ApplyUpdate.Test.GenericAddStaticField(); + + Assert.Equal (0.0, y.GetField()); + + ApplyUpdateUtil.ApplyUpdate(assm); + + // there are two updates - the first adds the fields, the second one updates the + // methods to use the new fields + ApplyUpdateUtil.ApplyUpdate(assm); + + x.TestMethod(); + + string result = x.GetField(); + Assert.Equal("4567", result); - Assert.Null(parms[3].DefaultValue); - Assert.Equal(string.Empty, parms[4].DefaultValue); + Assert.Equal(0.0, y.GetField()); }); - } + } + + [ActiveIssue("https://github.com/dotnet/runtime/issues/87574", TestRuntimes.CoreCLR)] + [ConditionalFact(typeof(ApplyUpdateUtil), nameof(ApplyUpdateUtil.IsSupported))] + public static void TestGenericAddInstanceField() + { + ApplyUpdateUtil.TestCase(static () => + { + var assm = typeof(System.Reflection.Metadata.ApplyUpdate.Test.GenericAddInstanceField<>).Assembly; + + var x = new System.Reflection.Metadata.ApplyUpdate.Test.GenericAddInstanceField("abcd"); + + Assert.Null (x.GetIt()); + + var y = new System.Reflection.Metadata.ApplyUpdate.Test.GenericAddInstanceField(45.0); + + Assert.Equal (0.0, y.GetIt()); + + ApplyUpdateUtil.ApplyUpdate(assm); + + var fi = x.GetType().GetField("myAddedField", BindingFlags.Instance | BindingFlags.NonPublic); + + Assert.NotNull(fi); + + Assert.Equal ("myAddedField", fi.Name); + + Assert.Equal (typeof(string), fi.FieldType); + + var fi2 = y.GetType().GetField("myAddedField", BindingFlags.Instance | BindingFlags.NonPublic); + + Assert.NotNull(fi2); + + Assert.Equal ("myAddedField", fi2.Name); + + Assert.Equal (typeof(double), fi2.FieldType); + + // there are two updates - the first adds the fields, the second one updates the + // methods to use the new fields + ApplyUpdateUtil.ApplyUpdate(assm); + + Assert.Null (x.GetIt()); + Assert.Equal (0.0, y.GetIt()); + + x = new System.Reflection.Metadata.ApplyUpdate.Test.GenericAddInstanceField("spqr"); + + string result = x.GetIt(); + Assert.Equal("spqr", result); + + y = new System.Reflection.Metadata.ApplyUpdate.Test.GenericAddInstanceField(2.717); + Assert.Equal(2.717, y.GetIt()); + + var dt = DateTime.Now; + var z = new System.Reflection.Metadata.ApplyUpdate.Test.GenericAddInstanceField(dt); + Assert.Equal(dt, z.GetIt()); + }); + } } } diff --git a/src/libraries/System.Runtime.Loader/tests/System.Runtime.Loader.Tests.csproj b/src/libraries/System.Runtime.Loader/tests/System.Runtime.Loader.Tests.csproj index 9062c6b5e03c1b..293105e20d4345 100644 --- a/src/libraries/System.Runtime.Loader/tests/System.Runtime.Loader.Tests.csproj +++ b/src/libraries/System.Runtime.Loader/tests/System.Runtime.Loader.Tests.csproj @@ -64,6 +64,8 @@ + + diff --git a/src/mono/mono/component/hot_reload.c b/src/mono/mono/component/hot_reload.c index 150330769a34c6..12fd9b6fb03d65 100644 --- a/src/mono/mono/component/hot_reload.c +++ b/src/mono/mono/component/hot_reload.c @@ -178,6 +178,9 @@ add_event_to_existing_class (MonoImage *image_base, BaselineInfo *base_info, uin static void add_semantic_method_to_existing_event (MonoImage *image_base, BaselineInfo *base_info, uint32_t semantics, uint32_t klass_token, uint32_t event_token, uint32_t method_token); +static MonoClassMetadataUpdateInfo * +hot_reload_get_or_add_ginst_update_info(MonoClass *ginst); + static MonoComponentHotReload fn_table = { { MONO_COMPONENT_ITF_VERSION, &hot_reload_available }, &hot_reload_set_fastpath_data, @@ -2983,7 +2986,12 @@ hot_reload_get_field_idx (MonoClassField *field) static MonoClassField * hot_reload_get_field (MonoClass *klass, uint32_t fielddef_token) { - MonoClassMetadataUpdateInfo *info = mono_class_get_or_add_metadata_update_info (klass); + MonoClassMetadataUpdateInfo *info; + if (mono_class_is_ginst (klass)) { + info = hot_reload_get_or_add_ginst_update_info (klass); + } else { + info = mono_class_get_metadata_update_info (klass); + } g_assert (mono_metadata_token_table (fielddef_token) == MONO_TABLE_FIELD); GSList *added_fields = info->added_fields; @@ -3252,7 +3260,12 @@ hot_reload_get_static_field_addr (MonoClassField *field) g_assert (!m_type_is_byref(f->field.type)); // byref fields only in ref structs, which aren't allowed in EnC updates MonoClass *parent = m_field_get_parent (&f->field); - MonoClassMetadataUpdateInfo *parent_info = mono_class_get_or_add_metadata_update_info (parent); + MonoClassMetadataUpdateInfo *parent_info; + if (mono_class_is_ginst (parent)) { + parent_info = hot_reload_get_or_add_ginst_update_info (parent); + } else { + parent_info = mono_class_get_metadata_update_info (parent); + } MonoClassRuntimeMetadataUpdateInfo *runtime_info = &parent_info->runtime; ensure_class_runtime_info_inited (parent, runtime_info); @@ -3394,7 +3407,12 @@ hot_reload_added_methods_iter (MonoClass *klass, gpointer *iter) static MonoClassField * hot_reload_added_fields_iter (MonoClass *klass, gboolean lazy G_GNUC_UNUSED, gpointer *iter) { - MonoClassMetadataUpdateInfo *info = mono_class_get_metadata_update_info (klass); + MonoClassMetadataUpdateInfo *info; + if (mono_class_is_ginst (klass)) { + info = hot_reload_get_or_add_ginst_update_info (klass); + } else { + info = mono_class_get_metadata_update_info (klass); + } if (!info) return NULL; @@ -3422,7 +3440,12 @@ hot_reload_added_fields_iter (MonoClass *klass, gboolean lazy G_GNUC_UNUSED, gpo static uint32_t hot_reload_get_num_fields_added (MonoClass *klass) { - MonoClassMetadataUpdateInfo *info = mono_class_get_metadata_update_info (klass); + MonoClassMetadataUpdateInfo *info; + if (mono_class_is_ginst (klass)) { + info = hot_reload_get_or_add_ginst_update_info (klass); + } else { + info = mono_class_get_metadata_update_info (klass); + } if (!info) return 0; return g_slist_length (info->added_fields); @@ -3432,6 +3455,7 @@ static uint32_t hot_reload_get_num_methods_added (MonoClass *klass) { uint32_t count = 0; + // FIXME: this might need to look at the generic class if `klass` is a ginst GSList *members = hot_reload_get_added_members (klass); for (GSList *ptr = members; ptr; ptr = ptr->next) { uint32_t token = GPOINTER_TO_UINT(ptr->data); @@ -3471,7 +3495,7 @@ hot_reload_get_method_params (MonoImage *base_image, uint32_t methoddef_token, u static const char * hot_reload_get_capabilities (void) { - return "Baseline AddMethodToExistingType AddStaticFieldToExistingType NewTypeDefinition ChangeCustomAttributes AddInstanceFieldToExistingType GenericAddMethodToExistingType GenericUpdateMethod UpdateParameters"; + return "Baseline AddMethodToExistingType AddStaticFieldToExistingType NewTypeDefinition ChangeCustomAttributes AddInstanceFieldToExistingType GenericAddMethodToExistingType GenericUpdateMethod UpdateParameters GenericAddFieldToExistingType"; } static GENERATE_GET_CLASS_WITH_CACHE_DECL (hot_reload_instance_field_table); @@ -3552,14 +3576,10 @@ hot_reload_get_or_add_ginst_update_info(MonoClass *ginst) ((struct_type *) mono_class_alloc0 ((klass), ((gsize) sizeof (struct_type)) * ((gsize) (n_structs)))) static void -recompute_ginst_update_info(MonoClass *ginst, MonoClass *gtd, MonoClassMetadataUpdateInfo *gtd_info) +recompute_ginst_props (MonoClass *ginst, MonoClassMetadataUpdateInfo *info, + MonoClass *gtd, MonoClassMetadataUpdateInfo *gtd_info, + MonoError *error) { - // if ginst has a `MonoClassMetadataUpdateInfo`, use it to start with, otherwise, allocate a new one - MonoClassMetadataUpdateInfo *info = mono_class_get_or_add_metadata_update_info (ginst); - - if (!info) - info = mono_class_new0 (ginst, MonoClassMetadataUpdateInfo, 1); - // replace info->added_props by a new list re-computed from gtd_info->added_props info->added_props = NULL; for (GSList *ptr = gtd_info->added_props; ptr; ptr = ptr->next) { @@ -3569,20 +3589,25 @@ recompute_ginst_update_info(MonoClass *ginst, MonoClass *gtd, MonoClassMetadataU added_prop->prop = gtd_added_prop->prop; added_prop->token = gtd_added_prop->token; - ERROR_DECL (error); if (added_prop->prop.get) added_prop->prop.get = mono_class_inflate_generic_method_full_checked ( added_prop->prop.get, ginst, mono_class_get_context (ginst), error); if (added_prop->prop.set) added_prop->prop.set = mono_class_inflate_generic_method_full_checked ( added_prop->prop.set, ginst, mono_class_get_context (ginst), error); - g_assert (is_ok (error)); /*FIXME proper error handling*/ + mono_error_assert_ok (error); /*FIXME proper error handling*/ added_prop->prop.parent = ginst; info->added_props = g_slist_prepend_mem_manager (m_class_get_mem_manager (ginst), info->added_props, (gpointer)added_prop); } +} +static void +recompute_ginst_events (MonoClass *ginst, MonoClassMetadataUpdateInfo *info, + MonoClass *gtd, MonoClassMetadataUpdateInfo *gtd_info, + MonoError *error) +{ // replace info->added_events by a new list re-computed from gtd_info->added_events info->added_events = NULL; for (GSList *ptr = gtd_info->added_events; ptr; ptr = ptr->next) { @@ -3591,7 +3616,6 @@ recompute_ginst_update_info(MonoClass *ginst, MonoClass *gtd, MonoClassMetadataU added_event->evt = gtd_added_event->evt; - ERROR_DECL (error); if (added_event->evt.add) added_event->evt.add = mono_class_inflate_generic_method_full_checked ( added_event->evt.add, ginst, mono_class_get_context (ginst), error); @@ -3601,13 +3625,62 @@ recompute_ginst_update_info(MonoClass *ginst, MonoClass *gtd, MonoClassMetadataU if (added_event->evt.raise) added_event->evt.raise = mono_class_inflate_generic_method_full_checked ( added_event->evt.raise, ginst, mono_class_get_context (ginst), error); - g_assert (is_ok (error)); /*FIXME proper error handling*/ + mono_error_assert_ok (error); /*FIXME proper error handling*/ added_event->evt.parent = ginst; info->added_events = g_slist_prepend_mem_manager (m_class_get_mem_manager (ginst), info->added_events, (gpointer)added_event); } +} + +static void +recompute_ginst_fields (MonoClass *ginst, MonoClassMetadataUpdateInfo *info, + MonoClass *gtd, MonoClassMetadataUpdateInfo *gtd_info, + MonoError *error) +{ + info->added_fields = NULL; + for (GSList *ptr = gtd_info->added_fields; ptr; ptr = ptr->next) { + MonoClassMetadataUpdateField *gtd_added_field = (MonoClassMetadataUpdateField *)ptr->data; + MonoClassMetadataUpdateField *added_field = mono_class_new0 (ginst, MonoClassMetadataUpdateField, 1); + + mono_field_resolve_type (>d_added_field->field, error); + mono_error_assert_ok (error); + g_assert (gtd_added_field->field.type != NULL); + + added_field->field = gtd_added_field->field; + added_field->token = gtd_added_field->token; + + added_field->field.type = mono_class_inflate_generic_type_checked ( + added_field->field.type, mono_class_get_context (ginst), error); + mono_error_assert_ok (error); /*FIXME proper error handling*/ + + m_field_set_parent (&added_field->field, ginst); + m_field_set_meta_flags (&added_field->field, MONO_CLASS_FIELD_META_FLAG_FROM_UPDATE); + + info->added_fields = g_slist_prepend_mem_manager (m_class_get_mem_manager (ginst), info->added_fields, (gpointer)added_field); + } +} + +static void +recompute_ginst_update_info(MonoClass *ginst, MonoClass *gtd, MonoClassMetadataUpdateInfo *gtd_info) +{ + // if ginst has a `MonoClassMetadataUpdateInfo`, use it to start with, otherwise, allocate a new one + MonoClassMetadataUpdateInfo *info = mono_class_get_or_add_metadata_update_info (ginst); + + if (!info) + info = mono_class_new0 (ginst, MonoClassMetadataUpdateInfo, 1); + + ERROR_DECL (error); + + recompute_ginst_props (ginst, info, gtd, gtd_info, error); + mono_error_assert_ok (error); + + recompute_ginst_events (ginst, info, gtd, gtd_info, error); + mono_error_assert_ok (error); + recompute_ginst_fields (ginst, info, gtd, gtd_info, error); + mono_error_assert_ok (error); + // finally, update the generation of the ginst info to the same one as the gtd info->generation = gtd_info->generation; // we're done info is now up to date diff --git a/src/mono/mono/metadata/class.c b/src/mono/mono/metadata/class.c index 053a13ccc71bf4..834921ffd69bbc 100644 --- a/src/mono/mono/metadata/class.c +++ b/src/mono/mono/metadata/class.c @@ -2479,7 +2479,9 @@ mono_class_get_field_from_name_full (MonoClass *klass, const char *name, MonoTyp continue; if (type) { - MonoType *field_type = mono_metadata_get_corresponding_field_from_generic_type_definition (field)->type; + MonoClassField *gfield = mono_metadata_get_corresponding_field_from_generic_type_definition (field); + g_assert (gfield != NULL); + MonoType *field_type = gfield->type; if (!mono_metadata_type_equal_full (type, field_type, TRUE)) continue; } diff --git a/src/mono/mono/metadata/metadata.c b/src/mono/mono/metadata/metadata.c index 33289280b816af..c7398d558270bd 100644 --- a/src/mono/mono/metadata/metadata.c +++ b/src/mono/mono/metadata/metadata.c @@ -7735,13 +7735,15 @@ mono_metadata_get_corresponding_field_from_generic_type_definition (MonoClassFie if (!mono_class_is_ginst (m_field_get_parent (field))) return field; - /* - * metadata-update: nothing to do. can't add fields to existing generic - * classes; for new gtds added in updates, this is correct. - */ gtd = mono_class_get_generic_class (m_field_get_parent (field))->container_class; - offset = field - m_class_get_fields (m_field_get_parent (field)); - return m_class_get_fields (gtd) + offset; + + if (G_LIKELY (!m_field_is_from_update (field))) { + offset = field - m_class_get_fields (m_field_get_parent (field)); + return m_class_get_fields (gtd) + offset; + } else { + uint32_t token = mono_class_get_field_token (field); + return mono_class_get_field (gtd, token); + } } /* diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index fbd4d7dc8aa3bb..9089733a476750 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -6571,12 +6571,9 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, MonoClass *field_class = mono_class_from_mono_type_internal (ftype); interp_emit_metadata_update_ldflda (td, field, error); goto_if_nok (error, exit); - interp_add_ins (td, interp_get_ldind_for_mt (mt)); - interp_ins_set_sreg (td->last_ins, td->sp [-1].local); - td->sp--; - push_type (td, stack_type [mt], field_class); - interp_ins_set_dreg (td->last_ins, td->sp[-1].local); + interp_emit_ldobj (td, field_class); td->ip += 5; + BARRIER_IF_VOLATILE (td, MONO_MEMORY_BARRIER_ACQ); break; } int opcode = MINT_LDFLD_I1 + mt - MINT_TYPE_I1;