Add an aot option to override the value of readonly static fields.
authorPaolo Molaro <lupus@oddwiz.org>
Mon, 27 Jun 2011 13:49:48 +0000 (15:49 +0200)
committerPaolo Molaro <lupus@oddwiz.org>
Mon, 27 Jun 2011 14:04:44 +0000 (16:04 +0200)
If the static constructor of a type has been run, the JIT can perform
some optimizations based on the actual value of static readonly fields.
This isn't possible in AOT mode, since the code won't be ran before compile
time: this option allows to set any number of static readonly fields to
a constant value so that the compiler can perform the same kind of
optimizations.

man/mono.1
mono/mini/aot-compiler.c
mono/mini/method-to-ir.c
mono/mini/mini.h

index 857f391357736181a888a92610ff16ae6303e4ad..37e96045e568c18fd12d3f69cf4a67516fc2751a 100644 (file)
@@ -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
index d7e78d83cc72e45233ad612c2dcbfe7041665a4c..f07368eb76c6853a48cff60affb99c035f86d80e 100644 (file)
 #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)
 {
index ebf6dabbf1ae6745e56c6aacb5ba36d55c71cf67..c92b081ecd79295dd94790b5b1cac0cef96e698e 100644 (file)
@@ -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;
                                        }
index e3d5e54e1c5c93095f291c11dc86554977c7e7a5..474cb4a0128ecadd5d325ac3653d3b3fd7ab871a 100644 (file)
@@ -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);