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;