diff --git a/src/mono/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs b/src/mono/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs index d70267febc66cb..ba51ce0741def6 100644 --- a/src/mono/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs +++ b/src/mono/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs @@ -55,13 +55,16 @@ public static void ApplyUpdate(Assembly assembly, ReadOnlySpan metadataDel private static string InitializeApplyUpdateCapabilities() { - const string caps = "Baseline AddMethodToExistingType AddStaticFieldToExistingType NewTypeDefinition"; - return ApplyUpdateEnabled(justComponentCheck: 1) != 0 ? caps : string.Empty ; + string caps = GetApplyUpdateCapabilities(); + return ApplyUpdateEnabled(justComponentCheck: 1) != 0 ? caps : string.Empty; } [MethodImpl (MethodImplOptions.InternalCall)] private static extern int ApplyUpdateEnabled (int justComponentCheck); + [MethodImpl (MethodImplOptions.InternalCall)] + private static extern string GetApplyUpdateCapabilities(); + [MethodImpl (MethodImplOptions.InternalCall)] private static extern unsafe void ApplyUpdate_internal (IntPtr base_assm, byte* dmeta_bytes, int dmeta_length, byte *dil_bytes, int dil_length, byte *dpdb_bytes, int dpdb_length); } diff --git a/src/mono/mono/component/debugger-agent.c b/src/mono/mono/component/debugger-agent.c index 78b83e0549cd5c..64ce87be75ff9a 100644 --- a/src/mono/mono/component/debugger-agent.c +++ b/src/mono/mono/component/debugger-agent.c @@ -7051,6 +7051,10 @@ vm_commands (int command, int id, guint8 *p, guint8 *end, Buffer *buf) buffer_add_moduleid (buf, mono_get_root_domain (), assembly->image); break; } + case MDBGPROT_CMD_GET_ENC_CAPABILITIES: { + buffer_add_string (buf, mono_enc_capabilities ()); + break; + } default: return ERR_NOT_IMPLEMENTED; } diff --git a/src/mono/mono/component/debugger-protocol.h b/src/mono/mono/component/debugger-protocol.h index 70753b7ec70111..6433a50a8458c3 100644 --- a/src/mono/mono/component/debugger-protocol.h +++ b/src/mono/mono/component/debugger-protocol.h @@ -38,6 +38,7 @@ typedef enum { MDBGPROT_CMD_GET_ASSEMBLY_BY_NAME = 18, MDBGPROT_CMD_GET_MODULE_BY_GUID = 19, MDBGPROT_CMD_GET_ASSEMBLY_BYTES = 20, //wasm specific + MDBGPROT_CMD_GET_ENC_CAPABILITIES = 21 } MdbgProtCmdVM; typedef enum { diff --git a/src/mono/mono/component/hot_reload-stub.c b/src/mono/mono/component/hot_reload-stub.c index 630043c6be207b..e97e90499e3534 100644 --- a/src/mono/mono/component/hot_reload-stub.c +++ b/src/mono/mono/component/hot_reload-stub.c @@ -104,6 +104,12 @@ hot_reload_stub_added_fields_iter (MonoClass *klass, gboolean lazy, gpointer *it static uint32_t hot_reload_get_num_fields_added (MonoClass *klass); +static uint32_t +hot_reload_get_num_methods_added (MonoClass *klass); + +static const char * +hot_reload_get_capabilities (void); + static MonoComponentHotReload fn_table = { { MONO_COMPONENT_ITF_VERSION, &hot_reload_stub_available }, &hot_reload_stub_set_fastpath_data, @@ -134,7 +140,9 @@ static MonoComponentHotReload fn_table = { &hot_reload_stub_get_typedef_skeleton_events, &hot_reload_stub_added_methods_iter, &hot_reload_stub_added_fields_iter, - &hot_reload_get_num_fields_added + &hot_reload_get_num_fields_added, + &hot_reload_get_num_methods_added, + &hot_reload_get_capabilities }; static bool @@ -323,6 +331,17 @@ hot_reload_get_num_fields_added (MonoClass *klass) return 0; } +static uint32_t +hot_reload_get_num_methods_added (MonoClass *klass) +{ + return 0; +} + +static const char * +hot_reload_get_capabilities (void) +{ + return ""; +} MONO_COMPONENT_EXPORT_ENTRYPOINT MonoComponentHotReload * diff --git a/src/mono/mono/component/hot_reload.c b/src/mono/mono/component/hot_reload.c index aafca1e85d0676..da27a059117a22 100644 --- a/src/mono/mono/component/hot_reload.c +++ b/src/mono/mono/component/hot_reload.c @@ -138,6 +138,12 @@ hot_reload_added_fields_iter (MonoClass *klass, gboolean lazy, gpointer *iter); static uint32_t hot_reload_get_num_fields_added (MonoClass *klass); +static uint32_t +hot_reload_get_num_methods_added (MonoClass *klass); + +static const char * +hot_reload_get_capabilities (void); + static MonoClassMetadataUpdateField * metadata_update_field_setup_basic_info_and_resolve (MonoImage *image_base, BaselineInfo *base_info, uint32_t generation, DeltaInfo *delta_info, MonoClass *parent_klass, uint32_t fielddef_token, uint32_t field_flags, MonoError *error); @@ -172,6 +178,8 @@ static MonoComponentHotReload fn_table = { &hot_reload_added_methods_iter, &hot_reload_added_fields_iter, &hot_reload_get_num_fields_added, + &hot_reload_get_num_methods_added, + &hot_reload_get_capabilities }; MonoComponentHotReload * @@ -738,11 +746,12 @@ hot_reload_wait_for_update (uint32_t timeout_ms) } static void -hot_reload_update_publish (MonoAssemblyLoadContext *alc, uint32_t generation) +hot_reload_update_publish (MonoAssemblyLoadContext *alc, uint32_t generation, gboolean should_invalidate_transformed_code) { g_assert (update_published < generation && generation <= update_alloc_frontier); /* TODO: wait for all threads that are using old metadata to update. */ - hot_reload_update_published_invoke_hook (alc, generation); + if (should_invalidate_transformed_code) + hot_reload_update_published_invoke_hook (alc, generation); update_published = update_alloc_frontier; mono_memory_write_barrier (); publish_unlock (); @@ -1375,8 +1384,9 @@ prepare_mutated_rows (const MonoTableInfo *table_enclog, MonoImage *image_base, * function will fail and the metadata update should be aborted. This should * run before anything in the metadata world is updated. */ static gboolean -apply_enclog_pass1 (MonoImage *image_base, MonoImage *image_dmeta, DeltaInfo *delta_info, gconstpointer dil_data, uint32_t dil_length, MonoError *error) +apply_enclog_pass1 (MonoImage *image_base, MonoImage *image_dmeta, DeltaInfo *delta_info, gconstpointer dil_data, uint32_t dil_length, gboolean *should_invalidate_transformed_code, MonoError *error) { + *should_invalidate_transformed_code = false; MonoTableInfo *table_enclog = &image_dmeta->tables [MONO_TABLE_ENCLOG]; int rows = table_info_get_rows (table_enclog); @@ -1433,6 +1443,7 @@ apply_enclog_pass1 (MonoImage *image_base, MonoImage *image_dmeta, DeltaInfo *de /* okay, supported */ break; case MONO_TABLE_METHOD: + *should_invalidate_transformed_code = true; if (func_code == ENC_FUNC_ADD_PARAM) continue; /* ok, allowed */ /* handled above */ @@ -1442,6 +1453,7 @@ apply_enclog_pass1 (MonoImage *image_base, MonoImage *image_dmeta, DeltaInfo *de g_assert (func_code == ENC_FUNC_DEFAULT); break; case MONO_TABLE_PROPERTYMAP: { + *should_invalidate_transformed_code = true; if (func_code == ENC_FUNC_ADD_PROPERTY) { g_assert (i + 1 < rows); i++; /* skip the next record */ @@ -1458,10 +1470,12 @@ apply_enclog_pass1 (MonoImage *image_base, MonoImage *image_dmeta, DeltaInfo *de } case MONO_TABLE_PROPERTY: { /* ok */ + *should_invalidate_transformed_code = true; g_assert (func_code == ENC_FUNC_DEFAULT); break; } case MONO_TABLE_EVENTMAP: { + *should_invalidate_transformed_code = true; if (func_code == ENC_FUNC_ADD_EVENT) { g_assert (i + 1 < rows); i++; /* skip the next record */ @@ -1477,6 +1491,7 @@ apply_enclog_pass1 (MonoImage *image_base, MonoImage *image_dmeta, DeltaInfo *de break; } case MONO_TABLE_METHODSEMANTICS: { + *should_invalidate_transformed_code = true; if (is_addition) { /* new rows are fine */ break; @@ -1488,6 +1503,7 @@ apply_enclog_pass1 (MonoImage *image_base, MonoImage *image_dmeta, DeltaInfo *de } } case MONO_TABLE_CUSTOMATTRIBUTE: { + *should_invalidate_transformed_code = true; if (!is_addition) { /* modifying existing rows is ok, as long as the parent and ctor are the same */ guint32 ca_upd_cols [MONO_CUSTOM_ATTR_SIZE]; @@ -1533,6 +1549,7 @@ apply_enclog_pass1 (MonoImage *image_base, MonoImage *image_dmeta, DeltaInfo *de } } case MONO_TABLE_PARAM: { + *should_invalidate_transformed_code = true; if (!is_addition) { /* We only allow modifications where the parameter name doesn't change. */ uint32_t base_param [MONO_PARAM_SIZE]; @@ -1558,6 +1575,7 @@ apply_enclog_pass1 (MonoImage *image_base, MonoImage *image_dmeta, DeltaInfo *de break; /* added a row. ok */ } case MONO_TABLE_TYPEDEF: { + *should_invalidate_transformed_code = true; if (func_code == ENC_FUNC_ADD_METHOD) { /* next record should be a MONO_TABLE_METHOD addition (func == default) */ g_assert (i + 1 < rows); @@ -2504,8 +2522,8 @@ hot_reload_apply_changes (int origin, MonoImage *image_base, gconstpointer dmeta mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_METADATA_UPDATE, "Populated mutated tables for delta image %p", image_dmeta); - - if (!apply_enclog_pass1 (image_base, image_dmeta, delta_info, dil_bytes, dil_length, error)) { + gboolean should_invalidate_transformed_code = false; + if (!apply_enclog_pass1 (image_base, image_dmeta, delta_info, dil_bytes, dil_length, &should_invalidate_transformed_code, error)) { mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_METADATA_UPDATE, "Error on sanity-checking delta image to base=%s, due to: %s", basename, mono_error_get_message (error)); hot_reload_update_cancel (generation); return; @@ -2533,7 +2551,7 @@ hot_reload_apply_changes (int origin, MonoImage *image_base, gconstpointer dmeta pass2_context_destroy (&pass2ctx); MonoAssemblyLoadContext *alc = mono_image_get_alc (image_base); - hot_reload_update_publish (alc, generation); + hot_reload_update_publish (alc, generation, should_invalidate_transformed_code); mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_METADATA_UPDATE, ">>> EnC delta for base=%s (generation %d) applied", basename, generation); } @@ -3113,3 +3131,23 @@ hot_reload_get_num_fields_added (MonoClass *klass) return 0; return g_slist_length (info->added_fields); } + +static uint32_t +hot_reload_get_num_methods_added (MonoClass *klass) +{ + uint32_t count = 0; + GSList *members = hot_reload_get_added_members (klass); + for (GSList *ptr = members; ptr; ptr = ptr->next) { + uint32_t token = GPOINTER_TO_UINT(ptr->data); + if (mono_metadata_token_table (token) != MONO_TABLE_METHOD) + continue; + count++; + } + return count; +} + +static const char * +hot_reload_get_capabilities (void) +{ + return "Baseline AddMethodToExistingType AddStaticFieldToExistingType NewTypeDefinition ChangeCustomAttributes"; +} diff --git a/src/mono/mono/component/hot_reload.h b/src/mono/mono/component/hot_reload.h index 5a5d00f5aecb67..f7627245583af5 100644 --- a/src/mono/mono/component/hot_reload.h +++ b/src/mono/mono/component/hot_reload.h @@ -46,6 +46,8 @@ typedef struct _MonoComponentHotReload { MonoMethod* (*added_methods_iter) (MonoClass *klass, gpointer *iter); MonoClassField* (*added_fields_iter) (MonoClass *klass, gboolean lazy, gpointer *iter); uint32_t (*get_num_fields_added) (MonoClass *klass); + uint32_t (*get_num_methods_added) (MonoClass *klass); + const char* (*get_capabilities) (void); } MonoComponentHotReload; MONO_COMPONENT_EXPORT_ENTRYPOINT diff --git a/src/mono/mono/metadata/class.c b/src/mono/mono/metadata/class.c index c7f0960fef0dab..560624cbe68846 100644 --- a/src/mono/mono/metadata/class.c +++ b/src/mono/mono/metadata/class.c @@ -4986,6 +4986,10 @@ mono_class_num_fields (MonoClass *klass) int mono_class_num_methods (MonoClass *klass) { + MonoImage *image = m_class_get_image (klass); + if (G_UNLIKELY (image->has_updates)) { + return mono_class_get_method_count (klass) + mono_metadata_update_get_num_methods_added (klass); + } return mono_class_get_method_count (klass); } diff --git a/src/mono/mono/metadata/icall-decl.h b/src/mono/mono/metadata/icall-decl.h index 928bf83b3cc397..aae66d6dad11ff 100644 --- a/src/mono/mono/metadata/icall-decl.h +++ b/src/mono/mono/metadata/icall-decl.h @@ -185,6 +185,7 @@ ICALL_EXPORT void ves_icall_System_Runtime_Intrinsics_X86_X86Base___cpuidex (int ICALL_EXPORT void ves_icall_AssemblyExtensions_ApplyUpdate (MonoAssembly *assm, gconstpointer dmeta_bytes, int32_t dmeta_len, gconstpointer dil_bytes, int32_t dil_len, gconstpointer dpdb_bytes, int32_t dpdb_len); ICALL_EXPORT gint32 ves_icall_AssemblyExtensions_ApplyUpdateEnabled (gint32 just_component_check); +ICALL_EXPORT gint32 ves_icall_AssemblyExtensions_ApplyUpdateEnabled (gint32 just_component_check); ICALL_EXPORT guint32 ves_icall_RuntimeTypeHandle_GetCorElementType (MonoQCallTypeHandle type_handle); diff --git a/src/mono/mono/metadata/icall-def.h b/src/mono/mono/metadata/icall-def.h index 47395d1809e40c..5f47166ab1a646 100644 --- a/src/mono/mono/metadata/icall-def.h +++ b/src/mono/mono/metadata/icall-def.h @@ -331,6 +331,7 @@ HANDLES(FILEDI_2, "internal_from_handle_type", ves_icall_System_Reflection_Field ICALL_TYPE(MDUP, "System.Reflection.Metadata.MetadataUpdater", MDUP_1) NOHANDLES(ICALL(MDUP_1, "ApplyUpdateEnabled", ves_icall_AssemblyExtensions_ApplyUpdateEnabled)) NOHANDLES(ICALL(MDUP_2, "ApplyUpdate_internal", ves_icall_AssemblyExtensions_ApplyUpdate)) +HANDLES(MDUP_3, "GetApplyUpdateCapabilities", ves_icall_AssemblyExtensions_GetApplyUpdateCapabilities, MonoString, 0, ()) ICALL_TYPE(MBASE, "System.Reflection.MethodBase", MBASE_1) HANDLES(MBASE_1, "GetCurrentMethod", ves_icall_GetCurrentMethod, MonoReflectionMethod, 0, ()) diff --git a/src/mono/mono/metadata/icall.c b/src/mono/mono/metadata/icall.c index e86a99cde62ffc..dcc153aa907385 100644 --- a/src/mono/mono/metadata/icall.c +++ b/src/mono/mono/metadata/icall.c @@ -5334,6 +5334,15 @@ ves_icall_AssemblyExtensions_ApplyUpdate (MonoAssembly *assm, mono_error_set_pending_exception (error); } +MonoStringHandle +ves_icall_AssemblyExtensions_GetApplyUpdateCapabilities (MonoError *error) +{ + MonoStringHandle s; + s = mono_string_new_handle (mono_enc_capabilities (), error); + return_val_if_nok (error, NULL_HANDLE_STRING); + return s; +} + gint32 ves_icall_AssemblyExtensions_ApplyUpdateEnabled (gint32 just_component_check) { // if just_component_check is true, we only care whether the hot_reload component is enabled, diff --git a/src/mono/mono/metadata/metadata-internals.h b/src/mono/mono/metadata/metadata-internals.h index 973dcded724ba5..5c6ea98fca365c 100644 --- a/src/mono/mono/metadata/metadata-internals.h +++ b/src/mono/mono/metadata/metadata-internals.h @@ -816,6 +816,9 @@ enum MonoEnCDeltaOrigin { MONO_COMPONENT_API void mono_image_load_enc_delta (int delta_origin, MonoImage *base_image, gconstpointer dmeta, uint32_t dmeta_len, gconstpointer dil, uint32_t dil_len, gconstpointer dpdb, uint32_t dpdb_len, MonoError *error); +MONO_COMPONENT_API const char* +mono_enc_capabilities (void); + gboolean mono_image_load_cli_header (MonoImage *image, MonoCLIImageInfo *iinfo); diff --git a/src/mono/mono/metadata/metadata-update.c b/src/mono/mono/metadata/metadata-update.c index 490c91779f1819..0bfb211c6f0caa 100644 --- a/src/mono/mono/metadata/metadata-update.c +++ b/src/mono/mono/metadata/metadata-update.c @@ -76,6 +76,12 @@ mono_image_load_enc_delta (int origin, MonoImage *base_image, gconstpointer dmet } } +const char* +mono_enc_capabilities (void) +{ + return mono_component_hot_reload ()->get_capabilities(); +} + static void mono_image_close_except_pools_all_list (GList *images) { @@ -217,4 +223,10 @@ uint32_t mono_metadata_update_get_num_fields_added (MonoClass *klass) { return mono_component_hot_reload()->get_num_fields_added (klass); +} + +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 diff --git a/src/mono/mono/metadata/metadata-update.h b/src/mono/mono/metadata/metadata-update.h index 85d94e0dae4995..05cc4e5c80316c 100644 --- a/src/mono/mono/metadata/metadata-update.h +++ b/src/mono/mono/metadata/metadata-update.h @@ -90,4 +90,7 @@ mono_metadata_update_added_fields_iter (MonoClass *klass, gboolean lazy, gpointe uint32_t mono_metadata_update_get_num_fields_added (MonoClass *klass); + +uint32_t +mono_metadata_update_get_num_methods_added (MonoClass *klass); #endif /*__MONO_METADATA_UPDATE_H__*/