Skip to content

Commit

Permalink
[mono][debugger] Support new hot reload features from runtime (#70697)
Browse files Browse the repository at this point in the history
* Support new hotreload features on mobile devices.

* Implementing support to add methods in hotreload on mobile devices

* Only invalidate code when we really have some change.

* Remove printf

* add/remove extra lines in eof

* Sharing string between the debugger and the managed get capabilities API
  • Loading branch information
thaystg authored Jun 22, 2022
1 parent 1ef5515 commit 6212eab
Show file tree
Hide file tree
Showing 13 changed files with 109 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,16 @@ public static void ApplyUpdate(Assembly assembly, ReadOnlySpan<byte> 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);
}
Expand Down
4 changes: 4 additions & 0 deletions src/mono/mono/component/debugger-agent.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
1 change: 1 addition & 0 deletions src/mono/mono/component/debugger-protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
21 changes: 20 additions & 1 deletion src/mono/mono/component/hot_reload-stub.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 *
Expand Down
50 changes: 44 additions & 6 deletions src/mono/mono/component/hot_reload.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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 *
Expand Down Expand Up @@ -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 ();
Expand Down Expand Up @@ -1374,8 +1383,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];
guint32 rows = table_info_get_rows (table_enclog);

Expand Down Expand Up @@ -1432,6 +1442,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 */
Expand All @@ -1441,6 +1452,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 */
Expand All @@ -1457,10 +1469,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 */
Expand All @@ -1476,6 +1490,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;
Expand All @@ -1487,6 +1502,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];
Expand Down Expand Up @@ -1532,6 +1548,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];
Expand All @@ -1557,6 +1574,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);
Expand Down Expand Up @@ -2503,8 +2521,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;
Expand Down Expand Up @@ -2532,7 +2550,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);
}
Expand Down Expand Up @@ -3112,3 +3130,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";
}
2 changes: 2 additions & 0 deletions src/mono/mono/component/hot_reload.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions src/mono/mono/metadata/class.c
Original file line number Diff line number Diff line change
Expand Up @@ -4985,6 +4985,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);
}

Expand Down
1 change: 1 addition & 0 deletions src/mono/mono/metadata/icall-decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
1 change: 1 addition & 0 deletions src/mono/mono/metadata/icall-def.h
Original file line number Diff line number Diff line change
Expand Up @@ -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, ())
Expand Down
9 changes: 9 additions & 0 deletions src/mono/mono/metadata/icall.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
3 changes: 3 additions & 0 deletions src/mono/mono/metadata/metadata-internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
12 changes: 12 additions & 0 deletions src/mono/mono/metadata/metadata-update.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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);
}
3 changes: 3 additions & 0 deletions src/mono/mono/metadata/metadata-update.h
Original file line number Diff line number Diff line change
Expand Up @@ -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__*/

0 comments on commit 6212eab

Please sign in to comment.