[sdb] Fix support for async debugging in optimized mode, roslyn generates valuetype...
[mono.git] / mono / mini / genmdesc.c
index e9746259d9ebe4e0261b48178700792f4870ee82..60ff683a9af013b5e752fba402e179e89eb425d5 100644 (file)
@@ -1,5 +1,6 @@
-/*
- * genmdesc: Generates the machine description
+/**
+ * \file
+ * Generates the machine description
  *
  * Authors:
  *   Paolo Molaro (lupus@ximian.com)
 #include <string.h>
 #include <mono/metadata/opcodes.h>
 
+#define MINI_OP(a,b,dest,src1,src2) b,
+#define MINI_OP3(a,b,dest,src1,src2,src3) b,
+/* keep in sync with the enum in mini.h */
+static const char* const
+opnames[] = {
+#include "mini-ops.h"
+};
+#undef MINI_OP
+#undef MINI_OP3
+
+/*
+ * Duplicate this from helpers.c, so the opcode name array can be omitted when 
+ * DISABLE_JIT is set.
+ */
+static const char*
+inst_name (int op) {
+       if (op >= OP_LOAD && op <= OP_LAST)
+               return opnames [op - OP_LOAD];
+       if (op < OP_LOAD)
+               return mono_opcode_name (op);
+       g_error ("unknown opcode name for %d", op);
+       return NULL;
+}
+
 typedef struct {
        int num;
        const char *name;
@@ -19,10 +44,20 @@ typedef struct {
        char spec [MONO_INST_MAX];
 } OpDesc;
 
+static int nacl = 0;
 static GHashTable *table;
+static GHashTable *template_table;
 
 #define eat_whitespace(s) while (*(s) && isspace (*(s))) s++;
 
+// Per spec isalnum() expects input in the range 0-255
+// and can misbehave if you pass in a signed char.
+static int
+isalnum_char(char c)
+{
+       return isalnum ((unsigned char)c);
+}
+
 static int
 load_file (const char *name) {
        FILE *f;
@@ -40,7 +75,7 @@ load_file (const char *name) {
         * The format of the lines are:
         * # comment
         * opcode: [dest:format] [src1:format] [src2:format] [flags:format] [clob:format] 
-        *      [cost:num] [res:format] [delay:num] [len:num]
+        *      [cost:num] [res:format] [delay:num] [len:num] [nacl:num]
         * format is a single letter that depends on the field
         * NOTE: no space between the field name and the ':'
         *
@@ -48,6 +83,9 @@ load_file (const char *name) {
         */
        line = 0;
        while ((str = fgets (buf, sizeof (buf), f))) {
+               gboolean is_template = FALSE;
+               gboolean nacl_length_set = FALSE;
+
                ++line;
                eat_whitespace (str);
                if (!str [0])
@@ -61,11 +99,16 @@ load_file (const char *name) {
                        g_error ("Invalid format at line %d in %s\n", line, name);
                *p++ = 0;
                eat_whitespace (p);
-               desc = g_hash_table_lookup (table, str);
-               if (!desc)
-                       g_error ("Invalid opcode '%s' at line %d in %s\n", str, line, name);
-               if (desc->desc)
-                       g_error ("Duplicated opcode '%s' at line %d in %s\n", str, line, name);
+               if (strcmp (str, "template") == 0) {
+                       is_template = TRUE;
+                       desc = g_new0 (OpDesc, 1);
+               } else {
+                       desc = (OpDesc *)g_hash_table_lookup (table, str);
+                       if (!desc)
+                               g_error ("Invalid opcode '%s' at line %d in %s\n", str, line, name);
+                       if (desc->desc)
+                               g_error ("Duplicated opcode %s at line %d in %s\n", str, line, name);
+               }
                desc->desc = g_strdup (p);
                desc->comment = g_strdup (comment->str);
                g_string_truncate (comment, 0);
@@ -79,6 +122,9 @@ load_file (const char *name) {
                        } else if (strncmp (p, "src2:", 5) == 0) {
                                desc->spec [MONO_INST_SRC2] = p [5];
                                p += 6;
+                       } else if (strncmp (p, "src3:", 5) == 0) {
+                               desc->spec [MONO_INST_SRC3] = p [5];
+                               p += 6;
                        } else if (strncmp (p, "clob:", 5) == 0) {
                                desc->spec [MONO_INST_CLOB] = p [5];
                                p += 6;
@@ -97,14 +143,63 @@ load_file (const char *name) {
                                p += 7;
                                */
                        } else if (strncmp (p, "len:", 4) == 0) {
+                               unsigned long size;
+                               char* endptr;
                                p += 4;
-                               desc->spec [MONO_INST_LEN] = strtoul (p, &p, 10);
+                               size = strtoul (p, &endptr, 10);
+                               if (size == 0 && p == endptr)
+                                       g_error ("Invalid length '%s' at line %d in %s\n", p, line, name);
+                               p = endptr;
+                               if (!nacl_length_set) {
+                                       desc->spec [MONO_INST_LEN] = size;
+                               }
+                       } else if (strncmp (p, "nacl:", 5) == 0) {
+                               unsigned long size;
+                               p += 5;
+                               size = strtoul (p, &p, 10);
+                               if (nacl) {
+                                       desc->spec [MONO_INST_LEN] = size;
+                                       nacl_length_set = TRUE;
+                               }
+                       } else if (strncmp (p, "template:", 9) == 0) {
+                               char *tname;
+                               int i;
+                               OpDesc *tdesc;
+                               p += 9;
+                               tname = p;
+                               while (*p && isalnum_char (*p)) ++p;
+                               *p++ = 0;
+                               tdesc = (OpDesc *)g_hash_table_lookup (template_table, tname);
+                               if (!tdesc)
+                                       g_error ("Invalid template name %s at '%s' at line %d in %s\n", tname, p, line, name);
+                               for (i = 0; i < MONO_INST_MAX; ++i) {
+                                       if (desc->spec [i])
+                                               g_error ("The template overrides any previous value set at line %d in %s\n", line, name);
+                               }
+                               memcpy (desc->spec, tdesc->spec, sizeof (desc->spec));
+                       } else if (strncmp (p, "name:", 5) == 0) {
+                               char *tname;
+                               if (!is_template)
+                                       g_error ("name tag only valid in templates at '%s' at line %d in %s\n", p, line, name);
+                               if (desc->name)
+                                       g_error ("Duplicated name tag in template %s at '%s' at line %d in %s\n", desc->name, p, line, name);
+                               p += 5;
+                               tname = p;
+                               while (*p && isalnum_char (*p)) ++p;
+                               *p++ = 0;
+                               if (g_hash_table_lookup (template_table, tname))
+                                       g_error ("Duplicated template %s at line %d in %s\n", tname, line, name);
+                               desc->name = g_strdup (tname);
+                               g_hash_table_insert (template_table, (void*)desc->name, desc);
                        } else {
                                g_error ("Parse error at '%s' at line %d in %s\n", p, line, name);
                        }
                        eat_whitespace (p);
                }
+               if (is_template && !desc->name)
+                       g_error ("Template without name at line %d in %s\n", line, name);
        }
+       g_string_free (comment,TRUE);
        fclose (f);
        return 0;
 }
@@ -116,31 +211,24 @@ init_table (void) {
        int i;
        OpDesc *desc;
 
+       template_table = g_hash_table_new (g_str_hash, g_str_equal);
        table = g_hash_table_new (g_str_hash, g_str_equal);
 
        opcodes = g_new0 (OpDesc, OP_LAST);
-#ifndef MONO_ARCH_ENABLE_NORMALIZE_OPCODES
-       for (i = 0; i < MONO_CEE_LAST; ++i) {
-               desc = opcodes + i;
-               desc->num = i;
-               desc->name = mono_inst_name (i);
-               g_hash_table_insert (table, (char *)desc->name, desc);
-       }
-#endif
        for (i = OP_LOAD; i < OP_LAST; ++i) {
                desc = opcodes + i;
                desc->num = i;
-               desc->name = mono_inst_name (i);
+               desc->name = inst_name (i);
                g_hash_table_insert (table, (char *)desc->name, desc);
        }
 }
 
 static void
 output_char (FILE *f, char c) {
-       if (isalnum (c))
+       if (isalnum_char (c))
                fprintf (f, "%c", c);
        else
-               fprintf (f, "\\x%x\" \"", c);
+               fprintf (f, "\\x%x\" \"", (guint8)c);
 }
 
 static void
@@ -155,15 +243,15 @@ build_table (const char *fname, const char *name) {
        if (!(f = fopen (fname, "w")))
                g_error ("Cannot open file '%s'", fname);
        fprintf (f, "/* File automatically generated by genmdesc, don't change */\n\n");
-       fprintf (f, "const char %s [] = {\n", name);
+       fprintf (f, "const char mono_%s [] = {\n", name);
        fprintf (f, "\t\"");
        for (j = 0; j < MONO_INST_MAX; ++j)
                fprintf (f, "\\x0");
        fprintf (f, "\"\t/* null entry */\n");
        idx = 1;
-       g_string_append_printf (idx_array, "const guint16 %s_idx [] = {\n", name);
+       g_string_append_printf (idx_array, "const guint16 mono_%s_idx [] = {\n", name);
 
-       for (i = 0; i < OP_LAST; ++i) {
+       for (i = OP_LOAD; i < OP_LAST; ++i) {
                desc = opcodes + i;
                if (!desc->desc)
                        g_string_append_printf (idx_array, "\t0,\t/* %s */\n", desc->name ? desc->name : "");
@@ -219,21 +307,28 @@ int
 main (int argc, char* argv [])
 {
        init_table ();
-       switch (argc) {
-       case 2:
+       if (argc == 2) {
                /* useful to get a new file when some opcodes are added: looses the comments, though */
                load_file (argv [1]);
                dump ();
-               break;
-       case 4:
-               load_file (argv [1]);
-               build_table (argv [2], argv [3]);
-               break;
-       default:
+       } else if (argc < 4) {
                g_print ("Usage: genmdesc arguments\n");
-               g_print ("\tgenmdesc desc             Output to stdout the description file.\n");
-               g_print ("\tgenmdesc desc output name Write to output the description in a table named 'name'.\n");
+               g_print ("\tgenmdesc desc     Output to stdout the description file.\n");
+               g_print ("\tgenmdesc [--nacl] output name desc [desc1...]\n"
+                       "                     Write to output the description in a table named 'name',\n"
+                       "                     use --nacl to generate Google NativeClient code\n");
                return 1;
+       } else {
+               int i = 3;
+               if (strcmp (argv [1], "--nacl") == 0) {
+                       nacl = 1;
+                       i++;
+               }
+               
+               for (; i < argc; ++i)
+                       load_file (argv [i]);
+               
+               build_table (argv [1 + nacl], argv [2 + nacl]);
        }
        return 0;
 }