diff options
-rw-r--r-- | man/mono.1 | 13 | ||||
-rw-r--r-- | mono/mini/aot-compiler.c | 102 | ||||
-rw-r--r-- | mono/mini/method-to-ir.c | 8 | ||||
-rw-r--r-- | mono/mini/mini.h | 1 |
4 files changed, 121 insertions, 3 deletions
diff --git a/man/mono.1 b/man/mono.1 index 857f3913577..37e96045e56 100644 --- a/man/mono.1 +++ b/man/mono.1 @@ -192,6 +192,19 @@ Same for the llvm tools 'opt' and 'llc'. .TP .I stats Print various stats collected during AOT compilation. +.TP +.I readonly-value=namespace.typename.fieldname=type/value +Override the value of a static readonly field. Usually, during JIT +compilation, the static constructor is ran eagerly, so the value of +a static readonly field is known at compilation time and the compiler +can do a number of optimizations based on it. During AOT, instead, the static +constructor can't be ran, so this option can be used to set the value of such +a field and enable the same set of optimizations. +Type can be any of i1, i2, i4 for integers of the respective sizes (in bytes). +Note that signed/unsigned numbers do not matter here, just the storage size. +This option can be specified multiple times and it doesn't prevent the static +constructor for the type defining the field to execute with the usual rules +at runtime (hence possibly computing a different value for the field). .PP For more information about AOT, see: http://www.mono-project.com/AOT diff --git a/mono/mini/aot-compiler.c b/mono/mini/aot-compiler.c index d7e78d83cc7..f07368eb76c 100644 --- a/mono/mini/aot-compiler.c +++ b/mono/mini/aot-compiler.c @@ -92,6 +92,22 @@ #define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1))) #define ROUND_DOWN(VALUE,SIZE) ((VALUE) & ~((SIZE) - 1)) +/* predefined values for static readonly fields without needed to run the .cctor */ +typedef struct _ReadOnlyValue ReadOnlyValue; +struct _ReadOnlyValue { + ReadOnlyValue *next; + char *name; + int type; /* to be used later for typechecking to prevent user errors */ + union { + guint8 i1; + guint16 i2; + guint32 i4; + guint64 i8; + gpointer ptr; + } value; +}; +static ReadOnlyValue *readonly_values = NULL; + typedef struct MonoAotOptions { char *outfile; gboolean save_temps; @@ -4620,6 +4636,83 @@ str_begins_with (const char *str1, const char *str2) return strncmp (str1, str2, len) == 0; } +void* +mono_aot_readonly_field_override (MonoClassField *field) +{ + ReadOnlyValue *rdv; + for (rdv = readonly_values; rdv; rdv = rdv->next) { + char *p = rdv->name; + int len; + len = strlen (field->parent->name_space); + if (strncmp (p, field->parent->name_space, len)) + continue; + p += len; + if (*p++ != '.') + continue; + len = strlen (field->parent->name); + if (strncmp (p, field->parent->name, len)) + continue; + p += len; + if (*p++ != '.') + continue; + if (strcmp (p, field->name)) + continue; + switch (rdv->type) { + case MONO_TYPE_I1: + return &rdv->value.i1; + case MONO_TYPE_I2: + return &rdv->value.i2; + case MONO_TYPE_I4: + return &rdv->value.i4; + default: + break; + } + } + return NULL; +} + +static void +add_readonly_value (MonoAotOptions *opts, const char *val) +{ + ReadOnlyValue *rdv; + const char *fval; + const char *tval; + /* the format of val is: + * namespace.typename.fieldname=type/value + * type can be i1 for uint8/int8/boolean, i2 for uint16/int16/char, i4 for uint32/int32 + */ + fval = strrchr (val, '/'); + if (!fval) { + fprintf (stderr, "AOT : invalid format for readonly field '%s', missing /.\n", val); + exit (1); + } + tval = strrchr (val, '='); + if (!tval) { + fprintf (stderr, "AOT : invalid format for readonly field '%s', missing =.\n", val); + exit (1); + } + rdv = g_new0 (ReadOnlyValue, 1); + rdv->name = g_malloc0 (tval - val + 1); + memcpy (rdv->name, val, tval - val); + tval++; + fval++; + if (strncmp (tval, "i1", 2) == 0) { + rdv->value.i1 = atoi (fval); + rdv->type = MONO_TYPE_I1; + } else if (strncmp (tval, "i2", 2) == 0) { + rdv->value.i2 = atoi (fval); + rdv->type = MONO_TYPE_I2; + } else if (strncmp (tval, "i4", 2) == 0) { + rdv->value.i4 = atoi (fval); + rdv->type = MONO_TYPE_I4; + } else { + fprintf (stderr, "AOT : unsupported type for readonly field '%s'.\n", tval); + exit (1); + } + rdv->next = readonly_values; + readonly_values = rdv; +} + static void mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts) { @@ -4676,6 +4769,8 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts) opts->mtriple = g_strdup (arg + strlen ("mtriple=")); } else if (str_begins_with (arg, "llvm-path=")) { opts->llvm_path = g_strdup (arg + strlen ("llvm-path=")); + } else if (str_begins_with (arg, "readonly-value=")) { + add_readonly_value (opts, arg + strlen ("readonly-value=")); } else if (str_begins_with (arg, "info")) { printf ("AOT target setup: %s.\n", AOT_TARGET_STR); exit (0); @@ -4698,6 +4793,7 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts) printf (" nimt-trampolines=\n"); printf (" autoreg\n"); printf (" tool-prefix=\n"); + printf (" readonly-value=\n"); printf (" soft-debug\n"); printf (" print-skipped\n"); printf (" stats\n"); @@ -7209,6 +7305,12 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) /* AOT disabled */ +void* +mono_aot_readonly_field_override (MonoClassField *field) +{ + return NULL; +} + int mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) { diff --git a/mono/mini/method-to-ir.c b/mono/mini/method-to-ir.c index ebf6dabbf1a..c92b081ecd7 100644 --- a/mono/mini/method-to-ir.c +++ b/mono/mini/method-to-ir.c @@ -8965,15 +8965,17 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b } else { gboolean is_const = FALSE; MonoVTable *vtable = NULL; + gpointer addr = NULL; if (!context_used) { vtable = mono_class_vtable (cfg->domain, klass); CHECK_TYPELOAD (klass); } - if (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && - vtable->initialized && (ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY)) { - gpointer addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset; + if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) || + (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) { int ro_type = ftype->type; + if (!addr) + addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset; if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) { ro_type = mono_class_enum_basetype (ftype->data.klass)->type; } diff --git a/mono/mini/mini.h b/mono/mini/mini.h index e3d5e54e1c5..474cb4a0128 100644 --- a/mono/mini/mini.h +++ b/mono/mini/mini.h @@ -1836,6 +1836,7 @@ void mono_aot_set_make_unreadable (gboolean unreadable) MONO_INTERNAL; gboolean mono_aot_is_pagefault (void *ptr) MONO_INTERNAL; void mono_aot_handle_pagefault (void *ptr) MONO_INTERNAL; void mono_aot_register_jit_icall (const char *name, gpointer addr) MONO_INTERNAL; +void* mono_aot_readonly_field_override (MonoClassField *field) MONO_INTERNAL; /* This is an exported function */ void mono_aot_register_globals (gpointer *globals); |