diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewMethod/ReflectionAddNewMethod.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewMethod/ReflectionAddNewMethod.cs new file mode 100644 index 00000000000000..c483ce17129def --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewMethod/ReflectionAddNewMethod.cs @@ -0,0 +1,16 @@ +// 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 ReflectionAddNewMethod + { + public string ExistingMethod(string u, double f) + { + return u + f.ToString();; + } + + } +} diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewMethod/ReflectionAddNewMethod_v1.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewMethod/ReflectionAddNewMethod_v1.cs new file mode 100644 index 00000000000000..bd4804ab16aa70 --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewMethod/ReflectionAddNewMethod_v1.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; +using System.Runtime.CompilerServices; +using CancellationToken = System.Threading.CancellationToken; + +namespace System.Reflection.Metadata.ApplyUpdate.Test +{ + public class ReflectionAddNewMethod + { + public string ExistingMethod(string u, double f) + { + return u + f.ToString();; + } + + public double AddedNewMethod(char c, float h, string w, CancellationToken ct = default, [CallerMemberName] string callerName = "") + { + return ((double)Convert.ToInt32(c)) + h; + } + } +} diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewMethod/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewMethod.csproj b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewMethod/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewMethod.csproj new file mode 100644 index 00000000000000..f2b921019f7b33 --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewMethod/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewMethod.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.ReflectionAddNewMethod/deltascript.json b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewMethod/deltascript.json new file mode 100644 index 00000000000000..a9e2fde9d00786 --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewMethod/deltascript.json @@ -0,0 +1,6 @@ +{ + "changes": [ + {"document": "ReflectionAddNewMethod.cs", "update": "ReflectionAddNewMethod_v1.cs"}, + ] +} + diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs index f66b0d3fefe079..92f19a6b0c023e 100644 --- a/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs @@ -3,6 +3,7 @@ using System.Reflection; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using Xunit; namespace System.Reflection.Metadata @@ -629,5 +630,87 @@ public static void TestReflectionAddNewType() System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewType.ZExistingClass.ExistingMethod (); }); } + + [ConditionalFact(typeof(ApplyUpdateUtil), nameof(ApplyUpdateUtil.IsSupported))] + public static void TestReflectionAddNewMethod() + { + ApplyUpdateUtil.TestCase(static () => + { + var ty = typeof(System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewMethod); + var assm = ty.Assembly; + + var bindingFlags = BindingFlags.Instance | BindingFlags.Public; + var allMethods = ty.GetMethods(bindingFlags); + + int objectMethods = typeof(object).GetMethods(bindingFlags).Length; + Assert.Equal (objectMethods + 1, allMethods.Length); + + ApplyUpdateUtil.ApplyUpdate(assm); + ApplyUpdateUtil.ClearAllReflectionCaches(); + + ty = typeof(System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewMethod); + + allMethods = ty.GetMethods(bindingFlags); + Assert.Equal (objectMethods + 2, allMethods.Length); + + var mi = ty.GetMethod ("AddedNewMethod"); + + Assert.NotNull (mi); + + var retParm = mi.ReturnParameter; + Assert.NotNull (retParm); + Assert.NotNull (retParm.ParameterType); + Assert.Equal (-1, retParm.Position); + + var retCas = retParm.GetCustomAttributes(false); + Assert.NotNull(retCas); + Assert.Equal(0, retCas.Length); + + var parms = mi.GetParameters(); + Assert.Equal (5, parms.Length); + + int parmPos = 0; + foreach (var parm in parms) + { + Assert.NotNull(parm); + Assert.NotNull(parm.ParameterType); + Assert.Equal(parmPos, parm.Position); + Assert.NotNull(parm.Name); + + var cas = parm.GetCustomAttributes(false); + foreach (var ca in cas) { + Assert.NotNull (ca); + } + + parmPos++; + } + + 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); + + Assert.True(parms[3].HasDefaultValue); + Assert.True(parms[4].HasDefaultValue); + + Assert.Null(parms[3].DefaultValue); + Assert.Equal(string.Empty, parms[4].DefaultValue); + }); + } } } 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 50941fe7b3ca73..6c5a8469726179 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 @@ -62,6 +62,7 @@ + diff --git a/src/mono/mono/component/hot_reload-internals.h b/src/mono/mono/component/hot_reload-internals.h index a668eb295c4388..cc97538749d056 100644 --- a/src/mono/mono/component/hot_reload-internals.h +++ b/src/mono/mono/component/hot_reload-internals.h @@ -86,4 +86,9 @@ typedef struct _MonoClassMetadataUpdateEvent { uint32_t token; /* the Event table token where this event was defined. */ } MonoClassMetadataUpdateEvent; +typedef struct _MonoMethodMetadataUpdateParamInfo { + uint32_t first_param_token; /* a Param token */ + uint32_t param_count; +} MonoMethodMetadataUpdateParamInfo; + #endif/*_MONO_COMPONENT_HOT_RELOAD_INTERNALS_H*/ diff --git a/src/mono/mono/component/hot_reload-stub.c b/src/mono/mono/component/hot_reload-stub.c index e97e90499e3534..94730bbe26b164 100644 --- a/src/mono/mono/component/hot_reload-stub.c +++ b/src/mono/mono/component/hot_reload-stub.c @@ -110,6 +110,9 @@ hot_reload_get_num_methods_added (MonoClass *klass); static const char * hot_reload_get_capabilities (void); +static uint32_t +hot_reload_stub_get_method_params (MonoImage *base_image, uint32_t methoddef_token, uint32_t *out_param_count_opt); + static MonoComponentHotReload fn_table = { { MONO_COMPONENT_ITF_VERSION, &hot_reload_stub_available }, &hot_reload_stub_set_fastpath_data, @@ -142,7 +145,8 @@ static MonoComponentHotReload fn_table = { &hot_reload_stub_added_fields_iter, &hot_reload_get_num_fields_added, &hot_reload_get_num_methods_added, - &hot_reload_get_capabilities + &hot_reload_get_capabilities, + &hot_reload_stub_get_method_params, }; static bool @@ -343,6 +347,12 @@ hot_reload_get_capabilities (void) return ""; } +static uint32_t +hot_reload_stub_get_method_params (MonoImage *base_image, uint32_t methoddef_token, uint32_t *out_param_count_opt) +{ + return 0; +} + MONO_COMPONENT_EXPORT_ENTRYPOINT MonoComponentHotReload * mono_component_hot_reload_init (void) diff --git a/src/mono/mono/component/hot_reload.c b/src/mono/mono/component/hot_reload.c index 166fe683e56d21..c412aa3efe6662 100644 --- a/src/mono/mono/component/hot_reload.c +++ b/src/mono/mono/component/hot_reload.c @@ -144,6 +144,9 @@ hot_reload_get_num_methods_added (MonoClass *klass); static const char * hot_reload_get_capabilities (void); +static uint32_t +hot_reload_get_method_params (MonoImage *base_image, uint32_t methoddef_token, uint32_t *out_param_count_opt); + static MonoClassMetadataUpdateField * metadata_update_field_setup_basic_info (MonoImage *image_base, BaselineInfo *base_info, uint32_t generation, DeltaInfo *delta_info, MonoClass *parent_klass, uint32_t fielddef_token, uint32_t field_flags); @@ -179,7 +182,8 @@ static MonoComponentHotReload fn_table = { &hot_reload_added_fields_iter, &hot_reload_get_num_fields_added, &hot_reload_get_num_methods_added, - &hot_reload_get_capabilities + &hot_reload_get_capabilities, + &hot_reload_get_method_params, }; MonoComponentHotReload * @@ -272,6 +276,9 @@ struct _BaselineInfo { /* Parents for added methods, fields, etc */ GHashTable *member_parent; /* maps added methoddef or fielddef tokens to typedef tokens */ + /* Params for added methods */ + GHashTable *method_params; /* maps methoddef tokens to a MonoClassMetadataUpdateMethodParamInfo* */ + /* Skeletons for all newly-added types from every generation. Accessing the array requires the image lock. */ GArray *skeletons; }; @@ -412,6 +419,12 @@ baseline_info_destroy (BaselineInfo *info) if (info->skeletons) g_array_free (info->skeletons, TRUE); + if (info->member_parent) + g_hash_table_destroy (info->member_parent); + + if (info->method_params) + g_hash_table_destroy (info->method_params); + g_free (info); } @@ -627,6 +640,11 @@ add_method_to_baseline (BaselineInfo *base_info, DeltaInfo *delta_info, MonoClas static void add_field_to_baseline (BaselineInfo *base_info, DeltaInfo *delta_info, MonoClass *klass, uint32_t field_token); +/* Add a method->params lookup for new methods in existing classes */ +static void +add_param_info_for_method (BaselineInfo *base_info, uint32_t param_token, uint32_t method_token); + + void hot_reload_init (void) { @@ -2019,6 +2037,7 @@ apply_enclog_pass2 (Pass2Context *ctx, MonoImage *image_base, BaselineInfo *base uint32_t add_member_typedef = 0; uint32_t add_property_propertymap = 0; uint32_t add_event_eventmap = 0; + uint32_t add_field_method = 0; gboolean assemblyref_updated = FALSE; for (guint32 i = 0; i < rows ; ++i) { @@ -2049,6 +2068,7 @@ apply_enclog_pass2 (Pass2Context *ctx, MonoImage *image_base, BaselineInfo *base case ENC_FUNC_ADD_PARAM: { g_assert (token_table == MONO_TABLE_METHOD); + add_field_method = log_token; break; } case ENC_FUNC_ADD_FIELD: { @@ -2115,8 +2135,11 @@ apply_enclog_pass2 (Pass2Context *ctx, MonoImage *image_base, BaselineInfo *base } case MONO_TABLE_METHOD: { /* if adding a param, handle it with the next record */ - if (func_code == ENC_FUNC_ADD_PARAM) + if (func_code == ENC_FUNC_ADD_PARAM) { + g_assert (is_addition); break; + } + g_assert (func_code == ENC_FUNC_DEFAULT); if (!base_info->method_table_update) base_info->method_table_update = g_hash_table_new (g_direct_hash, g_direct_equal); @@ -2366,9 +2389,21 @@ apply_enclog_pass2 (Pass2Context *ctx, MonoImage *image_base, BaselineInfo *base * * So by the time we see the param additions, the methods are already in. * - * FIXME: we need a lookaside table (like member_parent) for every place - * that looks at MONO_METHOD_PARAMLIST */ + if (is_addition) { + g_assert (add_field_method != 0); + uint32_t parent_type_token = hot_reload_method_parent (image_base, add_field_method); + g_assert (parent_type_token != 0); // we added a parameter to a method that was added + if (pass2_context_is_skeleton (ctx, parent_type_token)) { + // it's a parameter on a new method in a brand new class + // FIXME: need to do something here? + } else { + // it's a parameter on a new method in an existing class + add_param_info_for_method (base_info, log_token, add_field_method); + } + add_field_method = 0; + break; + } break; } case MONO_TABLE_INTERFACEIMPL: { @@ -2819,6 +2854,28 @@ hot_reload_field_parent (MonoImage *base_image, uint32_t field_token) } +static void +add_param_info_for_method (BaselineInfo *base_info, uint32_t param_token, uint32_t method_token) +{ + if (!base_info->method_params) { + base_info->method_params = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free); + } + MonoMethodMetadataUpdateParamInfo* info = NULL; + info = g_hash_table_lookup (base_info->method_params, GUINT_TO_POINTER (method_token)); + if (!info) { + // FIXME locking + info = g_new0 (MonoMethodMetadataUpdateParamInfo, 1); + g_hash_table_insert (base_info->method_params, GUINT_TO_POINTER (method_token), info); + info->first_param_token = param_token; + info->param_count = 1; + } else { + uint32_t param_index = mono_metadata_token_index (param_token); + // expect params for a single method to be a contiguous sequence of rows + g_assert (mono_metadata_token_index (info->first_param_token) + info->param_count == param_index); + info->param_count++; + } +} + /* HACK - keep in sync with locator_t in metadata/metadata.c */ typedef struct { guint32 idx; /* The index that we are trying to locate */ @@ -3148,6 +3205,32 @@ hot_reload_get_num_methods_added (MonoClass *klass) return count; } +static uint32_t +hot_reload_get_method_params (MonoImage *base_image, uint32_t methoddef_token, uint32_t *out_param_count_opt) +{ + BaselineInfo *base_info = baseline_info_lookup (base_image); + g_assert (base_info); + + /* FIXME: locking in case the hash table grows */ + + if (!base_info->method_params) + return 0; + + MonoMethodMetadataUpdateParamInfo* info = NULL; + info = g_hash_table_lookup (base_info->method_params, GUINT_TO_POINTER (methoddef_token)); + if (!info) { + if (out_param_count_opt) + *out_param_count_opt = 0; + return 0; + } + + if (out_param_count_opt) + *out_param_count_opt = info->param_count; + + return mono_metadata_token_index (info->first_param_token); +} + + static const char * hot_reload_get_capabilities (void) { diff --git a/src/mono/mono/component/hot_reload.h b/src/mono/mono/component/hot_reload.h index f7627245583af5..40c6a0f263f417 100644 --- a/src/mono/mono/component/hot_reload.h +++ b/src/mono/mono/component/hot_reload.h @@ -48,6 +48,7 @@ typedef struct _MonoComponentHotReload { uint32_t (*get_num_fields_added) (MonoClass *klass); uint32_t (*get_num_methods_added) (MonoClass *klass); const char* (*get_capabilities) (void); + uint32_t (*get_method_params) (MonoImage *base_image, uint32_t methoddef_token, uint32_t *out_param_count_opt); } MonoComponentHotReload; MONO_COMPONENT_EXPORT_ENTRYPOINT diff --git a/src/mono/mono/metadata/custom-attrs.c b/src/mono/mono/metadata/custom-attrs.c index 98dbd70d6b9334..2bce3b3e79781c 100644 --- a/src/mono/mono/metadata/custom-attrs.c +++ b/src/mono/mono/metadata/custom-attrs.c @@ -2248,15 +2248,12 @@ mono_custom_attrs_from_param_checked (MonoMethod *method, guint32 param, MonoErr method_index = mono_method_get_index (method); if (!method_index) return NULL; - ca = &image->tables [MONO_TABLE_METHOD]; - /* FIXME: metadata-update */ - param_list = mono_metadata_decode_row_col (ca, method_index - 1, MONO_METHOD_PARAMLIST); - if (method_index == table_info_get_rows (ca)) { - param_last = table_info_get_rows (&image->tables [MONO_TABLE_PARAM]) + 1; - } else { - param_last = mono_metadata_decode_row_col (ca, method_index, MONO_METHOD_PARAMLIST); - } + param_list = mono_metadata_get_method_params (image, method_index, ¶m_last); + + if (!param_list) + return NULL; + ca = &image->tables [MONO_TABLE_PARAM]; found = FALSE; diff --git a/src/mono/mono/metadata/loader.c b/src/mono/mono/metadata/loader.c index 86b60c0a6e3236..51803fa5808f72 100644 --- a/src/mono/mono/metadata/loader.c +++ b/src/mono/mono/metadata/loader.c @@ -1409,7 +1409,6 @@ mono_method_get_param_names (MonoMethod *method, const char **names) { int i, lastp; MonoClass *klass; - MonoTableInfo *methodt; MonoTableInfo *paramt; MonoMethodSignature *signature; guint32 idx; @@ -1463,19 +1462,18 @@ mono_method_get_param_names (MonoMethod *method, const char **names) return; } - methodt = &klass_image->tables [MONO_TABLE_METHOD]; paramt = &klass_image->tables [MONO_TABLE_PARAM]; idx = mono_method_get_index (method); if (idx > 0) { + guint32 cols [MONO_PARAM_SIZE]; guint param_index; - param_index = mono_metadata_decode_row_col (methodt, idx - 1, MONO_METHOD_PARAMLIST); + param_index = mono_metadata_get_method_params (klass_image, idx, (uint32_t*)&lastp); + + if (!param_index) + return; - if (idx < table_info_get_rows (methodt)) - lastp = mono_metadata_decode_row_col (methodt, idx, MONO_METHOD_PARAMLIST); - else - lastp = table_info_get_rows (paramt) + 1; for (i = param_index; i < lastp; ++i) { mono_metadata_decode_row (paramt, i -1, cols, MONO_PARAM_SIZE); if (cols [MONO_PARAM_SEQUENCE] && cols [MONO_PARAM_SEQUENCE] <= signature->param_count) /* skip return param spec and bounds check*/ @@ -1491,7 +1489,6 @@ guint32 mono_method_get_param_token (MonoMethod *method, int index) { MonoClass *klass = method->klass; - MonoTableInfo *methodt; guint32 idx; mono_class_init_internal (klass); @@ -1499,11 +1496,10 @@ mono_method_get_param_token (MonoMethod *method, int index) MonoImage *klass_image = m_class_get_image (klass); g_assert (!image_is_dynamic (klass_image)); - methodt = &klass_image->tables [MONO_TABLE_METHOD]; idx = mono_method_get_index (method); if (idx > 0) { - guint param_index = mono_metadata_decode_row_col (methodt, idx - 1, MONO_METHOD_PARAMLIST); - + guint param_index = mono_metadata_get_method_params (klass_image, idx, NULL); + if (index == -1) /* Return value */ return mono_metadata_make_token (MONO_TABLE_PARAM, 0); @@ -1522,7 +1518,6 @@ mono_method_get_marshal_info (MonoMethod *method, MonoMarshalSpec **mspecs) { int i, lastp; MonoClass *klass = method->klass; - MonoTableInfo *methodt; MonoTableInfo *paramt; MonoMethodSignature *signature; guint32 idx; @@ -1560,17 +1555,14 @@ mono_method_get_marshal_info (MonoMethod *method, MonoMarshalSpec **mspecs) mono_class_init_internal (klass); MonoImage *klass_image = m_class_get_image (klass); - methodt = &klass_image->tables [MONO_TABLE_METHOD]; paramt = &klass_image->tables [MONO_TABLE_PARAM]; idx = mono_method_get_index (method); if (idx > 0) { guint32 cols [MONO_PARAM_SIZE]; - guint param_index = mono_metadata_decode_row_col (methodt, idx - 1, MONO_METHOD_PARAMLIST); + guint param_index = mono_metadata_get_method_params (klass_image, idx, (uint32_t*)&lastp); - if (idx < table_info_get_rows (methodt)) - lastp = mono_metadata_decode_row_col (methodt, idx, MONO_METHOD_PARAMLIST); - else - lastp = table_info_get_rows (paramt) + 1; + if (!param_index) + return; for (i = param_index; i < lastp; ++i) { mono_metadata_decode_row (paramt, i -1, cols, MONO_PARAM_SIZE); @@ -1595,7 +1587,6 @@ mono_method_has_marshal_info (MonoMethod *method) { int i, lastp; MonoClass *klass = method->klass; - MonoTableInfo *methodt; MonoTableInfo *paramt; guint32 idx; @@ -1614,17 +1605,15 @@ mono_method_has_marshal_info (MonoMethod *method) mono_class_init_internal (klass); - methodt = &m_class_get_image (klass)->tables [MONO_TABLE_METHOD]; - paramt = &m_class_get_image (klass)->tables [MONO_TABLE_PARAM]; + MonoImage *klass_image = m_class_get_image (klass); + paramt = &klass_image->tables [MONO_TABLE_PARAM]; idx = mono_method_get_index (method); if (idx > 0) { guint32 cols [MONO_PARAM_SIZE]; - guint param_index = mono_metadata_decode_row_col (methodt, idx - 1, MONO_METHOD_PARAMLIST); + guint param_index = mono_metadata_get_method_params (klass_image, idx, (uint32_t*)&lastp); - if (idx + 1 < table_info_get_rows (methodt)) - lastp = mono_metadata_decode_row_col (methodt, idx, MONO_METHOD_PARAMLIST); - else - lastp = table_info_get_rows (paramt) + 1; + if (!param_index) + return FALSE; for (i = param_index; i < lastp; ++i) { mono_metadata_decode_row (paramt, i -1, cols, MONO_PARAM_SIZE); diff --git a/src/mono/mono/metadata/metadata-internals.h b/src/mono/mono/metadata/metadata-internals.h index 5c6ea98fca365c..91845152d3ecce 100644 --- a/src/mono/mono/metadata/metadata-internals.h +++ b/src/mono/mono/metadata/metadata-internals.h @@ -1248,4 +1248,7 @@ mono_metadata_table_to_ptr_table (int table_num) } } +uint32_t +mono_metadata_get_method_params (MonoImage *image, uint32_t method_idx, uint32_t *last_param_out); + #endif /* __MONO_METADATA_INTERNALS_H__ */ diff --git a/src/mono/mono/metadata/metadata-update.c b/src/mono/mono/metadata/metadata-update.c index 0bfb211c6f0caa..9541a25384c00a 100644 --- a/src/mono/mono/metadata/metadata-update.c +++ b/src/mono/mono/metadata/metadata-update.c @@ -229,4 +229,10 @@ uint32_t mono_metadata_update_get_num_methods_added (MonoClass *klass) { return mono_component_hot_reload()->get_num_methods_added (klass); -} \ No newline at end of file +} + +uint32_t +mono_metadata_update_get_method_params (MonoImage *image, uint32_t methoddef_token, uint32_t *out_param_count_opt) +{ + return mono_component_hot_reload()->get_method_params (image, methoddef_token, out_param_count_opt); +} diff --git a/src/mono/mono/metadata/metadata-update.h b/src/mono/mono/metadata/metadata-update.h index 05cc4e5c80316c..e68ca1a8ad71ae 100644 --- a/src/mono/mono/metadata/metadata-update.h +++ b/src/mono/mono/metadata/metadata-update.h @@ -93,4 +93,7 @@ mono_metadata_update_get_num_fields_added (MonoClass *klass); uint32_t mono_metadata_update_get_num_methods_added (MonoClass *klass); + +uint32_t +mono_metadata_update_get_method_params (MonoImage *image, uint32_t methoddef_token, uint32_t *out_param_count_opt); #endif /*__MONO_METADATA_UPDATE_H__*/ diff --git a/src/mono/mono/metadata/metadata.c b/src/mono/mono/metadata/metadata.c index 690df1e8157398..0c63c068929173 100644 --- a/src/mono/mono/metadata/metadata.c +++ b/src/mono/mono/metadata/metadata.c @@ -2277,17 +2277,12 @@ gboolean mono_metadata_method_has_param_attrs (MonoImage *m, int def) { MonoTableInfo *paramt = &m->tables [MONO_TABLE_PARAM]; - MonoTableInfo *methodt = &m->tables [MONO_TABLE_METHOD]; - guint lastp, i, param_index = mono_metadata_decode_row_col (methodt, def - 1, MONO_METHOD_PARAMLIST); + guint lastp, i, param_index; - if (param_index == 0) - return FALSE; + param_index = mono_metadata_get_method_params (m, def, (uint32_t*)&lastp); - /* FIXME: metadata-update */ - if (GINT_TO_UINT32(def) < table_info_get_rows (methodt)) - lastp = mono_metadata_decode_row_col (methodt, def, MONO_METHOD_PARAMLIST); - else - lastp = table_info_get_rows (&m->tables [MONO_TABLE_PARAM]) + 1; + if (!param_index) + return FALSE; for (i = param_index; i < lastp; ++i) { guint32 flags = mono_metadata_decode_row_col (paramt, i - 1, MONO_PARAM_FLAGS); @@ -2313,20 +2308,14 @@ int* mono_metadata_get_param_attrs (MonoImage *m, int def, guint32 param_count) { MonoTableInfo *paramt = &m->tables [MONO_TABLE_PARAM]; - MonoTableInfo *methodt = &m->tables [MONO_TABLE_METHOD]; guint32 cols [MONO_PARAM_SIZE]; - guint lastp, i, param_index = mono_metadata_decode_row_col (methodt, def - 1, MONO_METHOD_PARAMLIST); + guint lastp, i, param_index; int *pattrs = NULL; - /* hot reload deltas may specify 0 for the param table index */ - if (param_index == 0) - return NULL; + param_index = mono_metadata_get_method_params (m, def, (uint32_t*)&lastp); - /* FIXME: metadata-update */ - if (GINT_TO_UINT32(def) < mono_metadata_table_num_rows (m, MONO_TABLE_METHOD)) - lastp = mono_metadata_decode_row_col (methodt, def, MONO_METHOD_PARAMLIST); - else - lastp = table_info_get_rows (paramt) + 1; + if (!param_index) + return NULL; for (i = param_index; i < lastp; ++i) { mono_metadata_decode_row (paramt, i - 1, cols, MONO_PARAM_SIZE); @@ -8124,3 +8113,40 @@ mono_metadata_get_class_guid (MonoClass* klass, guint8* guid, MonoError *error) g_warning ("Generated GUIDs only implemented for interfaces!"); #endif } + +uint32_t +mono_metadata_get_method_params (MonoImage *image, uint32_t method_idx, uint32_t *last_param_out) +{ + if (last_param_out) + *last_param_out = 0; + if (!method_idx) + return 0; + + MonoTableInfo *methodt = &image->tables [MONO_TABLE_METHOD]; + + uint32_t param_index, lastp; + + param_index = mono_metadata_decode_row_col (methodt, method_idx - 1, MONO_METHOD_PARAMLIST); + + if (G_UNLIKELY (param_index == 0 && image->has_updates)) { + uint32_t count; + param_index = mono_metadata_update_get_method_params (image, mono_metadata_make_token (MONO_TABLE_METHOD, method_idx), &count); + if (!param_index) + return 0; + lastp = param_index + count; + } else { + /* lastp is the starting param index for the next method in the table, or + * one past the last row if this is the last method + */ + + if (method_idx < table_info_get_rows (methodt)) + lastp = mono_metadata_decode_row_col (methodt, method_idx, MONO_METHOD_PARAMLIST); + else + lastp = table_info_get_rows (&image->tables [MONO_TABLE_PARAM]) + 1; + } + + if (last_param_out) + *last_param_out = lastp; + + return param_index; +} diff --git a/src/mono/mono/metadata/reflection.c b/src/mono/mono/metadata/reflection.c index 0149b9d5c6a6da..52107a74225441 100644 --- a/src/mono/mono/metadata/reflection.c +++ b/src/mono/mono/metadata/reflection.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -1391,7 +1392,6 @@ get_default_param_value_blobs (MonoMethod *method, char **blobs, guint32 *types) MonoMethodSignature *methodsig = mono_method_signature_internal (method); MonoTableInfo *constt; - MonoTableInfo *methodt; MonoTableInfo *paramt; if (!methodsig->param_count) @@ -1411,22 +1411,16 @@ get_default_param_value_blobs (MonoMethod *method, char **blobs, guint32 *types) return; } - methodt = &image->tables [MONO_TABLE_METHOD]; paramt = &image->tables [MONO_TABLE_PARAM]; constt = &image->tables [MONO_TABLE_CONSTANT]; idx = mono_method_get_index (method); g_assert (idx != 0); - /* lastp is the starting param index for the next method in the table, or - * one past the last row if this is the last method - */ - /* FIXME: metadata-update : will this work with added methods ? */ - param_index = mono_metadata_decode_row_col (methodt, idx - 1, MONO_METHOD_PARAMLIST); - if (!mono_metadata_table_bounds_check (image, MONO_TABLE_METHOD, idx + 1)) - lastp = mono_metadata_decode_row_col (methodt, idx, MONO_METHOD_PARAMLIST); - else - lastp = table_info_get_rows (paramt) + 1; + param_index = mono_metadata_get_method_params (image, idx, &lastp); + + if (!param_index) + return; for (i = param_index; i < lastp; ++i) { guint32 paramseq;