Add a cache for virtual generic thunks to avoid freeing those created by AOT.
[mono-project/dkf.git] / mono / mini / genmdesc.c
blob0c942afabafd3a8f47fb18c3352781254e16c441
1 /*
2 * genmdesc: Generates the machine description
4 * Authors:
5 * Paolo Molaro (lupus@ximian.com)
7 * (C) 2003 Ximian, Inc.
8 */
9 #include "mini.h"
10 #include <ctype.h>
11 #include <string.h>
12 #include <mono/metadata/opcodes.h>
14 #define MINI_OP(a,b,dest,src1,src2) b,
15 #define MINI_OP3(a,b,dest,src1,src2,src3) b,
16 /* keep in sync with the enum in mini.h */
17 static const char* const
18 opnames[] = {
19 #include "mini-ops.h"
21 #undef MINI_OP
22 #undef MINI_OP3
25 * Duplicate this from helpers.c, so the opcode name array can be omitted when
26 * DISABLE_JIT is set.
28 static const char*
29 inst_name (int op) {
30 if (op >= OP_LOAD && op <= OP_LAST)
31 return opnames [op - OP_LOAD];
32 if (op < OP_LOAD)
33 return mono_opcode_name (op);
34 g_error ("unknown opcode name for %d", op);
35 return NULL;
38 typedef struct {
39 int num;
40 const char *name;
41 char *desc;
42 char *comment;
43 char spec [MONO_INST_MAX];
44 } OpDesc;
46 static int nacl = 0;
47 static GHashTable *table;
48 static GHashTable *template_table;
50 #define eat_whitespace(s) while (*(s) && isspace (*(s))) s++;
52 static int
53 load_file (const char *name) {
54 FILE *f;
55 char buf [256];
56 char *str, *p;
57 int line;
58 OpDesc *desc;
59 GString *comment;
61 if (!(f = fopen (name, "r")))
62 g_error ("Cannot open file '%s'", name);
64 comment = g_string_new ("");
66 * The format of the lines are:
67 * # comment
68 * opcode: [dest:format] [src1:format] [src2:format] [flags:format] [clob:format]
69 * [cost:num] [res:format] [delay:num] [len:num] [nacl:num]
70 * format is a single letter that depends on the field
71 * NOTE: no space between the field name and the ':'
73 * len: maximum instruction length
75 line = 0;
76 while ((str = fgets (buf, sizeof (buf), f))) {
77 gboolean is_template = FALSE;
78 gboolean nacl_length_set = FALSE;
80 ++line;
81 eat_whitespace (str);
82 if (!str [0])
83 continue;
84 if (str [0] == '#') {
85 g_string_append (comment, str);
86 continue;
88 p = strchr (str, ':');
89 if (!p)
90 g_error ("Invalid format at line %d in %s\n", line, name);
91 *p++ = 0;
92 eat_whitespace (p);
93 if (strcmp (str, "template") == 0) {
94 is_template = TRUE;
95 desc = g_new0 (OpDesc, 1);
96 } else {
97 desc = g_hash_table_lookup (table, str);
98 if (!desc)
99 g_error ("Invalid opcode '%s' at line %d in %s\n", str, line, name);
100 if (desc->desc)
101 g_error ("Duplicated opcode %s at line %d in %s\n", str, line, name);
103 desc->desc = g_strdup (p);
104 desc->comment = g_strdup (comment->str);
105 g_string_truncate (comment, 0);
106 while (*p) {
107 if (strncmp (p, "dest:", 5) == 0) {
108 desc->spec [MONO_INST_DEST] = p [5];
109 p += 6;
110 } else if (strncmp (p, "src1:", 5) == 0) {
111 desc->spec [MONO_INST_SRC1] = p [5];
112 p += 6;
113 } else if (strncmp (p, "src2:", 5) == 0) {
114 desc->spec [MONO_INST_SRC2] = p [5];
115 p += 6;
116 } else if (strncmp (p, "src3:", 5) == 0) {
117 desc->spec [MONO_INST_SRC3] = p [5];
118 p += 6;
119 } else if (strncmp (p, "clob:", 5) == 0) {
120 desc->spec [MONO_INST_CLOB] = p [5];
121 p += 6;
122 /* Currently unused fields
123 } else if (strncmp (p, "cost:", 5) == 0) {
124 desc->spec [MONO_INST_COST] = p [5];
125 p += 6;
126 } else if (strncmp (p, "res:", 4) == 0) {
127 desc->spec [MONO_INST_RES] = p [4];
128 p += 5;
129 } else if (strncmp (p, "flags:", 6) == 0) {
130 desc->spec [MONO_INST_FLAGS] = p [6];
131 p += 7;
132 } else if (strncmp (p, "delay:", 6) == 0) {
133 desc->spec [MONO_INST_DELAY] = p [6];
134 p += 7;
136 } else if (strncmp (p, "len:", 4) == 0) {
137 unsigned long size;
138 p += 4;
139 size = strtoul (p, &p, 10);
140 if (!nacl_length_set) {
141 desc->spec [MONO_INST_LEN] = size;
143 } else if (strncmp (p, "nacl:", 5) == 0) {
144 unsigned long size;
145 p += 5;
146 size = strtoul (p, &p, 10);
147 if (nacl) {
148 desc->spec [MONO_INST_LEN] = size;
149 nacl_length_set = TRUE;
151 } else if (strncmp (p, "template:", 9) == 0) {
152 char *tname;
153 int i;
154 OpDesc *tdesc;
155 p += 9;
156 tname = p;
157 while (*p && isalnum (*p)) ++p;
158 *p++ = 0;
159 tdesc = g_hash_table_lookup (template_table, tname);
160 if (!tdesc)
161 g_error ("Invalid template name %s at '%s' at line %d in %s\n", tname, p, line, name);
162 for (i = 0; i < MONO_INST_MAX; ++i) {
163 if (desc->spec [i])
164 g_error ("The template overrides any previous value set at line %d in %s\n", line, name);
166 memcpy (desc->spec, tdesc->spec, sizeof (desc->spec));
167 } else if (strncmp (p, "name:", 5) == 0) {
168 char *tname;
169 if (!is_template)
170 g_error ("name tag only valid in templates at '%s' at line %d in %s\n", p, line, name);
171 if (desc->name)
172 g_error ("Duplicated name tag in template %s at '%s' at line %d in %s\n", desc->name, p, line, name);
173 p += 5;
174 tname = p;
175 while (*p && isalnum (*p)) ++p;
176 *p++ = 0;
177 if (g_hash_table_lookup (template_table, tname))
178 g_error ("Duplicated template %s at line %d in %s\n", tname, line, name);
179 desc->name = g_strdup (tname);
180 g_hash_table_insert (template_table, (void*)desc->name, desc);
181 } else {
182 g_error ("Parse error at '%s' at line %d in %s\n", p, line, name);
184 eat_whitespace (p);
186 if (is_template && !desc->name)
187 g_error ("Template without name at line %d in %s\n", line, name);
189 fclose (f);
190 return 0;
193 static OpDesc *opcodes = NULL;
195 static void
196 init_table (void) {
197 int i;
198 OpDesc *desc;
200 template_table = g_hash_table_new (g_str_hash, g_str_equal);
201 table = g_hash_table_new (g_str_hash, g_str_equal);
203 opcodes = g_new0 (OpDesc, OP_LAST);
204 for (i = OP_LOAD; i < OP_LAST; ++i) {
205 desc = opcodes + i;
206 desc->num = i;
207 desc->name = inst_name (i);
208 g_hash_table_insert (table, (char *)desc->name, desc);
212 static void
213 output_char (FILE *f, char c) {
214 if (isalnum (c))
215 fprintf (f, "%c", c);
216 else
217 fprintf (f, "\\x%x\" \"", c);
220 static void
221 build_table (const char *fname, const char *name) {
222 FILE *f;
223 int i, j, idx;
224 OpDesc *desc;
225 GString *idx_array = g_string_new ("");
226 /* use this to remove duplicates */
227 GHashTable *desc_ht = g_hash_table_new (g_str_hash, g_str_equal);
229 if (!(f = fopen (fname, "w")))
230 g_error ("Cannot open file '%s'", fname);
231 fprintf (f, "/* File automatically generated by genmdesc, don't change */\n\n");
232 fprintf (f, "const char %s [] = {\n", name);
233 fprintf (f, "\t\"");
234 for (j = 0; j < MONO_INST_MAX; ++j)
235 fprintf (f, "\\x0");
236 fprintf (f, "\"\t/* null entry */\n");
237 idx = 1;
238 g_string_append_printf (idx_array, "const guint16 %s_idx [] = {\n", name);
240 for (i = OP_LOAD; i < OP_LAST; ++i) {
241 desc = opcodes + i;
242 if (!desc->desc)
243 g_string_append_printf (idx_array, "\t0,\t/* %s */\n", desc->name ? desc->name : "");
244 else {
245 fprintf (f, "\t\"");
246 for (j = 0; j < MONO_INST_MAX; ++j)
247 output_char (f, desc->spec [j]);
248 fprintf (f, "\"\t/* %s */\n", desc->name);
249 g_string_append_printf (idx_array, "\t%d,\t/* %s */\n", idx * MONO_INST_MAX, desc->name);
250 ++idx;
253 fprintf (f, "};\n\n");
254 fprintf (f, "%s};\n\n", idx_array->str);
255 fclose (f);
256 g_string_free (idx_array, TRUE);
257 g_hash_table_destroy (desc_ht);
260 static void
261 dump (void) {
262 int i;
263 OpDesc *desc;
265 for (i = 0; i < MONO_CEE_LAST; ++i) {
266 desc = opcodes + i;
267 if (desc->comment)
268 g_print ("%s", desc->comment);
269 if (!desc->desc)
270 g_print ("%s:\n", desc->name);
271 else {
272 g_print ("%s: %s", desc->name, desc->desc);
273 if (!strchr (desc->desc, '\n'))
274 g_print ("\n");
277 for (i = OP_LOAD; i < OP_LAST; ++i) {
278 desc = opcodes + i;
279 if (!desc->desc)
280 g_print ("%s:\n", desc->name);
281 else {
282 g_print ("%s: %s", desc->name, desc->desc);
283 if (!strchr (desc->desc, '\n'))
284 g_print ("\n");
290 * TODO: output the table (possibly merged), in the input format
292 int
293 main (int argc, char* argv [])
295 init_table ();
296 if (argc == 2) {
297 /* useful to get a new file when some opcodes are added: looses the comments, though */
298 load_file (argv [1]);
299 dump ();
300 } else if (argc < 4) {
301 g_print ("Usage: genmdesc arguments\n");
302 g_print ("\tgenmdesc desc Output to stdout the description file.\n");
303 g_print ("\tgenmdesc [--nacl] output name desc [desc1...]\n"
304 " Write to output the description in a table named 'name',\n"
305 " use --nacl to generate Google NativeClient code\n");
306 return 1;
307 } else {
308 int i = 3;
309 if (strcmp (argv [1], "--nacl") == 0) {
310 nacl = 1;
311 i++;
314 for (; i < argc; ++i)
315 load_file (argv [i]);
317 build_table (argv [1 + nacl], argv [2 + nacl]);
319 return 0;