Skip to content

Add new Mono embedding API to consume binary runtimeconfig format #49740

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Mar 22, 2021
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 121 additions & 9 deletions src/mono/mono/metadata/appdomain.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,12 @@ typedef struct
static gboolean no_exec = FALSE;

static int n_appctx_props;
static gunichar2 **appctx_keys;
static gunichar2 **appctx_values;
static char **appctx_keys;
static char **appctx_values;

static MonovmRuntimeConfigArguments *runtime_config_arg;
static MonovmRuntimeConfigArgumentsCleanup runtime_config_cleanup_fn;
static gpointer runtime_config_user_data;

static const char *
mono_check_corlib_version_internal (void);
Expand Down Expand Up @@ -122,6 +126,12 @@ add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
static void
add_assembly_to_alc (MonoAssemblyLoadContext *alc, MonoAssembly *ass);

static const char *
runtimeconfig_json_get_buffer (MonovmRuntimeConfigArguments *arg, MonoFileMap **file_map, gpointer *buf_handle);

static void
runtimeconfig_json_read_props (const char *ptr, const char **endp, int nprops, gunichar2 **dest_keys, gunichar2 **dest_values);

static MonoLoadFunc load_function = NULL;

/* Lazy class loading functions */
Expand Down Expand Up @@ -1239,15 +1249,23 @@ void
mono_runtime_register_appctx_properties (int nprops, const char **keys, const char **values)
{
n_appctx_props = nprops;
appctx_keys = g_new0 (gunichar2*, nprops);
appctx_values = g_new0 (gunichar2*, nprops);
appctx_keys = g_new0 (char *, n_appctx_props);
appctx_values = g_new0 (char *, n_appctx_props);

for (int i = 0; i < nprops; ++i) {
appctx_keys [i] = g_utf8_to_utf16 (keys [i], strlen (keys [i]), NULL, NULL, NULL);
appctx_values [i] = g_utf8_to_utf16 (values [i], strlen (values [i]), NULL, NULL, NULL);
appctx_keys [i] = g_strdup (keys [i]);
appctx_values [i] = g_strdup (values [i]);
}
}

void
mono_runtime_register_runtimeconfig_json_properties (MonovmRuntimeConfigArguments *arg, MonovmRuntimeConfigArgumentsCleanup cleanup_fn, void *user_data)
{
runtime_config_arg = arg;
runtime_config_cleanup_fn = cleanup_fn;
runtime_config_user_data = user_data;
}

static GENERATE_GET_CLASS_WITH_CACHE (appctx, "System", "AppContext")

/* Install properties into AppContext */
Expand All @@ -1256,27 +1274,121 @@ mono_runtime_install_appctx_properties (void)
{
ERROR_DECL (error);
gpointer args [3];
int n_runtimeconfig_json_props = 0;
int n_combined_props;
gunichar2 **combined_keys;
gunichar2 **combined_values;
MonoFileMap *runtimeconfig_json_map = NULL;
gpointer runtimeconfig_json_map_handle = NULL;
const char *buffer_start = runtimeconfig_json_get_buffer (runtime_config_arg, &runtimeconfig_json_map, &runtimeconfig_json_map_handle);
const char *buffer = buffer_start;

MonoMethod *setup = mono_class_get_method_from_name_checked (mono_class_get_appctx_class (), "Setup", 3, 0, error);
g_assert (setup);

// FIXME: TRUSTED_PLATFORM_ASSEMBLIES is very large

// Combine and convert properties
if (buffer)
n_runtimeconfig_json_props = mono_metadata_decode_value (buffer, &buffer);

n_combined_props = n_appctx_props + n_runtimeconfig_json_props;
combined_keys = g_new0 (gunichar2 *, n_combined_props);
combined_values = g_new0 (gunichar2 *, n_combined_props);

for (int i = 0; i < n_appctx_props; ++i) {
combined_keys [i] = g_utf8_to_utf16 (appctx_keys [i], -1, NULL, NULL, NULL);
combined_values [i] = g_utf8_to_utf16 (appctx_values [i], -1, NULL, NULL, NULL);
}

runtimeconfig_json_read_props (buffer, &buffer, n_runtimeconfig_json_props, combined_keys + n_appctx_props, combined_values + n_appctx_props);

/* internal static unsafe void Setup(char** pNames, char** pValues, int count) */
args [0] = appctx_keys;
args [1] = appctx_values;
args [2] = &n_appctx_props;
args [0] = combined_keys;
args [1] = combined_values;
args [2] = &n_combined_props;

mono_runtime_invoke_checked (setup, NULL, args, error);
mono_error_assert_ok (error);

if (runtimeconfig_json_map != NULL) {
mono_file_unmap ((gpointer)buffer_start, runtimeconfig_json_map_handle);
mono_file_map_close (runtimeconfig_json_map);
}

// Call user defined cleanup function
if (runtime_config_cleanup_fn)
(*runtime_config_cleanup_fn) (runtime_config_arg, runtime_config_user_data);

/* No longer needed */
for (int i = 0; i < n_combined_props; ++i) {
g_free (combined_keys [i]);
g_free (combined_values [i]);
}
g_free (combined_keys);
g_free (combined_values);
for (int i = 0; i < n_appctx_props; ++i) {
g_free (appctx_keys [i]);
g_free (appctx_values [i]);
}
g_free (appctx_keys);
g_free (appctx_values);

appctx_keys = NULL;
appctx_values = NULL;
if (runtime_config_arg) {
runtime_config_arg = NULL;
runtime_config_cleanup_fn = NULL;
runtime_config_user_data = NULL;
}
}

static const char *
runtimeconfig_json_get_buffer (MonovmRuntimeConfigArguments *arg, MonoFileMap **file_map, gpointer *buf_handle)
{
if (arg != NULL) {
switch (arg->kind) {
case 0: {
char *buffer = NULL;
guint64 file_len = 0;

*file_map = mono_file_map_open (arg->runtimeconfig.name.path);
g_assert (*file_map);
file_len = mono_file_map_size (*file_map);
g_assert (file_len > 0);
buffer = (char *)mono_file_map (file_len, MONO_MMAP_READ|MONO_MMAP_PRIVATE, mono_file_map_fd (*file_map), 0, buf_handle);
g_assert (buffer);
return buffer;
}
case 1: {
*file_map = NULL;
*buf_handle = NULL;
return arg->runtimeconfig.data.data;
}
default:
g_assert_not_reached ();
}
}

*file_map = NULL;
*buf_handle = NULL;
return NULL;
}

static void
runtimeconfig_json_read_props (const char *ptr, const char **endp, int nprops, gunichar2 **dest_keys, gunichar2 **dest_values)
{
for (int i = 0; i < nprops; ++i) {
int str_len;

str_len = mono_metadata_decode_value (ptr, &ptr);
dest_keys [i] = g_utf8_to_utf16 (ptr, str_len, NULL, NULL, NULL);
ptr += str_len;

str_len = mono_metadata_decode_value (ptr, &ptr);
dest_values [i] = g_utf8_to_utf16 (ptr, str_len, NULL, NULL, NULL);
ptr += str_len;
}

*endp = ptr;
}
4 changes: 4 additions & 0 deletions src/mono/mono/metadata/domain-internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <mono/metadata/loader-internals.h>
#include <mono/metadata/mempool-internals.h>
#include <mono/metadata/handle-decl.h>
#include <mono/mini/mono-private-unstable.h>

G_BEGIN_DECLS

Expand Down Expand Up @@ -449,6 +450,9 @@ mono_domain_get_assemblies (MonoDomain *domain);
void
mono_runtime_register_appctx_properties (int nprops, const char **keys, const char **values);

void
mono_runtime_register_runtimeconfig_json_properties (MonovmRuntimeConfigArguments *arg, MonovmRuntimeConfigArgumentsCleanup cleanup_fn, void *user_data);

void
mono_runtime_install_appctx_properties (void);

Expand Down
18 changes: 18 additions & 0 deletions src/mono/mono/mini/mono-private-unstable.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,21 @@
#include <mono/utils/mono-publib.h>
#include <mono/metadata/image.h>

typedef struct {
uint32_t kind; // 0 = Path of runtimeconfig.blob, 1 = pointer to image data, >= 2 undefined
union {
struct {
const char *path;
} name;
struct {
const char *data;
uint32_t data_len;
} data;
} runtimeconfig;
} MonovmRuntimeConfigArguments;

typedef void (*MonovmRuntimeConfigArgumentsCleanup) (MonovmRuntimeConfigArguments *args, void *user_data);

/* These are used to load the AOT data for aot images compiled with MONO_AOT_FILE_FLAG_SEPARATE_DATA */
/*
* Return the AOT data for ASSEMBLY. SIZE is the size of the data. OUT_HANDLE should be set to a handle which is later
Expand All @@ -29,6 +44,9 @@ mono_install_load_aot_data_hook (MonoLoadAotDataFunc load_func, MonoFreeAotDataF
MONO_API int
monovm_initialize (int propertyCount, const char **propertyKeys, const char **propertyValues);

MONO_API int
monovm_runtimeconfig_initialize (MonovmRuntimeConfigArguments *arg, MonovmRuntimeConfigArgumentsCleanup cleanup_fn, void* user_data);

//#ifdef HOST_WASM
typedef void* (*MonoWasmGetNativeToInterpTramp) (MonoMethod *method, void *extra_arg);

Expand Down
8 changes: 8 additions & 0 deletions src/mono/mono/mini/monovm.c
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,14 @@ monovm_initialize (int propertyCount, const char **propertyKeys, const char **pr
return 0;
}

// Initialize monovm with properties set by runtimeconfig.json. Primarily used by mobile targets.
int
monovm_runtimeconfig_initialize (MonovmRuntimeConfigArguments *arg, MonovmRuntimeConfigArgumentsCleanup cleanup_fn, void *user_data)
{
mono_runtime_register_runtimeconfig_json_properties (arg, cleanup_fn, user_data);
return 0;
}

int
monovm_execute_assembly (int argc, const char **argv, const char *managedAssemblyPath, unsigned int *exitCode)
{
Expand Down