1 /* Jitter: generator implementation.
2
3 Copyright (C) 2017, 2018, 2019, 2020, 2021 Luca Saiu
4 Written by Luca Saiu
5
6 This file is part of Jitter.
7
8 Jitter is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 Jitter is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with Jitter. If not, see <http://www.gnu.org/licenses/>. */
20
21
22 /* Include the Gnulib header. */
23 #include <config.h>
24
25 #include <assert.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <ctype.h>
29 #include <unistd.h> /* for unlink and rmdir */
30 #include <string.h>
31 #include <sys/stat.h> /* For mkdir and permission bit macros. */
32 #include <errno.h>
33
34 #include <xalloc.h>
35 #include <gl_array_list.h>
36 #include <gl_xlist.h>
37
38 #include "jitterc-generate.h"
39 #include "jitterc-utility.h"
40 #include "jitterc-vm.h"
41 #include "jitterc-rewrite.h"
42 #include "jitterc-mangle.h"
43
44 #include <jitter/jitter-fatal.h>
45 #include <jitter/jitter-string.h>
46
47 /* This contains fixed opcodes for special specialized instructions. */
48 #include <jitter/jitter-specialize.h>
49
50
51 /* Preliminary definitions.
52 * ************************************************************************** */
53
54 /* VM prefixes as occurring in templates and generated files before
55 replacement. */
56 #define INPUT_LOWER_CASE_PREFIX "vmprefix"
57 #define INPUT_UPPER_CASE_PREFIX "VMPREFIX"
58
59 /* The temporary subdirectory basename. This directory contains a temporary
60 copy of the generated files, to be copied to the actual output directory
61 at the end if everything succeeds. */
62 #define TMP "tmp-vm-generator"
63
64
65
66
67 /* Code generation machinery.
68 * ************************************************************************** */
69
70 /* Perform a fprintf call exiting fatally in case of error. */
71 #define EMIT_TO(...) \
72 do \
73 { \
74 if (fprintf (__VA_ARGS__) < 0) \
75 jitter_fatal ("could not write to output file"); \
76 } \
77 while (false)
78
79 /* Perform a fprintf call exiting fatally in case of error and using as output
80 the variable f, jitter it is in the current scope. */
81 #define EMIT(...) \
82 EMIT_TO(f, __VA_ARGS__)
83
84 static FILE *
jitterc_fopen_pathname(const char * pathname,const char * opentype)85 jitterc_fopen_pathname (const char *pathname, const char *opentype)
86 {
87 FILE *res = fopen (pathname, opentype);
88 if (res == NULL)
89 jitter_fatal ("could not open file %s in mode %s", pathname, opentype);
90 return res;
91 }
92
93 /* Return a new file stream open for reading, or fail fatally in case of error;
94 the file full pathname is given as an argument. */
95 static FILE *
jitterc_fopen_r_pathname(const char * pathname)96 jitterc_fopen_r_pathname (const char *pathname)
97 {
98 return jitterc_fopen_pathname (pathname, "r");
99 }
100
101 /* Return a new file stream open for writing, or fail fatally in case of error;
102 the file full pathname is given as an argument. */
103 static FILE *
jitterc_fopen_w_pathname(const char * pathname)104 jitterc_fopen_w_pathname (const char *pathname)
105 {
106 return jitterc_fopen_pathname (pathname, "w");
107 }
108
109 /* Return a new file stream open for appending, or fail fatally in case of
110 error; the file full pathname is given as an argument. */
111 static FILE *
jitterc_fopen_a_pathname(const char * pathname)112 jitterc_fopen_a_pathname (const char *pathname)
113 {
114 return jitterc_fopen_pathname (pathname, "a");
115 }
116
117 /* Return a malloc-allocated string containing the full pathname of the given
118 basename, within the temporary directory of the pointed VM. */
119 __attribute__ ((returns_nonnull, nonnull (1, 2)))
120 static char *
jitterc_pathname(const struct jitterc_vm * vm,const char * basename)121 jitterc_pathname (const struct jitterc_vm *vm,
122 const char *basename)
123 {
124 size_t pathname_size
125 = strlen (vm->tmp_directory) + 1 + strlen (basename) + 1;
126 char *pathname = xmalloc (pathname_size);
127 sprintf (pathname, "%s/%s", vm->tmp_directory, basename);
128 return pathname;
129 }
130
131 /* Return a new file stream open for appending in the temporary directory of the
132 pointed VM, or fail fatally in case of error; the file basename is given as
133 an argument. */
134 static FILE *
jitterc_fopen_a_basename(const struct jitterc_vm * vm,const char * basename)135 jitterc_fopen_a_basename (const struct jitterc_vm *vm,
136 const char *basename)
137 {
138 char *pathname = jitterc_pathname (vm, basename);
139 FILE *res = jitterc_fopen_a_pathname (pathname);
140 free (pathname);
141 return res;
142 }
143
144 static FILE *
jitterc_fopen_w_or_a_and_remember_basename(const struct jitterc_vm * vm,const char * basename,const char letter)145 jitterc_fopen_w_or_a_and_remember_basename (const struct jitterc_vm *vm,
146 const char *basename,
147 const char letter)
148 {
149 gl_list_add_last (vm->written_file_names,
150 jitter_clone_string (basename));
151 char *pathname = jitterc_pathname (vm, basename);
152 FILE *res;
153 if (letter == 'w')
154 res = jitterc_fopen_w_pathname (pathname);
155 else if (letter == 'a')
156 res = jitterc_fopen_a_pathname (pathname);
157 else
158 jitter_fatal ("jitterc_fopen_w_or_a_and_remember_basename: wrong letter");
159 free (pathname);
160 return res;
161 }
162
163 /* Return a new file stream open for writing; the given file basename is
164 appended to the temporary output directory of the VM whose pointer is given,
165 and the file basename is copied to the written_file_names list in the VM, so
166 that the written file can be moved later to the actual output directory if
167 everything succeeds. */
168 __attribute__ ((unused))
169 static FILE *
jitterc_fopen_w_and_remember_basename(const struct jitterc_vm * vm,const char * basename)170 jitterc_fopen_w_and_remember_basename (const struct jitterc_vm *vm,
171 const char *basename)
172 {
173 return jitterc_fopen_w_or_a_and_remember_basename (vm, basename, 'w');
174 }
175
176 /* Like jitterc_fopen_w_and_remember_basename, but append instead of
177 overwriting in case the file already exists. */
178 static FILE *
jitterc_fopen_a_and_remember_basename(const struct jitterc_vm * vm,const char * basename)179 jitterc_fopen_a_and_remember_basename (const struct jitterc_vm *vm,
180 const char *basename)
181 {
182 return jitterc_fopen_w_or_a_and_remember_basename (vm, basename, 'a');
183 }
184
185 /* Close the given stream, failing fatally in case of errors. This works for
186 both input and output streams.*/
187 void
jitterc_fclose(FILE * f)188 jitterc_fclose (FILE *f)
189 {
190 if (fclose (f) != 0)
191 jitter_fatal ("could not close file");
192 }
193
194 /* Make the given directory, exiting fatally in case of error. */
195 static void
jitterc_mkdir(const char * pathname)196 jitterc_mkdir (const char *pathname)
197 {
198 if (mkdir (pathname, S_IRWXU) != 0 && errno != EEXIST)
199 jitter_fatal ("could not make directory %s", (pathname));
200 }
201
202 /* From this point on any use of fopen, fclose or fprintf or mkdir is almost
203 certainly a mistake. Poison the identifiers in question. */
204 #pragma GCC poison \
205 mkdir fclose fprintf fopen
206
207 #define FOR_LIST(VARIABLE, COMMA, LIST) \
208 for (VARIABLE = 0 \
209 , COMMA = ((VARIABLE == gl_list_size (LIST) - 1) ? "" : ","); \
210 VARIABLE < gl_list_size (LIST); \
211 VARIABLE ++ \
212 , COMMA = ((VARIABLE == gl_list_size (LIST) - 1) ? "" : ","))
213
214 #define FOR_LIST_DOWN(VARIABLE, COMMA, LIST) \
215 for (VARIABLE = gl_list_size (LIST) - 1 \
216 , COMMA = ((VARIABLE == 0) ? "" : ","); \
217 VARIABLE >= 0; \
218 VARIABLE -- \
219 , COMMA = ((VARIABLE == 0) ? "" : ","))
220
221
222
223 /* Simple source generation. */
224
225 /* Emit verbatim text to the output, without any added whitespace. This
226 is useful to emit comments or C code. */
227 static void
jitterc_emit_text_to_stream(const struct jitterc_vm * vm,const char * file_basename,const char * text)228 jitterc_emit_text_to_stream (const struct jitterc_vm *vm,
229 const char *file_basename,
230 const char *text)
231 {
232 FILE *f = jitterc_fopen_a_basename (vm, file_basename);
233 EMIT ("%s", text);
234 jitterc_fclose (f);
235 }
236
237 /* Emit user-specified code. FIXME: use this everywhere and find some way of
238 handling #line directives out of user code. */
239 static void
jitterc_emit_user_c_code_to_stream(const struct jitterc_vm * vm,FILE * f,const char * code,char * description)240 jitterc_emit_user_c_code_to_stream (const struct jitterc_vm *vm,
241 FILE *f,
242 const char *code,
243 char *description)
244 {
245 EMIT("/* User-specified code, %s part: beginning. */\n", description);
246 EMIT("%s", code);
247 EMIT("\n/* User-specified code, %s part: end */\n", description);
248 EMIT("\n");
249 }
250
251 /* Emit user-specified code. FIXME: use this everywhere and find some way of
252 handling #line directives out of user code. */
253 static void
jitterc_emit_user_c_code(const struct jitterc_vm * vm,const char * file_basename,const char * code,char * description)254 jitterc_emit_user_c_code (const struct jitterc_vm *vm,
255 const char *file_basename,
256 const char *code,
257 char *description)
258 {
259 FILE *f = jitterc_fopen_a_basename (vm, file_basename);
260 jitterc_emit_user_c_code_to_stream (vm, f, code, description);
261 jitterc_fclose (f);
262 }
263
264 /* Emit the initial part of the user-specified code for the header. This user code
265 comes before everything, even before standard #include directives. */
266 static void
jitterc_emit_initial_header_c(const struct jitterc_vm * vm)267 jitterc_emit_initial_header_c (const struct jitterc_vm *vm)
268 {
269 jitterc_emit_user_c_code (vm, "vm.h", vm->initial_header_c_code,
270 "initial header");
271 }
272
273 /* Like jitterc_emit_initial_header_c for the other generated files. */
274 static void
jitterc_emit_initial_vm1_c(const struct jitterc_vm * vm)275 jitterc_emit_initial_vm1_c (const struct jitterc_vm *vm)
276 {
277 jitterc_emit_user_c_code (vm, "vm1.c", vm->initial_vm1_c_code,
278 "initial vm1");
279 }
280 static void
jitterc_emit_initial_vm2_c(const struct jitterc_vm * vm)281 jitterc_emit_initial_vm2_c (const struct jitterc_vm *vm)
282 {
283 jitterc_emit_user_c_code (vm, "vm2.c", vm->initial_vm2_c_code,
284 "initial vm2");
285 }
286 static void
jitterc_emit_initial_vm_main_c(const struct jitterc_vm * vm)287 jitterc_emit_initial_vm_main_c (const struct jitterc_vm *vm)
288 {
289 jitterc_emit_user_c_code (vm, "vm-main.c", vm->initial_vm_main_c_code,
290 "initial vm-main");
291 }
292
293
294 /* Emit the early part of the user-specified code for the header. */
295 static void
jitterc_emit_early_header_c(const struct jitterc_vm * vm)296 jitterc_emit_early_header_c (const struct jitterc_vm *vm)
297 {
298 jitterc_emit_user_c_code (vm, "vm.h", vm->early_header_c_code,
299 "early header");
300 }
301
302 /* Emit the late part of the user-specified code for the header. */
303 static void
jitterc_emit_late_header_c(const struct jitterc_vm * vm)304 jitterc_emit_late_header_c (const struct jitterc_vm *vm)
305 {
306 jitterc_emit_user_c_code (vm, "vm.h", vm->late_header_c_code,
307 "late header");
308 }
309
310 /* Emit the late part of the user-specified code for the header. */
311 static void
jitterc_emit_header_closing(const struct jitterc_vm * vm)312 jitterc_emit_header_closing (const struct jitterc_vm *vm)
313 {
314 FILE *f = jitterc_fopen_a_basename (vm, "vm.h");
315 EMIT("\n");
316 EMIT("/* Close the multiple-inclusion guard opened in the template. */\n");
317 EMIT("#endif // #ifndef VMPREFIX_VM_H_\n");
318 jitterc_fclose (f);
319 }
320
321 static void
jitterc_emit_meta_instructions_h(const struct jitterc_vm * vm)322 jitterc_emit_meta_instructions_h (const struct jitterc_vm *vm)
323 {
324 FILE *f = jitterc_fopen_a_basename (vm, "vm.h");
325 EMIT("#ifndef VMPREFIX_META_INSTRUCTIONS_H_\n#define VMPREFIX_META_INSTRUCTIONS_H_\n\n");
326 EMIT("enum vmprefix_meta_instruction_id\n");
327 EMIT(" {\n");
328 int i; char *comma;
329 FOR_LIST(i, comma, vm->instructions)
330 EMIT(" vmprefix_meta_instruction_id_%s = %i%s\n",
331 (((const struct jitterc_instruction*)
332 gl_list_get_at (vm->instructions, i))->mangled_name),
333 i,
334 comma);
335 EMIT(" };\n");
336 EMIT("\n#define VMPREFIX_META_INSTRUCTION_NO %i\n\n", i);
337
338 EMIT("/* The longest meta-instruction name length, not mangled, without\n");
339 EMIT(" counting the final '\\0' character. */\n");
340 EMIT("#define VMPREFIX_MAX_META_INSTRUCTION_NAME_LENGTH %u\n\n",
341 (unsigned) vm->max_instruction_name_length);
342 EMIT("#endif // #ifndef VMPREFIX_META_INSTRUCTIONS_H_\n");
343 jitterc_fclose (f);
344 }
345
346 /* Emit user C code for literal argument printing. This is called at the
347 appropriate time to be visible in the relevant part of the generated code
348 without forward-declarations. */
349 static void
jitterc_emit_printer_c(const struct jitterc_vm * vm)350 jitterc_emit_printer_c (const struct jitterc_vm *vm)
351 {
352 jitterc_emit_user_c_code (vm, "vm1.c", vm->printer_c_code,
353 "printer");
354 }
355
356 /* The generated file also includes what was in the old generated
357 vm/meta-instruction-parameter-types.c . */
358 static void
jitterc_emit_meta_instructions(const struct jitterc_vm * vm)359 jitterc_emit_meta_instructions (const struct jitterc_vm *vm)
360 {
361 FILE *f = jitterc_fopen_a_basename (vm, "vm1.c");
362 int i; char *comma __attribute__ ((unused));
363 EMIT("//#include <stdbool.h>\n\n");
364 EMIT("//#include <jitter/jitter.h>\n");
365 EMIT("//#include <jitter/jitter-instruction.h>\n\n");
366 EMIT("//#include \"vmprefix-meta-instructions.h\"\n");
367 EMIT("\n");
368 EMIT("// FIXME: comment.\n");
369 EMIT("struct jitter_hash_table\n");
370 EMIT("vmprefix_meta_instruction_hash;\n");
371 EMIT("\n\n");
372 FOR_LIST(i, comma, vm->instructions)
373 {
374 const struct jitterc_instruction *in
375 = (const struct jitterc_instruction*)
376 (gl_list_get_at (vm->instructions, i));
377
378 int in_arity = gl_list_size (in->arguments);
379 if (in_arity == 0)
380 continue;
381
382 EMIT("static const /*FIXME: use enum jitterc_instruction_argument_kind instead*/struct jitter_meta_instruction_parameter_type vmprefix_%s_meta_instruction_parameter_types [%i] =\n {",
383 in->mangled_name,
384 in_arity);
385 int j; char *inner_comma;
386 FOR_LIST(j, inner_comma, in->arguments)
387 //for (j = 0; j < in_arity; j ++)
388 {
389 //if (j == (in_arity - 1))
390 // inner_comma = "";
391 /* FIXME: this is a temporary compatibility hack. I should do away
392 with enum jitter_meta_instruction_parameter_type and use enum
393 jitterc_instruction_argument_kind instead .*/
394 const struct jitterc_instruction_argument *arg
395 = (const struct jitterc_instruction_argument *)
396 (gl_list_get_at (in->arguments, j));
397 char *kind;
398 bool includes_register = false;
399 switch ((int) arg->kind)
400 {
401 case jitterc_instruction_argument_kind_register:
402 kind = "jitter_meta_instruction_parameter_kind_register";
403 includes_register = true;
404 break;
405 case jitterc_instruction_argument_kind_literal:
406 kind = "jitter_meta_instruction_parameter_kind_literal_fixnum";
407 break;
408 case jitterc_instruction_argument_kind_label:
409 case jitterc_instruction_argument_kind_fast_label:
410 kind = "jitter_meta_instruction_parameter_kind_literal_label";
411 break;
412 case jitterc_instruction_argument_kind_register
413 | jitterc_instruction_argument_kind_literal:
414 kind = "jitter_meta_instruction_parameter_kind_register_or_literal_fixnum";
415 includes_register = true;
416 break;
417 case jitterc_instruction_argument_kind_register
418 | jitterc_instruction_argument_kind_label:
419 kind = "jitter_meta_instruction_parameter_kind_register_or_literal_label";
420 includes_register = true;
421 break;
422 case jitterc_instruction_argument_kind_literal
423 | jitterc_instruction_argument_kind_label:
424 kind = "jitter_meta_instruction_parameter_kind_literal_fixnum_or_literal_label";
425 includes_register = false;
426 break;
427 case jitterc_instruction_argument_kind_register
428 | jitterc_instruction_argument_kind_literal
429 | jitterc_instruction_argument_kind_label:
430 kind = "jitter_meta_instruction_parameter_kind_register_or_literal_fixnum_or_literal_label";
431 includes_register = true;
432 break;
433 default:
434 jitter_fatal ("Unsupported enum jitterc_instruction_argument_kind case: %i\n",
435 (int) arg->kind);
436 }
437
438 /* Get the name of the literal printer, of a default if none was
439 given. */
440 char *literal_printer_name;
441 if (arg->c_literal_printer_name != NULL)
442 literal_printer_name = arg->c_literal_printer_name;
443 else
444 literal_printer_name = "jitter_default_literal_parameter_printer";
445
446 if (includes_register)
447 EMIT(" { %s, & vmprefix_register_class_%c, %s }%s", kind,
448 arg->register_class_character, literal_printer_name,
449 inner_comma);
450 else
451 EMIT(" { %s, NULL, %s }%s", kind, literal_printer_name,
452 inner_comma);
453 }
454 EMIT(" };\n\n");
455 }
456 //EMIT(" };\n");
457 EMIT("\n");
458 EMIT("const struct jitter_meta_instruction\n");
459 EMIT("vmprefix_meta_instructions [VMPREFIX_META_INSTRUCTION_NO]\n");
460 EMIT(" = {\n");
461 FOR_LIST(i, comma, vm->instructions)
462 {
463 const struct jitterc_instruction *in
464 = (const struct jitterc_instruction*)
465 (gl_list_get_at (vm->instructions, i));
466 int in_arity = gl_list_size (in->arguments);
467 EMIT(" { %i, \"%s\", %i, %s, %s, %s, ",
468 i, in->name, in_arity,
469 ((in->callerness == jitterc_callerness_caller)
470 ? "true" : "false"),
471 ((in->calleeness == jitterc_calleeness_callee)
472 ? "true" : "false"),
473 ((in->relocatability == jitterc_relocatability_relocatable)
474 ? "true /* FIXME: this may be wrong with replacements. */"
475 : "false /* FIXME: this may be wrong with replacements. */"));
476 if (in_arity == 0)
477 EMIT("NULL }%s\n", comma);
478 else
479 EMIT("vmprefix_%s_meta_instruction_parameter_types }%s\n",
480 in->mangled_name, comma);
481 }
482 EMIT(" };\n");
483 jitterc_fclose (f);
484 }
485
486 static void
jitterc_emit_specialized_instructions_h(const struct jitterc_vm * vm)487 jitterc_emit_specialized_instructions_h (const struct jitterc_vm *vm)
488 {
489 FILE *f = jitterc_fopen_a_basename (vm, "vm.h");
490 EMIT("#ifndef VMPREFIX_SPECIALIZED_INSTRUCTIONS_H_\n#define VMPREFIX_SPECIALIZED_INSTRUCTIONS_H_\n\n");
491 EMIT("enum vmprefix_specialized_instruction_opcode\n");
492 EMIT(" {\n");
493 int i; char *comma;
494 FOR_LIST(i, comma, vm->specialized_instructions)
495 EMIT(" vmprefix_specialized_instruction_opcode_%s = %i%s\n",
496 (((const struct jitterc_specialized_instruction*)
497 gl_list_get_at (vm->specialized_instructions, i))->mangled_name),
498 i,
499 comma);
500 EMIT(" };\n");
501 EMIT("\n#define VMPREFIX_SPECIALIZED_INSTRUCTION_NO %i\n\n", i);
502 EMIT("#endif // #ifndef VMPREFIX_SPECIALIZED_INSTRUCTIONS_H_\n");
503 jitterc_fclose (f);
504 }
505
506 static void
jitterc_emit_specialized_instruction_names(const struct jitterc_vm * vm)507 jitterc_emit_specialized_instruction_names (const struct jitterc_vm *vm)
508 {
509 FILE *f = jitterc_fopen_a_basename (vm, "vm1.c");
510 EMIT("//#include \"vmprefix-specialized-instructions.h\"\n");
511 EMIT("\n");
512 EMIT("const char * const\n");
513 EMIT("vmprefix_specialized_instruction_names [VMPREFIX_SPECIALIZED_INSTRUCTION_NO]\n");
514 EMIT(" = {\n");
515 int i; char *comma;
516 FOR_LIST(i, comma, vm->specialized_instructions)
517 EMIT(" \"%s\"%s\n",
518 (((const struct jitterc_specialized_instruction*)
519 gl_list_get_at (vm->specialized_instructions, i))->name),
520 comma);
521 EMIT(" };\n");
522 jitterc_fclose (f);
523 }
524
525 static void
jitterc_emit_specialized_instruction_residual_arities(const struct jitterc_vm * vm)526 jitterc_emit_specialized_instruction_residual_arities
527 (const struct jitterc_vm *vm)
528 {
529 FILE *f = jitterc_fopen_a_basename (vm, "vm1.c");
530 EMIT("// #include <stdlib.h>\n\n");
531 EMIT("// #include \"vmprefix-specialized-instructions.h\"\n");
532 EMIT("const size_t\n");
533 EMIT("vmprefix_specialized_instruction_residual_arities [VMPREFIX_SPECIALIZED_INSTRUCTION_NO]\n");
534 EMIT(" = {\n");
535 int i; char *comma;
536 FOR_LIST(i, comma, vm->specialized_instructions)
537 {
538 const struct jitterc_specialized_instruction* sins
539 = ((const struct jitterc_specialized_instruction*)
540 gl_list_get_at (vm->specialized_instructions, i));
541 size_t residual_arity = 0;
542 int j;
543 for (j = 0; j < gl_list_size (sins->specialized_arguments); j ++)
544 if (((const struct jitterc_specialized_argument*)
545 gl_list_get_at (sins->specialized_arguments, j))->residual)
546 residual_arity ++;
547 EMIT(" %i%s /* %s */\n", (int)residual_arity, comma, sins->name);
548 }
549 EMIT(" };\n");
550 jitterc_fclose (f);
551 }
552
553 /* This factors the implementation of
554 jitterc_emit_specialized_instruction_label_bitmasks and
555 jitterc_emit_specialized_instruction_fast_label_bitmasks . */
556 static void
jitterc_emit_specialized_instruction_label_bitmasks_possibly_fast(const struct jitterc_vm * vm,bool fast)557 jitterc_emit_specialized_instruction_label_bitmasks_possibly_fast
558 (const struct jitterc_vm *vm,
559 bool fast)
560 {
561 FILE *f = jitterc_fopen_a_basename (vm, "vm1.c");
562 if (fast)
563 EMIT("#ifdef JITTER_HAVE_PATCH_IN\n");
564 EMIT("const unsigned long // FIXME: shall I use a shorter type when possible?\n");
565 EMIT("vmprefix_specialized_instruction_%slabel_bitmasks [VMPREFIX_SPECIALIZED_INSTRUCTION_NO]\n",
566 fast ? "fast_" : "");
567 EMIT(" = {\n");
568 EMIT(" /* It's important that !BEGINBASICBLOCK has a zero here: it does not need residual patching. */\n");
569 int i; char *comma;
570 FOR_LIST(i, comma, vm->specialized_instructions)
571 {
572 const struct jitterc_specialized_instruction* sins
573 = ((const struct jitterc_specialized_instruction*)
574 gl_list_get_at (vm->specialized_instructions, i));
575 EMIT(" 0");
576 int j;
577 int residual_counter = 0;
578 for (j = 0; j < gl_list_size (sins->specialized_arguments); j ++)
579 {
580 const struct jitterc_specialized_argument *sarg
581 = ((const struct jitterc_specialized_argument*)
582 gl_list_get_at (sins->specialized_arguments, j));
583 if (! sarg->residual)
584 continue;
585 bool has_a_one;
586 if (fast)
587 has_a_one
588 = sarg->kind == jitterc_instruction_argument_kind_fast_label;
589 else
590 has_a_one
591 = sarg->kind == jitterc_instruction_argument_kind_label
592 || sarg->kind == jitterc_instruction_argument_kind_fast_label;
593 if (has_a_one)
594 EMIT(" | (1UL << %i)", residual_counter);
595
596 residual_counter ++;
597 }
598 EMIT("%s /* %s */\n", comma, sins->name);
599 }
600 EMIT(" };\n");
601 if (fast)
602 EMIT("#endif // #ifdef JITTER_HAVE_PATCH_IN\n\n");
603 jitterc_fclose (f);
604 }
605 static void
jitterc_emit_specialized_instruction_label_bitmasks(const struct jitterc_vm * vm)606 jitterc_emit_specialized_instruction_label_bitmasks (const struct jitterc_vm *vm)
607 {
608 jitterc_emit_specialized_instruction_label_bitmasks_possibly_fast (vm, false);
609 }
610 static void
jitterc_emit_specialized_instruction_fast_label_bitmasks(const struct jitterc_vm * vm)611 jitterc_emit_specialized_instruction_fast_label_bitmasks (const struct jitterc_vm *vm)
612 {
613 jitterc_emit_specialized_instruction_label_bitmasks_possibly_fast (vm, true);
614 }
615
616
617
618
619 /* Code generation utility.
620 * ************************************************************************** */
621
622 /* Emit a #line directive referring the Jitter VM specification source file,
623 unless #line-generation was disabled and unless enable_hash_line is false.
624 Rationale: according to the C Standard # preprocessor directives must not
625 appear within macro arguments, and the enable_hash_line argument provides an
626 easy way of disabling #line directives in such contexts, without having
627 explicit conditionals in callers. */
628 static void
jitterc_emit_hash_line(FILE * f,const struct jitterc_vm * vm,int line_no,bool enable_hash_line)629 jitterc_emit_hash_line (FILE *f, const struct jitterc_vm *vm, int line_no,
630 bool enable_hash_line)
631 {
632 if (vm->generate_line && enable_hash_line)
633 EMIT("#line %i \"%s\"\n", line_no, vm->source_file_name);
634 }
635
636
637
638
639 /* More complex code generation.
640 * ************************************************************************** */
641
642 static void
jitterc_emit_specialized_instruction_relocatables(const struct jitterc_vm * vm)643 jitterc_emit_specialized_instruction_relocatables
644 (const struct jitterc_vm *vm)
645 {
646 FILE *f = jitterc_fopen_a_basename (vm, "vm1.c");
647
648 EMIT("// FIXME: I may want to conditionalize this.\n");
649 EMIT("const bool\n");
650 EMIT("vmprefix_specialized_instruction_relocatables [VMPREFIX_SPECIALIZED_INSTRUCTION_NO]\n");
651 EMIT(" = {\n");
652 int i; char *comma;
653 FOR_LIST(i, comma, vm->specialized_instructions)
654 {
655 const struct jitterc_specialized_instruction* sins
656 = ((const struct jitterc_specialized_instruction*)
657 gl_list_get_at (vm->specialized_instructions, i));
658 bool relocatable = (sins->relocatability
659 == jitterc_relocatability_relocatable);
660 EMIT(" %s%s // %s\n",
661 relocatable ? "true" : "false",
662 comma,
663 sins->name);
664 }
665 EMIT(" };\n\n");
666 jitterc_fclose (f);
667 }
668
669 /* Emit the definition of a bool vector, one element per specialized instruction,
670 each element being true iff the corresponding instruction is a caller/callee. */
671 static void
jitterc_emit_specialized_instruction_callers_or_callees(const struct jitterc_vm * vm,bool callers)672 jitterc_emit_specialized_instruction_callers_or_callees
673 (const struct jitterc_vm *vm,
674 bool callers)
675 {
676 FILE *f = jitterc_fopen_a_basename (vm, "vm1.c");
677 char *name = callers ? "callers" : "callees";
678
679 EMIT("// FIXME: this is not currently accessed, and in fact may be useless.\n");
680 EMIT("const bool\n");
681 EMIT("vmprefix_specialized_instruction_%s [VMPREFIX_SPECIALIZED_INSTRUCTION_NO]\n",
682 name);
683 EMIT(" = {\n");
684 int i; char *comma;
685 FOR_LIST(i, comma, vm->specialized_instructions)
686 {
687 const struct jitterc_specialized_instruction* sins
688 = ((const struct jitterc_specialized_instruction*)
689 gl_list_get_at (vm->specialized_instructions, i));
690 bool value;
691 if (sins->instruction == NULL)
692 value = false;
693 else if (callers)
694 value = (sins->instruction->callerness == jitterc_callerness_caller);
695 else
696 value = (sins->instruction->calleeness == jitterc_calleeness_callee);
697 EMIT(" %s%s // %s\n", value ? "true" : "false", comma, sins->name);
698 }
699 EMIT(" };\n\n");
700 jitterc_fclose (f);
701 }
702
703 /* Emit the definition of a bool vector, one element per specialized instruction,
704 each element being true iff the corresponding instruction is a caller. */
705 static void
jitterc_emit_specialized_instruction_callers(const struct jitterc_vm * vm)706 jitterc_emit_specialized_instruction_callers
707 (const struct jitterc_vm *vm)
708 {
709 jitterc_emit_specialized_instruction_callers_or_callees (vm, true);
710 }
711
712 /* Emit the definition of a bool vector, one element per specialized instruction,
713 each element being true iff the corresponding instruction is a callee. */
714 static void
jitterc_emit_specialized_instruction_callees(const struct jitterc_vm * vm)715 jitterc_emit_specialized_instruction_callees
716 (const struct jitterc_vm *vm)
717 {
718 jitterc_emit_specialized_instruction_callers_or_callees (vm, false);
719 }
720
721 /* Emit the definition of an array whose indices are specialised instruction
722 opcode, and whose elements are the corresponding unspecialised instructions
723 opcodes -- or -1 when there is no mapping. */
724 static void
jitterc_emit_specialized_instruction_to_unspecialized_instruction(const struct jitterc_vm * vm)725 jitterc_emit_specialized_instruction_to_unspecialized_instruction
726 (const struct jitterc_vm *vm)
727 {
728 FILE *f = jitterc_fopen_a_basename (vm, "vm1.c");
729
730 EMIT("/* An array whose indices are specialised instruction opcodes, and\n");
731 EMIT(" whose elements are the corresponding unspecialised instructions\n");
732 EMIT(" opcodes -- or -1 when there is no mapping mapping having */\n");
733 EMIT("const int\n");
734 EMIT("vmprefix_specialized_instruction_to_unspecialized_instruction\n");
735 EMIT(" [VMPREFIX_SPECIALIZED_INSTRUCTION_NO]\n");
736 EMIT(" = {\n");
737 int i; char *comma;
738 FOR_LIST(i, comma, vm->specialized_instructions)
739 {
740 const struct jitterc_specialized_instruction* sins
741 = ((const struct jitterc_specialized_instruction*)
742 gl_list_get_at (vm->specialized_instructions, i));
743 if (sins->instruction == NULL)
744 EMIT(" -1%s /* %s */\n", comma, sins->name);
745 else
746 EMIT(" vmprefix_meta_instruction_id_%s%s /* %s */\n",
747 sins->instruction->mangled_name, comma, sins->name);
748 }
749 EMIT(" };\n\n");
750 jitterc_fclose (f);
751 }
752
753 /* Emit the worst-case defect table for the pointed VM. */
754 static void
jitterc_emit_worst_case_defect_table(const struct jitterc_vm * vm)755 jitterc_emit_worst_case_defect_table (const struct jitterc_vm *vm)
756 {
757 FILE *f = jitterc_fopen_a_basename (vm, "vm1.c");
758 EMIT("#ifdef JITTER_HAVE_PATCH_IN\n");
759 EMIT("/* Worst-case defect table. */\n");
760 EMIT("const jitter_uint\n");
761 EMIT("vmprefix_worst_case_defect_table [] =\n");
762 EMIT(" {\n");
763 int i; char *comma;
764 FOR_LIST(i, comma, vm->specialized_instructions)
765 {
766 const struct jitterc_specialized_instruction* sins
767 = ((const struct jitterc_specialized_instruction*)
768 gl_list_get_at (vm->specialized_instructions, i));
769 if (sins->has_as_replacement == NULL)
770 EMIT(" vmprefix_specialized_instruction_opcode_%s%s /* NOT potentially defective. */\n",
771 sins->mangled_name, comma);
772 else
773 EMIT(" /*vmprefix_specialized_instruction_opcode__eINVALID*/vmprefix_specialized_instruction_opcode_%s%s /* POTENTIALLY DEFECTIVE. */\n",
774 sins->has_as_replacement->mangled_name, comma);
775 }
776 EMIT(" };\n");
777 EMIT("#endif // #ifdef JITTER_HAVE_PATCH_IN\n");
778 EMIT("\n\n");
779 jitterc_fclose (f);
780 }
781
782
783
784
785 /* Rewriter generation.
786 * ************************************************************************** */
787
788 /* Emit code for the pointed template expression to the pointed stream for the
789 pointed VM; the generated C code evaluates to a literal if
790 evaluate_to_literal is true, otherwise it evaluates to an instruction
791 argument. This is to be used both in rules bodies for instantiating template
792 expression and within a condition for evaluating a rule guard -- but the
793 output is not a condition.
794 About enable_hash_line, see the comment before jitterc_emit_hash_line . */
795 static void
jitterc_emit_rewrite_rule_template_expression(FILE * f,const struct jitterc_vm * vm,const struct jitterc_template_expression * te,bool evaluate_to_literal,bool enable_hash_line)796 jitterc_emit_rewrite_rule_template_expression
797 (FILE *f,
798 const struct jitterc_vm *vm,
799 const struct jitterc_template_expression *te,
800 bool evaluate_to_literal,
801 bool enable_hash_line)
802 {
803 /* Generate a #line directive for the template expression, indepdendently from
804 its shape. */
805 jitterc_emit_hash_line(f, vm, te->line_no, enable_hash_line);
806
807 /* Generate different code according to the AST case. */
808 switch (te->case_)
809 {
810 case jitterc_instruction_argument_expression_case_boolean_constant:
811 if (! evaluate_to_literal)
812 jitter_fatal ("template expression: unexpected boolean constant");
813 EMIT(" %s\n", te->constant.fixnum ? "true" : "false");
814 break;
815
816 case jitterc_instruction_argument_expression_case_fixnum_constant:
817 if (! evaluate_to_literal)
818 jitter_fatal ("template expression: unexpected fixnum constant");
819 EMIT(" %"JITTER_PRIi"\n", te->constant.fixnum);
820 break;
821
822 case jitterc_instruction_argument_expression_case_placeholder:
823 if (evaluate_to_literal)
824 EMIT(" JITTER_RULE_LITERAL_FIELD(JITTER_PLACEHOLDER_NAME(%s))\n",
825 te->placeholder);
826 else
827 EMIT(" JITTER_PLACEHOLDER_NAME(%s)\n", te->placeholder);
828 break;
829
830 case jitterc_instruction_argument_expression_case_operation:
831 {
832 int i; char *comma;
833 EMIT("#warning: operators (here \"%s\") not really implemented yet\n",
834 te->operator->name);
835 /* Convert the operator name to upper case, to emit it as part of a C
836 macro name. */
837 char operator_name_uppercase [1000];
838 for (i = 0; te->operator->name [i] != '\0'; i ++)
839 operator_name_uppercase [i] = toupper (te->operator->name [i]);
840 operator_name_uppercase [i] = '\0';
841
842 EMIT(" JITTER_RULE_EXPRESSION_%s(\n", operator_name_uppercase);
843 FOR_LIST(i, comma, te->operand_expressions)
844 {
845 const struct jitterc_template_expression *oe
846 = gl_list_get_at (te->operand_expressions, i);
847 bool literal_expected = true; // FIXME: compute it for real.
848 jitterc_emit_rewrite_rule_template_expression (f, vm, oe,
849 literal_expected,
850 false);
851 EMIT(" %s\n", comma);
852 }
853 EMIT(" )\n");
854 break;
855 }
856
857 default:
858 jitter_fatal ("impossible template expression case");
859 }
860 }
861
862 /* Emit a condition matching the argument_idx-th argument of the
863 instruction_idx-th instruction (both 0-based) of the candidate instructions,
864 to the pointed stream for the pointed VM.
865 The generated code assumes that the opcode have already been matched, so the
866 arity is correct. */
867 static void
jitterc_emit_rewrite_rule_argument_condition(FILE * f,const struct jitterc_vm * vm,int instruction_idx,int argument_idx,const struct jitterc_argument_pattern * ap)868 jitterc_emit_rewrite_rule_argument_condition
869 (FILE *f,
870 const struct jitterc_vm *vm,
871 int instruction_idx,
872 int argument_idx,
873 const struct jitterc_argument_pattern *ap)
874 {
875 /* Generate a #line directive for the argument pattern, indepdendently from
876 its shape. */
877 jitterc_emit_hash_line(f, vm, ap->line_no, true);
878
879 /* If the argument pattern specifies a literal, check that it matches. This
880 is a good check to make first, as it will fail frequently. This check also
881 currently includes a check on the kind (required literal), subsumed by the
882 kind checks below; anyway GCC should have no problem merging them into one
883 conditional, since there are no side effects in between. */
884 if (ap->has_literal)
885 EMIT(" JITTER_RULE_CONDITION_MATCH_LITERAL_ARGUMENT(%i, %i, %"
886 JITTER_PRIi ")\n",
887 instruction_idx, argument_idx, ap->literal.fixnum);
888
889 /* If a kind bitmask is specified, check it. */
890 if (ap->kind != jitterc_instruction_argument_kind_unspecified)
891 {
892 /* A kind is a bitmask, and we accept any one match with a bit. This
893 means that the alternatives are in logical or. Using C's infix || is
894 more convenient here than our non-variadic prefix macros. */
895 EMIT(" JITTER_RULE_CONDITION(false\n");
896 if (ap->kind & jitterc_instruction_argument_kind_register)
897 EMIT(" || JITTER_RULE_ARGUMENT_IS_A_REGISTER(%i, %i)\n",
898 instruction_idx, argument_idx);
899 if (ap->kind & jitterc_instruction_argument_kind_literal)
900 EMIT(" || JITTER_RULE_ARGUMENT_IS_A_LITERAL(%i, %i)\n",
901 instruction_idx, argument_idx);
902 if (ap->kind & jitterc_instruction_argument_kind_label)
903 EMIT(" || JITTER_RULE_ARGUMENT_IS_A_LABEL(%i, %i)\n",
904 instruction_idx, argument_idx);
905 /* Close the logical or. */
906 EMIT(" )\n");
907 }
908
909 /* Match against a placeholder (destructively), if a placeholder name is
910 given. */
911 if (ap->placeholder_or_NULL != NULL)
912 EMIT(" JITTER_RULE_CONDITION_MATCH_PLACEHOLDER(%i, %i, %s)\n",
913 instruction_idx, argument_idx, ap->placeholder_or_NULL);
914 }
915
916 /* Generate content for the condition section of the pointed rewrite rule for
917 the pointed VM to the pointed stream. */
918 static void
jitterc_emit_rewrite_rule_condition(FILE * f,const struct jitterc_vm * vm,const struct jitterc_rule * rule)919 jitterc_emit_rewrite_rule_condition (FILE *f, const struct jitterc_vm *vm,
920 const struct jitterc_rule *rule)
921 {
922 int i, j; char *comma __attribute__ ((unused));
923
924 /* Check that the opcode of every candidate instruction matches its
925 pattern. */
926 EMIT(" /* Check opcodes first: they are likely not to match, and in */\n");
927 EMIT(" /* that case we want to fail as early as possible. */\n");
928 FOR_LIST(i, comma, rule->in_instruction_patterns)
929 {
930 const struct jitterc_instruction_pattern *ip
931 = gl_list_get_at (rule->in_instruction_patterns, i);
932 char *opcode = ip->instruction_name;
933 char *mangled_opcode = jitterc_mangle (opcode);
934 jitterc_emit_hash_line(f, vm, ip->line_no, true);
935 EMIT(" JITTER_RULE_CONDITION_MATCH_OPCODE(%i, %s)\n",
936 i, mangled_opcode);
937 free (mangled_opcode);
938 }
939
940 /* Then check instruction arguments against the template, binding placeholders
941 in the process. */
942 EMIT(" /* Check arguments, binding placeholders. We don't have to worry */\n");
943 EMIT(" /* about arity, since the opcodes match if we're here. */\n");
944 FOR_LIST(i, comma, rule->in_instruction_patterns)
945 {
946 const struct jitterc_instruction_pattern *ip
947 = gl_list_get_at (rule->in_instruction_patterns, i);
948 FOR_LIST(j, comma, ip->argument_patterns)
949 {
950 const struct jitterc_argument_pattern *ap
951 = gl_list_get_at (ip->argument_patterns, j);
952 jitterc_emit_rewrite_rule_argument_condition (f, vm, i, j, ap);
953 }
954 }
955
956 /* Emit the guard at the end, as it may use any placeholder. If that succeeds
957 as well the condition is satisfied. */
958 EMIT(" /* Rule guard. */\n");
959 EMIT(" JITTER_RULE_CONDITION(\n");
960 jitterc_emit_rewrite_rule_template_expression (f, vm, rule->guard, true,
961 false);
962 EMIT(" )\n");
963 }
964
965 /* Generate code for the pointed instruction template for the pointed VM to the
966 pointed stream. This is to be used within the body section of rules. */
967 void
jitterc_emit_rewrite_rule_instruction_template(FILE * f,const struct jitterc_vm * vm,const struct jitterc_instruction_template * it)968 jitterc_emit_rewrite_rule_instruction_template
969 (FILE *f,
970 const struct jitterc_vm *vm,
971 const struct jitterc_instruction_template *it)
972 {
973 /* Emit a #line directive for the instruction template. */
974 jitterc_emit_hash_line(f, vm, it->line_no, true);
975
976 /* Emit code to add the opcode. */
977 EMIT(" //fprintf (stderr, \" rewrite: adding instruction %s\\n\");\n",
978 it->instruction_name);
979 char *mangled_opcode = jitterc_mangle (it->instruction_name);
980 EMIT(" JITTER_RULE_APPEND_INSTRUCTION_(%s);\n", mangled_opcode);
981 free (mangled_opcode);
982
983 /* Emit code to add the instantiation of every argument template. */
984 int i; char *comma __attribute__ ((unused));
985 FOR_LIST(i, comma, it->argument_expressions)
986 {
987 const struct jitterc_template_expression *ae
988 = gl_list_get_at (it->argument_expressions, i);
989 EMIT(" //fprintf (stderr, \" instantiating the %i-th argument of %s\\n\");\n",
990 i, it->instruction_name);
991
992 // FIXME: make a rewriting-specific macro instead of using
993 // jitter_mutable_routine_append_parameter_copy ?
994 EMIT(" jitter_mutable_routine_append_parameter_copy (jitter_mutable_routine_p,\n");
995 jitterc_emit_rewrite_rule_template_expression (f, vm, ae, false, true);
996 EMIT(" );\n");
997 }
998 }
999
1000 /* Generate code for the pointed rewrite rule for the pointed VM to the pointed
1001 stream. */
1002 static void
jitterc_emit_rewrite_rule(FILE * f,const struct jitterc_vm * vm,const struct jitterc_rule * rule)1003 jitterc_emit_rewrite_rule (FILE *f, const struct jitterc_vm *vm,
1004 const struct jitterc_rule *rule)
1005 {
1006 int i; char *comma __attribute__ ((unused));
1007
1008 EMIT("/* Rewrite rule \"%s\" */\n", rule->name);
1009 int head_size = gl_list_size (rule->in_instruction_patterns);
1010
1011 /* Open the rule section. */
1012 jitterc_emit_hash_line(f, vm, rule->line_no, true);
1013 EMIT("JITTER_RULE_BEGIN(%i)\n", head_size);
1014
1015 /* Emit the placeholder declaration section. */
1016 EMIT(" JITTER_RULE_BEGIN_PLACEHOLDER_DECLARATIONS\n");
1017 FOR_LIST(i, comma, rule->placeholders)
1018 {
1019 const char *placeholder = gl_list_get_at (rule->placeholders, i);
1020 EMIT(" JITTER_RULE_DECLARE_PLACEHOLDER_(%s);\n",
1021 placeholder);
1022 }
1023 EMIT(" JITTER_RULE_END_PLACEHOLDER_DECLARATIONS\n");
1024
1025 /* Emit the placeholder declaration section. */
1026 EMIT(" JITTER_RULE_BEGIN_CONDITIONS\n");
1027 jitterc_emit_rewrite_rule_condition (f, vm, rule);
1028 EMIT(" JITTER_RULE_END_CONDITIONS\n");
1029
1030 /* Emit the placeholder cloning section. */
1031 EMIT(" JITTER_RULE_BEGIN_PLACEHOLDER_CLONING\n");
1032 FOR_LIST(i, comma, rule->placeholders)
1033 {
1034 const char *placeholder = gl_list_get_at (rule->placeholders, i);
1035 EMIT(" JITTER_RULE_CLONE_PLACEHOLDER_(%s);\n",
1036 placeholder);
1037 }
1038 EMIT(" JITTER_RULE_END_PLACEHOLDER_CLONING\n");
1039
1040 /* Emit the rule body, by compiling instruction templates one after the
1041 other. */
1042 EMIT(" JITTER_RULE_BEGIN_BODY\n");
1043 EMIT(" //fprintf (stderr, \"* The rule %s (line %i) fires...\\n\");\n",
1044 rule->name, rule->line_no);
1045 FOR_LIST(i, comma, rule->out_instruction_templates)
1046 {
1047 const struct jitterc_instruction_template *it
1048 = gl_list_get_at (rule->out_instruction_templates, i);
1049 jitterc_emit_rewrite_rule_instruction_template (f, vm, it);
1050 }
1051 EMIT(" //fprintf (stderr, \" ...End of the rule %s\\n\");\n",
1052 rule->name);
1053 EMIT(" JITTER_RULE_END_BODY\n");
1054
1055 /* Emit the placeholder destruction section. */
1056 EMIT(" JITTER_RULE_BEGIN_PLACEHOLDER_DESTRUCTION\n");
1057 FOR_LIST(i, comma, rule->placeholders)
1058 {
1059 const char *placeholder = gl_list_get_at (rule->placeholders, i);
1060 EMIT(" JITTER_RULE_DESTROY_PLACEHOLDER_(%s);\n",
1061 placeholder);
1062 }
1063 EMIT(" JITTER_RULE_END_PLACEHOLDER_DESTRUCTION\n");
1064
1065 /* Close the rule section, and we're done. */
1066 EMIT("JITTER_RULE_END\n");
1067 EMIT("\n");
1068 }
1069
1070 static void
jitterc_emit_rewriter(const struct jitterc_vm * vm)1071 jitterc_emit_rewriter (const struct jitterc_vm *vm)
1072 {
1073 FILE *f = jitterc_fopen_a_basename (vm, "vm1.c");
1074
1075 EMIT("void\n");
1076 EMIT("vmprefix_rewrite (struct jitter_mutable_routine *jitter_mutable_routine_p)\n");
1077 EMIT("{\n");
1078
1079 /* Add the common prolog, defining variables to be visible to the entire
1080 function body. */
1081 EMIT(" JITTTER_REWRITE_FUNCTION_PROLOG_;\n");
1082 EMIT("\n");
1083
1084 /* Add user-specified code for the rewriter. */
1085 jitterc_emit_user_c_code_to_stream (vm, f, vm->rewriter_c_code, "rewriter");
1086 EMIT("\n");
1087
1088 /* Generate code for the rules. */
1089 int i; char *comma __attribute__ ((unused));
1090 FOR_LIST(i, comma, vm->rewrite_rules)
1091 {
1092 const struct jitterc_rule *rule
1093 = ((const struct jitterc_rule*)
1094 gl_list_get_at (vm->rewrite_rules, i));
1095 EMIT("//asm volatile (\"\\n# checking %s\");\n", rule->name);
1096 EMIT("//fprintf (stderr, \"Trying rule %i of %i, \\\"%s\\\" (line %i)\\n\");\n",
1097 i + 1, (int) gl_list_size (vm->rewrite_rules),
1098 rule->name,
1099 rule->line_no);
1100 jitterc_emit_rewrite_rule (f, vm, rule);
1101 }
1102 EMIT("//fprintf (stderr, \"No more rules to try\\n\");\n");
1103
1104 EMIT("}\n");
1105 EMIT("\n\n");
1106 jitterc_fclose (f);
1107 }
1108
1109
1110
1111
1112 /* Specializer generation.
1113 * ************************************************************************** */
1114
1115 static void
jitterc_emit_specializer_recognizer_prototypes(FILE * f,const struct jitterc_specialized_instruction_tree * tree)1116 jitterc_emit_specializer_recognizer_prototypes
1117 (FILE *f,
1118 const struct jitterc_specialized_instruction_tree* tree)
1119 {
1120 EMIT("inline static enum vmprefix_specialized_instruction_opcode\n");
1121 EMIT("vmprefix_recognize_specialized_instruction_%s (struct jitter_parameter ** const ps,\n",
1122 tree->prefix_mangled_name);
1123 EMIT(" bool enable_fast_literals)\n");
1124 EMIT(" __attribute__ ((pure));\n");
1125 int i;
1126 for (i = 0; i < gl_list_size (tree->children); i ++)
1127 {
1128 const struct jitterc_specialized_instruction_tree_child *sarg_and_child
1129 = ((const struct jitterc_specialized_instruction_tree_child *)
1130 gl_list_get_at (tree->children, i));
1131 jitterc_emit_specializer_recognizer_prototypes (f, sarg_and_child->child);
1132 }
1133 }
1134
1135 static void
jitterc_emit_specializer_recognizers(FILE * f,const struct jitterc_vm * vm,const struct jitterc_specialized_instruction_tree * tree)1136 jitterc_emit_specializer_recognizers
1137 (FILE *f,
1138 const struct jitterc_vm *vm,
1139 const struct jitterc_specialized_instruction_tree* tree)
1140 {
1141 EMIT("inline static enum vmprefix_specialized_instruction_opcode\n");
1142 EMIT("vmprefix_recognize_specialized_instruction_%s (struct jitter_parameter ** const ps,\n",
1143 tree->prefix_mangled_name);
1144 EMIT(" bool enable_fast_literals)\n");
1145 EMIT("{\n");
1146 if (gl_list_size (tree->children) == 0)
1147 {
1148 EMIT(" /* The prefix is a full specialized instruction. We're done recognizing it. */\n");
1149 if (tree->specialized_instruction == NULL)
1150 EMIT(" jitter_fatal (\"No specialised instruction exists to \"\n"
1151 " \"complete %s/... (zero fast registers and no \"\n"
1152 " \"slow registers?)\");\n",
1153 tree->prefix_name);
1154 else
1155 EMIT(" return vmprefix_specialized_instruction_opcode_%s;\n",
1156 tree->specialized_instruction->mangled_name);
1157 EMIT("}\n\n");
1158 /* There's nothing more in this subtree. */
1159 return;
1160 }
1161
1162 EMIT(" enum vmprefix_specialized_instruction_opcode res = vmprefix_specialized_instruction_opcode_%s;\n",
1163 jitterc_mangle ("!INVALID"));
1164 int i;
1165 for (i = 0; i < gl_list_size (tree->children); i ++)
1166 {
1167 const struct jitterc_specialized_instruction_tree_child *sarg_and_child
1168 = ((const struct jitterc_specialized_instruction_tree_child *)
1169 gl_list_get_at (tree->children, i));
1170 const struct jitterc_specialized_argument *sarg
1171 = sarg_and_child->specialized_argument;
1172 const struct jitterc_specialized_instruction_tree *child
1173 = sarg_and_child->child;
1174 EMIT(" if ((");
1175 switch (sarg->kind)
1176 {
1177 case jitterc_instruction_argument_kind_literal:
1178 EMIT("(* ps)->type == jitter_parameter_type_literal");
1179 if (! sarg->residual)
1180 // FIXME: this will need generatilzation with more literal types.
1181 EMIT(" && (* ps)->literal.fixnum == %li && enable_fast_literals",
1182 (long) sarg->nonresidual_literal->value.fixnum);
1183 break;
1184 case jitterc_instruction_argument_kind_register:
1185 EMIT("(* ps)->type == jitter_parameter_type_register_id");
1186 // FIXME: this will need generatilzation with more register classes; or, more likely, not.
1187 if (! sarg->residual)
1188 EMIT(" && (* ps)->register_index == %u",
1189 (unsigned) sarg->nonresidual_register->index);
1190 break;
1191 case jitterc_instruction_argument_kind_label:
1192 case jitterc_instruction_argument_kind_fast_label:
1193 EMIT("(* ps)->type == jitter_parameter_type_label");
1194 if (! sarg->residual)
1195 jitter_fatal ("non-residual label: this should not happen");
1196 break;
1197 default:
1198 jitter_fatal ("jitterc_emit_specializer_recognizers: unhandled kind");
1199 }
1200 EMIT(")\n");
1201 EMIT(" && (res = vmprefix_recognize_specialized_instruction_%s (ps + 1, enable_fast_literals)))\n",
1202 child->prefix_mangled_name);
1203 EMIT(" goto done;\n");
1204 }
1205 EMIT("done:\n");
1206 EMIT(" return res;\n");
1207 EMIT("}\n\n");
1208
1209 /* Generate definitions for every subtree. */
1210 for (i = 0; i < gl_list_size (tree->children); i ++)
1211 {
1212 const struct jitterc_specialized_instruction_tree_child *sarg_and_child
1213 = ((const struct jitterc_specialized_instruction_tree_child *)
1214 gl_list_get_at (tree->children, i));
1215 jitterc_emit_specializer_recognizers (f, vm, sarg_and_child->child);
1216 }
1217 }
1218
1219 static void
jitterc_emit_specializer(const struct jitterc_vm * vm)1220 jitterc_emit_specializer (const struct jitterc_vm *vm)
1221 {
1222 FILE *f = jitterc_fopen_a_basename (vm, "vm1.c");
1223 EMIT("//#include <jitter/jitter-fatal.h>\n");
1224 EMIT("\n");
1225 EMIT("//#include <jitter/jitter.h>\n");
1226 EMIT("//#include <jitter/jitter-instruction.h>\n");
1227 EMIT("//#include <jitter/jitter-specialize.h>\n");
1228 EMIT("\n");
1229 EMIT("//#include \"vmprefix-vm.h\"\n");
1230 EMIT("//#include \"vmprefix-meta-instructions.h\"\n");
1231 EMIT("//#include \"vmprefix-specialized-instructions.h\"\n");
1232 EMIT("\n\n");
1233 EMIT("/* Recognizer function prototypes. */\n");
1234 int i; char *comma __attribute__ ((unused));
1235 #define LET_TREE \
1236 const struct jitterc_specialized_instruction_tree *tree \
1237 = ((const struct jitterc_specialized_instruction_tree*) \
1238 gl_list_get_at (vm->specialized_instruction_forest, i))
1239 /* First generate a function prototype per specialized instruction prefix
1240 recognizer. I want to declare them all before the first definition, to
1241 be able to call the functions in any order. */
1242 FOR_LIST(i, comma, vm->specialized_instruction_forest)
1243 {
1244 LET_TREE;
1245 jitterc_emit_specializer_recognizer_prototypes (f, tree);
1246 }
1247 EMIT("\n\n");
1248
1249 /* Generate the actual definitions. */
1250 EMIT("/* Recognizer function definitions. */\n");
1251 FOR_LIST(i, comma, vm->specialized_instruction_forest)
1252 {
1253 LET_TREE;
1254 jitterc_emit_specializer_recognizers (f, vm, tree);
1255 }
1256 #undef LET_TREE
1257 EMIT("\n\n");
1258
1259 /* Generate the main recognizer function. */
1260 EMIT("/* Recognizer entry point. */\n");
1261 EMIT("static enum vmprefix_specialized_instruction_opcode\n");
1262 EMIT("vmprefix_recognize_specialized_instruction (struct jitter_mutable_routine *p,\n");
1263 EMIT(" const struct jitter_instruction *ins)\n");
1264 EMIT("{\n");
1265 EMIT(" bool fl = ! p->options.slow_literals_only;\n");
1266 EMIT(" const struct jitter_meta_instruction *mi = ins->meta_instruction;\n");
1267 EMIT(" switch (mi->id)\n");
1268 EMIT(" {\n");
1269 FOR_LIST(i, comma, vm->instructions)
1270 {
1271 const struct jitterc_instruction* ins
1272 = ((const struct jitterc_instruction*)
1273 gl_list_get_at (vm->instructions, i));
1274 EMIT(" case vmprefix_meta_instruction_id_%s:\n", ins->mangled_name);
1275 EMIT(" return vmprefix_recognize_specialized_instruction_%s (ins->parameters, fl);\n",
1276 ins->mangled_name);
1277 }
1278 EMIT(" default:\n");
1279 EMIT(" jitter_fatal (\"invalid meta-instruction id %%i\", (int)mi->id);\n");
1280 EMIT(" }\n");
1281 EMIT(" __builtin_unreachable ();\n");
1282 EMIT("}\n\n");
1283
1284 /* Generate the specializer function. */
1285 EMIT("/* Specializer entry point: the only non-static function here. */\n");
1286 EMIT("int\n");
1287 EMIT("vmprefix_specialize_instruction (struct jitter_mutable_routine *p,\n");
1288 EMIT(" const struct jitter_instruction *ins)\n");
1289 EMIT("{\n");
1290 EMIT(" enum vmprefix_specialized_instruction_opcode opcode\n");
1291 EMIT(" = vmprefix_recognize_specialized_instruction (p, ins);\n");
1292 EMIT(" if (opcode == vmprefix_specialized_instruction_opcode_%s)\n",
1293 jitterc_mangle ("!INVALID"));
1294 EMIT(" jitter_fatal (\"specialization failed: %%s\", ins->meta_instruction->name);\n");
1295 EMIT("\n");
1296 EMIT("#ifdef JITTER_HAVE_PATCH_IN\n");
1297 EMIT(" /* Replace the opcode with its non-defective counterpart. */\n");
1298 EMIT(" opcode = vmprefix_defect_table [opcode];\n");
1299 EMIT("#endif // #ifdef JITTER_HAVE_PATCH_IN\n");
1300 EMIT("\n");
1301 EMIT(" jitter_add_specialized_instruction_opcode (p, opcode);\n");
1302 EMIT("\n");
1303 EMIT("\n");
1304 EMIT(" /* FIXME: in the old shell-based generator I grouped specialized instructions by\n");
1305 EMIT(" their \"residual parameter map\", yielding a switch with a lot of different\n");
1306 EMIT(" specialized instructions mapping to the same case. I should redo that here. */\n");
1307 EMIT(" switch (opcode)\n");
1308 EMIT(" {\n");
1309 FOR_LIST(i, comma, vm->specialized_instructions)
1310 {
1311 const struct jitterc_specialized_instruction* sins
1312 = ((const struct jitterc_specialized_instruction*)
1313 gl_list_get_at (vm->specialized_instructions, i));
1314 EMIT(" case vmprefix_specialized_instruction_opcode_%s:\n", sins->mangled_name);
1315 const struct jitterc_instruction* uins = sins->instruction;
1316
1317 /* Emit code to add residual residual arguments to the threads, except for
1318 the last arguments of non-relocatable and caller instructions, which
1319 are special. */
1320 size_t residual_no = gl_list_size (sins->specialized_arguments);
1321 bool is_non_relocatable
1322 = ( uins != NULL
1323 && sins->relocatability == jitterc_relocatability_non_relocatable);
1324 bool is_caller
1325 = ( uins != NULL
1326 && uins->callerness == jitterc_callerness_caller);
1327 if (is_non_relocatable || is_caller)
1328 residual_no --;
1329 int j;
1330 for (j = 0; j < residual_no; j ++)
1331 {
1332 const struct jitterc_specialized_argument* sarg
1333 = ((const struct jitterc_specialized_argument*)
1334 gl_list_get_at (sins->specialized_arguments, j));
1335 if (! sarg->residual)
1336 continue;
1337 switch (sarg->kind)
1338 {
1339 case jitterc_instruction_argument_kind_register:
1340 EMIT(" /* A slow register is passed as a residual literal offset. */");
1341 EMIT(" jitter_add_specialized_instruction_literal (p, VMPREFIX_SLOW_REGISTER_OFFSET(%c, ins->parameters[%i]->register_index));\n",
1342 sarg->unspecialized->register_class_character, j);
1343 break;
1344 case jitterc_instruction_argument_kind_literal:
1345 EMIT(" jitter_add_specialized_instruction_literal (p, ins->parameters[%i]->literal.ufixnum);\n", j);
1346 break;
1347 case jitterc_instruction_argument_kind_label:
1348 case jitterc_instruction_argument_kind_fast_label:
1349 EMIT(" jitter_add_specialized_instruction_label_index (p, ins->parameters[%i]->label_as_index);\n", j);
1350 break;
1351 default:
1352 jitter_fatal ("jitterc_emit_specializer: unhandled kind");
1353 }
1354 }
1355
1356 /* Add one more residual argument in case of a non-relocatable
1357 instruction, as a placeholder for the return label. */
1358 if (is_non_relocatable)
1359 {
1360 EMIT(" /* Non-relocatable instruction: make place for the return label,\n");
1361 EMIT(" whose correct value will be patched in at specialization time. */\n");
1362 EMIT(" jitter_add_specialized_instruction_literal (p, -1);\n");
1363 }
1364
1365 /* Add one more residual argument in case of a caller instruction, as a
1366 placeholder for the return label. */
1367 if (is_caller)
1368 {
1369 EMIT(" /* Caller instruction: make place for the return address,\n");
1370 EMIT(" whose correct value will be patched in at specialization time. */\n");
1371 EMIT(" jitter_add_specialized_instruction_literal (p, -1);\n");
1372 }
1373
1374 /* Done handling sins . */
1375 EMIT(" break;\n\n");
1376 }
1377 EMIT(" default:\n");
1378 EMIT(" jitter_fatal (\"invalid specialized instruction opcode %%i\", (int)opcode);\n");
1379 EMIT(" }\n");
1380 EMIT(" return 1; // FIXME: I should rethink this return value.\n");
1381 EMIT("}\n\n");
1382
1383 jitterc_fclose (f);
1384 }
1385
1386
1387
1388
1389 /* VM stack support.
1390 * ************************************************************************** */
1391
1392 /* Emit an upper-case conversion of the given lower-case string. */
1393 static void
jitterc_emit_upper_case(FILE * f,const char * lower_case_string)1394 jitterc_emit_upper_case (FILE *f, const char *lower_case_string)
1395 {
1396 const char *p;
1397 for (p = lower_case_string; *p != '\0'; p ++)
1398 EMIT("%c", toupper (* p));
1399 }
1400
1401 /* Emit the CPP definition of a stack operation, to be called by user code
1402 within instructions. The generated macro is a wrapper around a stack
1403 operation defined in jitter/jitter-stack.h . */
1404 static void
jitterc_emit_stack_operation_definition(FILE * f,const struct jitterc_stack * stack,const char * lower_case_operation_name,size_t arity)1405 jitterc_emit_stack_operation_definition (FILE *f,
1406 const struct jitterc_stack *stack,
1407 const char *lower_case_operation_name,
1408 size_t arity)
1409 {
1410 assert (stack->implementation == jitterc_stack_implementation_tos
1411 || stack->implementation == jitterc_stack_implementation_no_tos);
1412 EMIT("/* Wrapper definition of the %s operation for the %s stack \"%s\". */\n",
1413 lower_case_operation_name,
1414 ((stack->implementation == jitterc_stack_implementation_tos)
1415 ? "TOS-optimized" : "non-TOS-optimized"),
1416 stack->lower_case_long_name);
1417 EMIT("#define JITTER_");
1418 jitterc_emit_upper_case (f, lower_case_operation_name);
1419 EMIT("_%s(", stack->upper_case_long_name);
1420 int i;
1421 for (i = 0; i < arity; i ++)
1422 EMIT("x%i%s", i, i != (arity - 1) ? ", ": "");
1423 const char *optimization_suffix
1424 = (stack->implementation == jitterc_stack_implementation_tos) ? "TOS" : "NTOS";
1425 EMIT(") \\\n");
1426 EMIT(" JITTER_STACK_%s_", optimization_suffix);
1427 jitterc_emit_upper_case (f, lower_case_operation_name);
1428 EMIT("(%s, jitter_state_runtime. , %s", stack->c_type,
1429 stack->lower_case_long_name);
1430 for (i = 0; i < arity; i ++)
1431 EMIT(", x%i", i);
1432 EMIT(")\n\n");
1433 }
1434
1435 /* Emit CPP definitions for stack operations, for every stack of the pointed
1436 VM. */
1437 static void
jitterc_emit_stack_operation_definitions(FILE * f,const struct jitterc_vm * vm)1438 jitterc_emit_stack_operation_definitions (FILE *f, const struct jitterc_vm *vm)
1439 {
1440 int i; char *comma __attribute__ ((unused));
1441 FOR_LIST(i, comma, vm->stacks)
1442 {
1443 const struct jitterc_stack *stack = gl_list_get_at (vm->stacks, i);
1444 jitterc_emit_stack_operation_definition (f, stack, "top", 0);
1445 jitterc_emit_stack_operation_definition (f, stack, "under_top", 0);
1446 jitterc_emit_stack_operation_definition (f, stack, "at_depth", 1);
1447 jitterc_emit_stack_operation_definition (f, stack, "at_nonzero_depth", 1);
1448 jitterc_emit_stack_operation_definition (f, stack, "set_at_depth", 2);
1449 jitterc_emit_stack_operation_definition (f, stack, "set_at_nonzero_depth", 2);
1450 jitterc_emit_stack_operation_definition (f, stack, "push_unspecified", 0);
1451 jitterc_emit_stack_operation_definition (f, stack, "push", 1);
1452
1453 jitterc_emit_stack_operation_definition (f, stack, "drop", 0);
1454 jitterc_emit_stack_operation_definition (f, stack, "dup", 0);
1455 jitterc_emit_stack_operation_definition (f, stack, "swap", 0);
1456 jitterc_emit_stack_operation_definition (f, stack, "quake", 0);
1457 jitterc_emit_stack_operation_definition (f, stack, "over", 0);
1458 jitterc_emit_stack_operation_definition (f, stack, "tuck", 0);
1459 jitterc_emit_stack_operation_definition (f, stack, "nip", 0);
1460 jitterc_emit_stack_operation_definition (f, stack, "rot", 0);
1461 jitterc_emit_stack_operation_definition (f, stack, "mrot", 0);
1462 jitterc_emit_stack_operation_definition (f, stack, "roll", 1);
1463 jitterc_emit_stack_operation_definition (f, stack, "mroll", 1);
1464 jitterc_emit_stack_operation_definition (f, stack, "slide", 2);
1465 jitterc_emit_stack_operation_definition (f, stack, "whirl", 1);
1466 jitterc_emit_stack_operation_definition (f, stack, "bulge", 1);
1467
1468 jitterc_emit_stack_operation_definition (f, stack, "height", 0);
1469 jitterc_emit_stack_operation_definition (f, stack, "set_height", 1);
1470
1471 jitterc_emit_stack_operation_definition (f, stack, "reverse", 1);
1472
1473 jitterc_emit_stack_operation_definition (f, stack, "unary", 1);
1474 jitterc_emit_stack_operation_definition (f, stack, "binary", 1); // Not a mistake.
1475 }
1476 }
1477
1478 /* Emit data structure declarations for VM stack backings. This generates code
1479 within the state backing struct containined within the VM state struct. */
1480 static void
jitterc_emit_stack_backing_declarations(FILE * f,const struct jitterc_vm * vm)1481 jitterc_emit_stack_backing_declarations (FILE *f, const struct jitterc_vm *vm)
1482 {
1483 EMIT(" /* Stack backing data structures. */\n");
1484 int i; char *comma __attribute__ ((unused));
1485 FOR_LIST(i, comma, vm->stacks)
1486 {
1487 const struct jitterc_stack *stack = gl_list_get_at (vm->stacks, i);
1488
1489 EMIT(" struct jitter_stack_backing jitter_stack_%s_backing;\n", stack->lower_case_long_name);
1490 }
1491 EMIT("\n");
1492 }
1493
1494 /* Emit data structure declarations for VM stacks. This generates code within
1495 the state runtime struct containined within the VM state struct. */
1496 static void
jitterc_emit_stack_runtime_declarations(FILE * f,const struct jitterc_vm * vm)1497 jitterc_emit_stack_runtime_declarations (FILE *f, const struct jitterc_vm *vm)
1498 {
1499 EMIT(" /* Stack runtime data structures. */\n");
1500 int i; char *comma __attribute__ ((unused));
1501 FOR_LIST(i, comma, vm->stacks)
1502 {
1503 const struct jitterc_stack *stack = gl_list_get_at (vm->stacks, i);
1504
1505 assert (stack->implementation == jitterc_stack_implementation_tos
1506 || stack->implementation == jitterc_stack_implementation_no_tos);
1507 const char *optimization_suffix
1508 = ((stack->implementation == jitterc_stack_implementation_tos)
1509 ? "TOS" : "NTOS");
1510 EMIT(" JITTER_STACK_%s_DECLARATION(%s, %s);\n",
1511 optimization_suffix,
1512 stack->c_type,
1513 stack->lower_case_long_name);
1514 }
1515 EMIT("\n");
1516 }
1517
1518 /* Emit initialization code for VM stacks. This generates code within the VM
1519 state initialization function. */
1520 static void
jitterc_emit_stack_initializations(FILE * f,const struct jitterc_vm * vm)1521 jitterc_emit_stack_initializations (FILE *f, const struct jitterc_vm *vm)
1522 {
1523 EMIT(" /* Initialize stack backings and stack runtime data structures, pointing\n");
1524 EMIT(" to memory from the backings. */\n");
1525 int i; char *comma __attribute__ ((unused));
1526 FOR_LIST(i, comma, vm->stacks)
1527 {
1528 const struct jitterc_stack *stack = gl_list_get_at (vm->stacks, i);
1529
1530 assert (stack->implementation == jitterc_stack_implementation_tos
1531 || stack->implementation == jitterc_stack_implementation_no_tos);
1532 const char *optimization_lower_case_suffix
1533 = ((stack->implementation == jitterc_stack_implementation_tos)
1534 ? "tos" : "ntos");
1535 const char *optimization_upper_case_suffix
1536 = ((stack->implementation == jitterc_stack_implementation_tos)
1537 ? "TOS" : "NTOS");
1538 char *c_type = stack->c_type;
1539 char *c_initial_value = stack->c_initial_value;
1540 const unsigned long element_no = stack->element_no;
1541 int guard_underflow = stack->guard_underflow;
1542 int guard_overflow = stack->guard_overflow;
1543 char element_pointer_name [121];
1544 if (c_initial_value != NULL)
1545 {
1546 char element_name [100];
1547 sprintf (element_name,
1548 "jitter_stack_%c_initial_element", stack->letter);
1549 EMIT(" %s %s = (%s) (%s);\n",
1550 c_type, element_name, c_type, c_initial_value);
1551 sprintf (element_pointer_name, "(char *) & %s", element_name);
1552 }
1553 else
1554 sprintf (element_pointer_name, "NULL");
1555
1556 EMIT(" jitter_stack_initialize_%s_backing(& jitter_state_backing->jitter_stack_%s_backing,\n",
1557 optimization_lower_case_suffix, stack->lower_case_long_name);
1558 EMIT(" sizeof (%s),\n",
1559 stack->c_type);
1560 EMIT(" %lu,\n", element_no);
1561 EMIT(" %s,\n", element_pointer_name);
1562 EMIT(" %i,\n", guard_underflow);
1563 EMIT(" %i);\n", guard_overflow);
1564 EMIT(" JITTER_STACK_%s_INITIALIZE(%s, jitter_state_runtime-> ,\n",
1565 optimization_upper_case_suffix, stack->c_type);
1566 EMIT(" %s, jitter_state_backing->jitter_stack_%s_backing);\n",
1567 stack->lower_case_long_name, stack->lower_case_long_name);
1568 }
1569 EMIT("\n");
1570 }
1571
1572 /* Emit finalization code for VM stacks. This generates code within the VM
1573 state finalization function. */
1574 static void
jitterc_emit_stack_finalizations(FILE * f,const struct jitterc_vm * vm)1575 jitterc_emit_stack_finalizations (FILE *f, const struct jitterc_vm *vm)
1576 {
1577 EMIT(" /* Finalize stack backings -- There is no need to finalize the stack\n");
1578 EMIT(" runtime data structures, as they hold no heap data of their own. */\n");
1579 int i; char *comma __attribute__ ((unused));
1580 FOR_LIST(i, comma, vm->stacks)
1581 {
1582 const struct jitterc_stack *stack = gl_list_get_at (vm->stacks, i);
1583
1584 EMIT(" jitter_stack_finalize_backing (& jitter_state_backing->jitter_stack_%s_backing);\n",
1585 stack->lower_case_long_name);
1586 }
1587 EMIT("\n");
1588 }
1589
1590 /* Emit initialisation code for VM registers. This generates code within the VM
1591 state initialisation function. */
1592 static void
jitterc_emit_register_initializations(FILE * f,const struct jitterc_vm * vm)1593 jitterc_emit_register_initializations (FILE *f, const struct jitterc_vm *vm)
1594 {
1595 EMIT(" /* Initialise the link register, if present. */\n");
1596 EMIT("#if defined(JITTER_DISPATCH_SWITCH) \\\n");
1597 EMIT(" || defined(JITTER_DISPATCH_DIRECT_THREADING) \\\n");
1598 EMIT(" || defined(JITTER_DISPATCH_MINIMAL_THREADING) \\\n");
1599 EMIT(" || ( defined(JITTER_DISPATCH_NO_THREADING) \\\n");
1600 EMIT(" && ! defined(JITTER_MACHINE_SUPPORTS_PROCEDURE))\n");
1601 EMIT(" jitter_state_runtime->_jitter_link = NULL;\n");
1602 EMIT("#endif\n");
1603 EMIT("\n");
1604
1605 int i; char *comma __attribute__ ((unused));
1606 FOR_LIST(i, comma, vm->register_classes)
1607 {
1608 const struct jitterc_register_class *rc
1609 = gl_list_get_at (vm->register_classes, i);
1610
1611 if (rc->c_initial_value != NULL)
1612 {
1613 EMIT(" /* Initialise %c-class fast registers. */\n", rc->letter);
1614 int j;
1615 for (j = 0; j < rc->fast_register_no; j ++)
1616 {
1617 EMIT(" jitter_state_runtime->jitter_fast_register_%c_%i\n",
1618 rc->letter, j);
1619 EMIT(" = (%s) (%s);\n", rc->c_type, rc->c_initial_value);
1620 }
1621 }
1622 else
1623 EMIT(" /* No need to initialise %c-class fast registers. */\n", rc->letter);
1624 EMIT("\n");
1625 }
1626 EMIT("\n");
1627 }
1628
1629 /* There is no register finalisation code. */
1630
1631
1632
1633
1634
1635 /* VM state.
1636 * ************************************************************************** */
1637
1638 static void
jitterc_emit_state_h(const struct jitterc_vm * vm)1639 jitterc_emit_state_h (const struct jitterc_vm *vm)
1640 {
1641 FILE *f = jitterc_fopen_a_basename (vm, "vm.h");
1642 EMIT("#ifndef VMPREFIX_STATE_H_\n");
1643 EMIT("#define VMPREFIX_STATE_H_\n\n");
1644 EMIT("//#include <jitter/jitter.h>\n\n");
1645
1646 /* Insert C code from the user. This is supposed to come in before the struct
1647 definition. */
1648 EMIT("/* Early C code from the user for the state definition. */\n");
1649 EMIT("%s", vm->state_early_c_code);
1650 EMIT("/* End of the early C code from the user for the state definition. */\n\n");
1651
1652 EMIT("/* The VM state backing. */\n");
1653 EMIT("struct vmprefix_state_backing\n");
1654 EMIT("{\n");
1655 EMIT(" /* The Array. This initial pointer is kept in the backing, since it is\n");
1656 EMIT(" not normally needed at run time. By subtracting JITTER_ARRAY_BIAS from\n");
1657 EMIT(" it (as a pointer to char) we get the base pointer. */\n");
1658 EMIT(" char *jitter_array;\n");
1659 EMIT("\n");
1660 EMIT(" /* How many slow registers per class the Array can hold, without being\n");
1661 EMIT(" reallocated. This number is always the same for evey class. */\n");
1662 EMIT(" jitter_int jitter_slow_register_no_per_class;\n");
1663 EMIT("\n");
1664
1665 /* Emit declarations for stack backing data structures. */
1666 jitterc_emit_stack_backing_declarations (f, vm);
1667
1668 EMIT(" /* State backing fields added in C by the user. */\n");
1669 EMIT("%s", vm->state_backing_struct_c_code);
1670 EMIT("\n /* End of the state backing fields added in C by the user. */\n");
1671 EMIT("};\n");
1672 EMIT("\n");
1673
1674 EMIT("/* The VM state runtime data structure, using memory from the VM state backing. */\n");
1675 EMIT("struct vmprefix_state_runtime\n");
1676 EMIT("{\n");
1677 EMIT("#if defined(JITTER_DISPATCH_SWITCH) \\\n");
1678 EMIT(" || defined(JITTER_DISPATCH_DIRECT_THREADING) \\\n");
1679 EMIT(" || defined(JITTER_DISPATCH_MINIMAL_THREADING) \\\n");
1680 EMIT(" || ( defined(JITTER_DISPATCH_NO_THREADING) \\\n");
1681 EMIT(" && ! defined(JITTER_MACHINE_SUPPORTS_PROCEDURE))\n");
1682 EMIT(" /* A link register for branch-and-link operations. This field must *not*\n");
1683 EMIT(" be accessed from user code, as it may not exist on all dispatching\n");
1684 EMIT(" models. It is only used internally for JITTER_PROCEDURE_PROLOG. */\n");
1685 EMIT(" const union jitter_word *_jitter_link;\n");
1686 EMIT("#endif\n");
1687 EMIT("\n");
1688 EMIT(" /* With recent GCC versions (as of Summer 2017) the *last* declared fields\n");
1689 EMIT(" are the most likely to be allocated in registers; this is why VM registers\n");
1690 EMIT(" are in reverse order here. The first few fast registers will be the \"fastest\"\n");
1691 EMIT(" ones, allocated in hardware registers; they may be followed by other fast\n");
1692 EMIT(" fast allocated on the stack at known offsets, with intermediate performance; then\n");
1693 EMIT(" come the slow registers. In critical code the users should prefer a register with as\n");
1694 EMIT(" small an index as possible for best performance. */\n");
1695 int i; char *comma __attribute__ ((unused));
1696 FOR_LIST(i, comma, vm->register_classes)
1697 {
1698 const struct jitterc_register_class *c
1699 = (gl_list_get_at (vm->register_classes, i));
1700 int j;
1701 for (j = c->fast_register_no - 1; j >= 0; j --)
1702 EMIT(" vmprefix_register_%c jitter_fast_register_%c_%i;\n",
1703 c->letter, c->letter, j);
1704 }
1705 EMIT("\n");
1706
1707 /* Emit declarations for stack runtime data structures. */
1708 jitterc_emit_stack_runtime_declarations (f, vm);
1709
1710 /* Insert C code from the user. This is supposed to contain struct fields. */
1711 EMIT(" /* State runtime fields added in C by the user. */\n");
1712 EMIT("%s", vm->state_runtime_struct_c_code);
1713 EMIT("\n /* End of the state runtime fields added in C by the user. */\n");
1714
1715 EMIT("};\n");
1716 EMIT("\n");
1717
1718 EMIT("/* A struct holding both the backing and the runtime part of the VM state. */\n");
1719 EMIT("struct vmprefix_state\n");
1720 EMIT("{\n");
1721 EMIT(" /* Pointers to the previous and next VM state for this VM. */\n");
1722 EMIT(" struct jitter_list_links links;\n");
1723 EMIT("\n");
1724 EMIT(" /* Each state data structure contains its backing. */\n");
1725 EMIT(" struct vmprefix_state_backing vmprefix_state_backing;\n");
1726 EMIT("\n");
1727 EMIT(" /* Each state data structure contains its runtime data structures,\n");
1728 EMIT(" to be allocated to registers as long as possible, and using\n");
1729 EMIT(" memory from the backing. */\n");
1730 EMIT(" struct vmprefix_state_runtime vmprefix_state_runtime;\n");
1731 EMIT("};\n");
1732
1733 EMIT("#endif // #ifndef VMPREFIX_STATE_H_\n");
1734 jitterc_fclose (f);
1735 }
1736
1737 static void
jitterc_emit_state(const struct jitterc_vm * vm)1738 jitterc_emit_state (const struct jitterc_vm *vm)
1739 {
1740 FILE *f = jitterc_fopen_a_basename (vm, "vm1.c");
1741
1742 EMIT("void\n");
1743 EMIT("vmprefix_state_initialize (struct vmprefix_state *jitter_state)\n");
1744 EMIT("{\n");
1745 EMIT(" struct vmprefix_state_backing * const jitter_state_backing\n");
1746 EMIT(" __attribute__ ((unused))\n");
1747 EMIT(" = & jitter_state->vmprefix_state_backing;\n");
1748 EMIT(" struct vmprefix_state_runtime * const jitter_state_runtime\n");
1749 EMIT(" __attribute__ ((unused))\n");
1750 EMIT(" = & jitter_state->vmprefix_state_runtime;\n");
1751 EMIT("\n");
1752
1753 EMIT(" /* Initialize the Array. */\n");
1754 EMIT(" jitter_state_backing->jitter_slow_register_no_per_class = 0; // FIXME: raise?\n");
1755 EMIT(" jitter_state_backing->jitter_array\n");
1756 EMIT(" = jitter_xmalloc (VMPREFIX_ARRAY_SIZE(jitter_state_backing\n");
1757 EMIT(" ->jitter_slow_register_no_per_class));\n");
1758 EMIT("\n");
1759 EMIT(" /* Initialize special-purpose data. */\n");
1760 EMIT(" vmprefix_initialize_special_purpose_data (VMPREFIX_ARRAY_TO_SPECIAL_PURPOSE_STATE_DATA (jitter_state_backing->jitter_array));\n");
1761 EMIT("\n");
1762
1763 /* Emit initialisation code for stacks and registers. */
1764 jitterc_emit_stack_initializations (f, vm);
1765 jitterc_emit_register_initializations (f, vm);
1766
1767 EMIT(" /* User code for state initialization. */\n");
1768 EMIT("%s\n", vm->state_initialization_c_code);
1769 EMIT(" /* End of the user code for state initialization. */\n");
1770 EMIT("\n");
1771 EMIT(" /* Link this new state to the list of states. */\n");
1772 EMIT(" JITTER_LIST_LINK_LAST (vmprefix_state, links, & vmprefix_vm->states, jitter_state);\n");
1773 EMIT("\n");
1774 EMIT("}\n");
1775 EMIT("\n");
1776
1777 EMIT("void\n");
1778 EMIT("vmprefix_state_finalize (struct vmprefix_state *jitter_state)\n");
1779 EMIT("{\n");
1780 EMIT(" /* Unlink this new state from the list of states. */\n");
1781 EMIT(" JITTER_LIST_UNLINK (vmprefix_state, links, & vmprefix_vm->states, jitter_state);\n");
1782 EMIT("\n");
1783 EMIT(" struct vmprefix_state_backing * const jitter_state_backing\n");
1784 EMIT(" __attribute__ ((unused))\n");
1785 EMIT(" = & jitter_state->vmprefix_state_backing;\n");
1786 EMIT(" struct vmprefix_state_runtime * const jitter_state_runtime\n");
1787 EMIT(" __attribute__ ((unused))\n");
1788 EMIT(" = & jitter_state->vmprefix_state_runtime;\n");
1789 EMIT("\n");
1790 EMIT(" /* Finalize special-purpose data. */\n");
1791 EMIT(" vmprefix_finalize_special_purpose_data (VMPREFIX_ARRAY_TO_SPECIAL_PURPOSE_STATE_DATA (jitter_state_backing->jitter_array));\n");
1792 EMIT("\n");
1793
1794 /* Emit finalization for stacks. */
1795 jitterc_emit_stack_finalizations (f, vm);
1796 EMIT("\n");
1797
1798 EMIT(" /* User code for state finalization. */\n");
1799 EMIT("%s\n", vm->state_finalization_c_code);
1800 EMIT(" /* End of the user code for state finalization. */\n");
1801 EMIT("\n");
1802 EMIT(" /* Finalize the Array. */\n");
1803 EMIT(" free ((void *) jitter_state_backing->jitter_array);\n");
1804 EMIT("\n");
1805 EMIT("}\n\n");
1806
1807 jitterc_fclose (f);
1808 }
1809
1810
1811
1812
1813 /* VM configuration.
1814 * ************************************************************************** */
1815
1816 /* Emit configuration macros. These are mostly useful to statically initialise
1817 the one instance of struct jitter_vm_configuration , to be used in --version
1818 and similar, and for for vm-main.c . */
1819 static void
jitterc_emit_configuration_macros(const struct jitterc_vm * vm)1820 jitterc_emit_configuration_macros (const struct jitterc_vm *vm)
1821 {
1822 FILE *f = jitterc_fopen_a_basename (vm, "vm.h");
1823
1824 EMIT("/* Configuration data for struct jitter_vm_configuration. */\n");
1825 char *name = vm->name;
1826 if (name == NULL)
1827 {
1828 name = jitter_clone_string (vm->lower_case_prefix);
1829 if (strlen (name) > 0)
1830 name [0] = toupper (name [0]);
1831 }
1832 EMIT("#define VMPREFIX_VM_NAME JITTER_STRINGIFY(%s)\n", name);
1833 EMIT("#define VMPREFIX_LOWER_CASE_PREFIX \"%s\"\n", vm->lower_case_prefix);
1834 EMIT("#define VMPREFIX_UPPER_CASE_PREFIX \"%s\"\n", vm->upper_case_prefix);
1835 EMIT("#define VMPREFIX_DISPATCH_HUMAN_READABLE \\\n");
1836 EMIT(" JITTER_DISPATCH_NAME_STRING\n");
1837 EMIT("#define VMPREFIX_MAX_FAST_REGISTER_NO_PER_CLASS %i\n",
1838 (int) vm->max_fast_register_no_per_class);
1839 EMIT("#define VMPREFIX_MAX_NONRESIDUAL_LITERAL_NO %i\n",
1840 (int) vm->max_nonresidual_literal_no);
1841
1842 EMIT("\n");
1843 jitterc_fclose (f);
1844 }
1845
1846
1847
1848
1849 /* VM register classes.
1850 * ************************************************************************** */
1851
1852 /* Emit header code for register classes. */
1853 static void
jitterc_emit_register_classes_h(const struct jitterc_vm * vm)1854 jitterc_emit_register_classes_h (const struct jitterc_vm *vm)
1855 {
1856 FILE *f = jitterc_fopen_a_basename (vm, "vm.h");
1857
1858 EMIT("\n");
1859 EMIT("/* For each register class define the register type, a unique index, and the\n");
1860 EMIT(" number of fast registers. Indices are useful for computing slow register\n");
1861 EMIT(" offsets. For each register class declare a global register class\n");
1862 EMIT(" descriptor, convenient to use when generating unspecialized instructions\n");
1863 EMIT(" from the C API.*/\n");
1864 int i; char *comma __attribute__ ((unused));
1865 FOR_LIST(i, comma, vm->register_classes)
1866 {
1867 const struct jitterc_register_class *c
1868 = (gl_list_get_at (vm->register_classes, i));
1869 EMIT("typedef\n%s vmprefix_register_%c;\n", c->c_type, c->letter);
1870 EMIT("#define VMPREFIX_REGISTER_%c_CLASS_ID %i\n", c->letter, i);
1871 EMIT("#define VMPREFIX_REGISTER_%c_FAST_REGISTER_NO %i\n", c->letter,
1872 (int) c->fast_register_no);
1873 EMIT("extern const struct jitter_register_class\n");
1874 EMIT("vmprefix_register_class_%c;\n", c->letter);
1875 }
1876 EMIT("\n");
1877
1878 EMIT("/* How many register classes we have. */\n");
1879 EMIT("#define VMPREFIX_REGISTER_CLASS_NO %i\n",
1880 (int) gl_list_size (vm->register_classes));
1881 EMIT("\n");
1882
1883 EMIT("/* A union large enough to hold a register of any class, or a machine word. */\n");
1884 EMIT("union vmprefix_any_register\n");
1885 EMIT("{\n");
1886 EMIT(" /* In any case the union must be at least as large as a machine word. */\n");
1887 EMIT(" jitter_int jitter_unused_field;\n\n");
1888 FOR_LIST(i, comma, vm->register_classes)
1889 {
1890 const struct jitterc_register_class *c
1891 = (gl_list_get_at (vm->register_classes, i));
1892 EMIT(" vmprefix_register_%c %c /* A %c-class register */;\n",
1893 c->letter, c->letter, c->letter);
1894 }
1895 EMIT("};\n");
1896 EMIT("\n");
1897
1898 EMIT("/* An enumeration of all vmprefix register classes. */\n");
1899 EMIT("enum vmprefix_register_class_id\n");
1900 EMIT(" {\n");
1901 FOR_LIST(i, comma, vm->register_classes)
1902 {
1903 const struct jitterc_register_class *c
1904 = (gl_list_get_at (vm->register_classes, i));
1905 EMIT(" vmprefix_register_class_id_%c = VMPREFIX_REGISTER_%c_CLASS_ID,\n",
1906 c->letter, c->letter);
1907 }
1908 EMIT("\n");
1909 EMIT(" /* The number of register class ids, not valid as a class id itself. */\n");
1910 EMIT(" vmprefix_register_class_id_no = VMPREFIX_REGISTER_CLASS_NO\n");
1911 EMIT(" };\n");
1912 EMIT("\n");
1913
1914 EMIT("/* A macro expanding to a statement initialising a rank of slow\n");
1915 EMIT(" registers. The argument has type union vmprefix_any_register *\n");
1916 EMIT(" and points to the first register in a rank. */\n");
1917 EMIT("#define VMPREFIX_INITIALIZE_SLOW_REGISTER_RANK(rank) \\\n");
1918 EMIT(" do \\\n");
1919 EMIT(" { \\\n");
1920 EMIT(" union vmprefix_any_register *_jitter_rank __attribute__ ((unused)) \\\n");
1921 EMIT(" = (rank); \\\n");
1922 FOR_LIST(i, comma, vm->register_classes)
1923 {
1924 const struct jitterc_register_class *c
1925 = (gl_list_get_at (vm->register_classes, i));
1926 if (c->c_initial_value != NULL)
1927 EMIT(" _jitter_rank [%i].%c = (%s) (%s); \\\n",
1928 (int) i, c->letter, c->c_type, c->c_initial_value);
1929 else
1930 EMIT(" /* %c-class registers need no initialisation. */ \\\n",
1931 c->letter);
1932 }
1933 EMIT(" } \\\n");
1934 EMIT(" while (false)\n");
1935 EMIT("\n");
1936 EMIT("\n");
1937
1938 jitterc_fclose (f);
1939 }
1940
1941 /* Emit implementation code for register classes. */
1942 static void
jitterc_emit_register_classes(const struct jitterc_vm * vm)1943 jitterc_emit_register_classes (const struct jitterc_vm *vm)
1944 {
1945 FILE *f = jitterc_fopen_a_basename (vm, "vm1.c");
1946 EMIT("\n");
1947
1948 /* Emit definitions for global register class descriptors. */
1949 int i; char *comma;
1950 FOR_LIST(i, comma, vm->register_classes)
1951 {
1952 const struct jitterc_register_class *c
1953 = (gl_list_get_at (vm->register_classes, i));
1954 EMIT("/* The register class descriptor for %c registers. */\n", c->letter);
1955 EMIT("const struct jitter_register_class\n");
1956 EMIT("vmprefix_register_class_%c\n", c->letter);
1957 EMIT(" = {\n");
1958 EMIT(" vmprefix_register_class_id_%c,\n", c->letter);
1959 EMIT(" '%c',\n", c->letter);
1960 EMIT(" \"%s\",\n", c->lower_case_long_name);
1961 EMIT(" \"%s\",\n", c->upper_case_long_name);
1962 EMIT(" VMPREFIX_REGISTER_%c_FAST_REGISTER_NO,\n", c->letter);
1963 EMIT(" %i /* Use slow registers */\n", (int) c->use_slow_registers);
1964 EMIT(" };\n\n");
1965 }
1966 EMIT("\n");
1967
1968 /* Group register class descriptors into a constant pointer constant array. */
1969 EMIT("/* A pointer to every existing register class descriptor. */\n");
1970 EMIT("const struct jitter_register_class * const\n");
1971 EMIT("vmprefix_regiter_classes []\n");
1972 EMIT(" = {\n");
1973 FOR_LIST(i, comma, vm->register_classes)
1974 {
1975 const struct jitterc_register_class *c
1976 = (gl_list_get_at (vm->register_classes, i));
1977 EMIT(" & vmprefix_register_class_%c%s\n", c->letter, comma);
1978 }
1979 EMIT(" };\n");
1980 EMIT("\n");
1981
1982 /* Emit the definition of vmprefix_register_class_character_to_register_class
1983 , returning a pointer to one of the structures above. */
1984 EMIT("const struct jitter_register_class *\n");
1985 EMIT("vmprefix_register_class_character_to_register_class (char c)\n");
1986 EMIT("{\n");
1987 EMIT(" switch (c)\n");
1988 EMIT(" {\n");
1989 FOR_LIST(i, comma, vm->register_classes)
1990 {
1991 const struct jitterc_register_class *c
1992 = (gl_list_get_at (vm->register_classes, i));
1993 EMIT(" case '%c': return & vmprefix_register_class_%c;\n",
1994 c->letter, c->letter);
1995 }
1996 EMIT(" default: return NULL;\n");
1997 EMIT(" }\n");
1998 EMIT("}\n");
1999 EMIT("\n");
2000
2001 jitterc_fclose (f);
2002 }
2003
2004
2005
2006
2007 /* VM register access.
2008 * ************************************************************************** */
2009
2010 /* Emit macro definitions for accessing slow registers. These go into the
2011 VM header, since they are useful both in specialization, for computing
2012 offsets from the base, and in the executor. */
2013 static void
jitterc_emit_register_access_macros_h(const struct jitterc_vm * vm)2014 jitterc_emit_register_access_macros_h (const struct jitterc_vm *vm)
2015 {
2016 FILE *f = jitterc_fopen_a_basename (vm, "vm.h");
2017
2018 EMIT("/* How many residuals we can have at most. This, with some dispatching models,\n");
2019 EMIT(" is needed to compute a slow register offset from the base. */\n");
2020 EMIT("#define VMPREFIX_MAX_RESIDUAL_ARITY %i\n\n", (int)vm->max_residual_arity);
2021
2022 jitterc_fclose (f);
2023 }
2024
2025
2026
2027
2028 /* Executor generation.
2029 * ************************************************************************** */
2030
2031 /* Emit macro definitions for accessing registers as lvalues, available to user
2032 meta-instruction code (mostly for implied operands) and for the generated
2033 code as well (for defining instruction register operands). There is one
2034 zero-argument macro per fast register, plus another for slow register, having
2035 the register index as the argument.
2036
2037 The slow-register access macro yields an array access with an index known at
2038 compile time. */
2039 static void
jitterc_emit_executor_register_access_macros(FILE * f,const struct jitterc_vm * vm)2040 jitterc_emit_executor_register_access_macros (FILE *f,
2041 const struct jitterc_vm *vm)
2042 {
2043 EMIT("/* Expand to the i-th fast register as an lvalue. This is used internally,\n");
2044 EMIT(" always with a literal index . */\n");
2045 EMIT("#define JITTER_FAST_REGISTER(class, index) \\\n");
2046 EMIT(" (JITTER_CONCATENATE_FOUR(jitter_state_runtime.jitter_fast_register_, \\\n");
2047 EMIT(" class, _, index))\n");
2048 EMIT("\n");
2049 int i, j; char *comma __attribute__ ((unused));
2050 FOR_LIST(i, comma, vm->register_classes)
2051 {
2052 const struct jitterc_register_class *c
2053 = (gl_list_get_at (vm->register_classes, i));
2054 for (j = 0; j < c->fast_register_no; j ++)
2055 {
2056 EMIT("/* Expand to the %i-th fast %c-register as an lvalue. */\n",
2057 j, c->letter);
2058 EMIT("#define JITTER_FAST_REGISTER_%c_%i JITTER_FAST_REGISTER(%c, %i)\n\n",
2059 c->letter, j, c->letter, j);
2060 }
2061 }
2062 EMIT("/* Expand to a slow register lvalue, given an offset in bytes from the base. */\n");
2063 EMIT("#define JITTER_SLOW_REGISTER_FROM_OFFSET(c, offset) \\\n");
2064 EMIT(" (* ((JITTER_CONCATENATE_TWO(vmprefix_register_, c) * restrict) \\\n");
2065 EMIT(" (((char *) jitter_array_base) + offset)))\n");
2066 EMIT("\n");
2067 const int vmprefix_slow_register_with_access_macro_no = 32;
2068 EMIT("/* Expand to the i-th register, which must be a slow register, as an lvalue.\n");
2069 EMIT(" The given index must be a register index counting from 0 and including fast\n");
2070 EMIT(" regusters as well, if there are any. For example if an r class had 3 fast\n");
2071 EMIT(" registers then the first slow register would be %%r3, to be accessed as\n");
2072 EMIT(" JITTER_SLOW_REGISTER(r, 3). It would be invalid to access %%r0, %%r1 and\n");
2073 EMIT(" %%r2 which this macro, as %%r0, %%r1 and %%r2 would be fast. */\n");
2074 EMIT("#define JITTER_SLOW_REGISTER(c, i) \\\n");
2075 EMIT(" JITTER_SLOW_REGISTER_FROM_OFFSET(c, VMPREFIX_SLOW_REGISTER_OFFSET(c, i))\n");
2076 EMIT("\n");
2077 EMIT("/* It's not possible to have a single macro JITTER_REGISTER taking an index and\n");
2078 EMIT(" expanding to either a fast or a slow register lvalue, due to CPP conditional\n");
2079 EMIT(" limitations. This restriction is unfortunate, but we have to live with it\n");
2080 EMIT(" as long as we don't switch to a different preprocessor.\n");
2081 EMIT(" What we can have is a set of zero-argument macros each expanding to a register\n");
2082 EMIT(" lvalue, for *a limited number* of registers. Here we define access macros for\n");
2083 EMIT(" every fast register plus a reasonable number (currently %i) of slow registers,\n",
2084 vmprefix_slow_register_with_access_macro_no);
2085 EMIT(" per class. */\n");
2086 FOR_LIST(i, comma, vm->register_classes)
2087 {
2088 const struct jitterc_register_class *c
2089 = (gl_list_get_at (vm->register_classes, i));
2090 for (j = 0; j < c->fast_register_no; j ++)
2091 EMIT("#define JITTER_REGISTER_%c_%-3i JITTER_FAST_REGISTER(%c, %i)\n",
2092 c->letter, j, c->letter, j);
2093 for (;
2094 j < (c->fast_register_no
2095 + vmprefix_slow_register_with_access_macro_no);
2096 j ++)
2097 EMIT("#define JITTER_REGISTER_%c_%-3i JITTER_SLOW_REGISTER(%c, %i)\n",
2098 c->letter, j, c->letter, j);
2099 }
2100 EMIT("\n");
2101 EMIT("\n");
2102 }
2103
2104 static void
jitterc_emit_executor_reserve_registers(FILE * f,const struct jitterc_vm * vm)2105 jitterc_emit_executor_reserve_registers (FILE *f,
2106 const struct jitterc_vm *vm)
2107 {
2108 /* We don't need to reserve global registers even with no-threading dispatch
2109 if this machine needs no residaul arguments at all. */
2110 if (vm->max_residual_arity == 0)
2111 return;
2112
2113 EMIT("#ifdef JITTER_DISPATCH_NO_THREADING\n\n");
2114
2115 EMIT("/* Reserve the scratch register, if any. */\n");
2116 EMIT("#ifdef JITTER_SCRATCH_REGISTER\n");
2117 EMIT(" register union jitter_word\n");
2118 EMIT(" jitter_residual_argument_scratch_register_variable asm (JITTER_STRINGIFY(JITTER_SCRATCH_REGISTER));\n");
2119 EMIT("#endif // #ifdef JITTER_SCRATCH_REGISTER\n\n");
2120
2121 EMIT("/* Reserve The Array base register. */\n");
2122 EMIT("#ifndef JITTER_BASE_REGISTER\n");
2123 EMIT("# error \"the machine does not define JITTER_BASE_REGISTER\"\n");
2124 EMIT("#else\n");
2125 EMIT("register char * restrict\n");
2126 EMIT("vmprefix_array_base_register_variable asm (JITTER_STRINGIFY(JITTER_BASE_REGISTER));\n");
2127 EMIT("#endif // #ifndef JITTER_BASE_REGISTER\n\n");
2128
2129 EMIT("/* Reserve registers for our %i residual arguments. If this particular VM doesn't\n",
2130 (int) vm->max_residual_arity);
2131 EMIT(" need all of those supported by the assembly machine then reserve only the first\n");
2132 EMIT(" ones. If, on the other hand, we need more residual arguments than we have\n");
2133 EMIT(" available registers, use CPP macros to map the remaining residual arguments\n");
2134 EMIT(" to memory locations relative to the base, with constant offsets. */\n\n");
2135
2136 int i;
2137 for (i = 0; i < vm->max_residual_arity; i ++)
2138 {
2139 EMIT("/* Define a macro for the %i-th residual as a register, or as a residual\n", i);
2140 EMIT(" memory slot. Also define a macro expanding to inline asm code with\n");
2141 EMIT(" output constraints on the appropriate register or memory, to let GCC\n");
2142 EMIT(" know that its value has been changed by unknown code. */\n");
2143 EMIT("#if (%i < JITTER_RESIDUAL_REGISTER_NO)\n", i);
2144 EMIT(" register union jitter_word\n");
2145 EMIT(" jitter_residual_argument_%i_register_variable asm (JITTER_STRINGIFY(JITTER_RESIDUAL_REGISTER_%i));\n", i, i);
2146 EMIT("# define JITTER_RESIDUAL_ARGUMENT_%i \\\n", i);
2147 EMIT(" jitter_residual_argument_%i_register_variable\n", i);
2148 EMIT("# define JITTER_MARK_RESIDUAL_%i_AS_SET_BY_ASSEMBLY \\\n", i);
2149 EMIT(" JITTER_MARK_REGISTER_AS_SET_BY_ASSEMBLY(jitter_residual_argument_%i_register_variable)\n", i);
2150 EMIT("#else\n");
2151 EMIT("# define JITTER_RESIDUAL_ARGUMENT_%i \\\n", i);
2152 EMIT(" (* (union jitter_word *) \\\n");
2153 EMIT(" (jitter_array_base + VMPREFIX_RESIDUAL_OFFSET(%i)))\n", i);
2154 EMIT("# define JITTER_MARK_RESIDUAL_%i_AS_SET_BY_ASSEMBLY \\\n", i);
2155 EMIT(" JITTER_MARK_MEMORY_AS_SET_BY_ASSEMBLY(JITTER_RESIDUAL_ARGUMENT_%i)\n", i);
2156 EMIT("#endif // #if (%i < JITTER_RESIDUAL_REGISTER_NO)\n\n", i);
2157 }
2158
2159 EMIT("/* The global register values we reserve in this compilation unit are\n");
2160 EMIT(" callee-save: the called function is supposed to save them before\n");
2161 EMIT(" setting them, and restore them to their previous value before\n");
2162 EMIT(" returning to the caller. Of course this is not done automatically\n");
2163 EMIT(" in this compilation unit, so we have to do it by hand. Notice that\n");
2164 EMIT(" every variable allocated to a register by GCC will not use the\n");
2165 EMIT(" registers we reserved, so we can be sure that, if we save our\n");
2166 EMIT(" global register variables before setting them for the first time,\n");
2167 EMIT(" their values will be the ones we want to retain. */\n");
2168 EMIT("\n");
2169 EMIT("/* The buffer where I keep the original register values needs to hold\n");
2170 EMIT(" every residual register, plus possibly the scratch register and the\n");
2171 EMIT(" residual base; those two registers are not always used, but allocating\n");
2172 EMIT(" just two words more costs essentially nothing and lets me simplify\n");
2173 EMIT(" the code a little. The two words are not written or read unless\n");
2174 EMIT(" needed. */\n");
2175 EMIT("#define VMPREFIX_REGISTER_BUFFER_ELEMENT_NO (JITTER_RESIDUAL_REGISTER_NO + 2)\n");
2176 EMIT("__attribute__ ((noinline, cold))\n");
2177 EMIT("\n");
2178
2179 EMIT("static void\n");
2180 EMIT("vmprefix_save_registers (union jitter_word *buffer)\n");
2181 EMIT("{\n");
2182 EMIT(" buffer [0].pointer = (union jitter_word*) vmprefix_array_base_register_variable;\n");
2183 EMIT("#ifdef JITTER_SCRATCH_REGISTER\n");
2184 EMIT(" buffer [1] = jitter_residual_argument_scratch_register_variable;\n");
2185 EMIT("#endif // #ifdef JITTER_SCRATCH_REGISTER\n");
2186 for (i = 0; i < vm->max_residual_arity; i ++)
2187 {
2188 EMIT("#if (%i < JITTER_RESIDUAL_REGISTER_NO)\n", i);
2189 EMIT(" buffer [%i + 2] = JITTER_RESIDUAL_ARGUMENT_%i;\n", i, i);
2190 EMIT("#endif // #if (%i < JITTER_RESIDUAL_REGISTER_NO)\n", i);
2191 }
2192 EMIT("}\n");
2193 EMIT("\n");
2194
2195 EMIT("__attribute__ ((noinline, cold))\n");
2196 EMIT("static void\n");
2197 EMIT("vmprefix_restore_registers (const union jitter_word *buffer)\n");
2198 EMIT("{\n");
2199 EMIT(" vmprefix_array_base_register_variable = (char *) buffer [0].pointer;\n");
2200 EMIT("#ifdef JITTER_SCRATCH_REGISTER\n");
2201 EMIT(" jitter_residual_argument_scratch_register_variable = buffer [1];\n");
2202 EMIT("#endif // #ifdef JITTER_SCRATCH_REGISTER\n");
2203 for (i = 0; i < vm->max_residual_arity; i ++)
2204 {
2205 EMIT("#if (%i < JITTER_RESIDUAL_REGISTER_NO)\n", i);
2206 EMIT(" JITTER_RESIDUAL_ARGUMENT_%i = buffer [%i + 2];\n", i, i);
2207 EMIT("#endif // #if (%i < JITTER_RESIDUAL_REGISTER_NO)\n", i);
2208 }
2209 EMIT("}\n");
2210 EMIT("\n");
2211
2212 EMIT("#endif // #ifdef JITTER_DISPATCH_NO_THREADING\n\n\n");
2213 }
2214
2215 static void
jitterc_emit_executor_global_wrappers(FILE * f,const struct jitterc_vm * vm)2216 jitterc_emit_executor_global_wrappers
2217 (FILE *f, const struct jitterc_vm *vm)
2218 {
2219 EMIT("/* Selectively suppress suprious -Wmaybe-uninitialized .\n");
2220 EMIT(" The indirect jump hack I use in profiling mode in order to\n");
2221 EMIT(" have a large gap inside a function introduced by assembler without\n");
2222 EMIT(" being restricted by jump offset limits (intentionally) tricks GCC\n");
2223 EMIT(" into believing that the indirect jump may reach any instruction label;\n");
2224 EMIT(" GCC would then warn that some locals might be used uninitialized,\n");
2225 EMIT(" by skipping over their initialization. This however is not possible,\n");
2226 EMIT(" and I want to selectively silence the warning for the variables in\n");
2227 EMIT(" question. */\n");
2228 EMIT("#pragma GCC diagnostic push\n");
2229 EMIT("#pragma GCC diagnostic ignored \"-Wmaybe-uninitialized\"\n");
2230 EMIT("\n");
2231 EMIT(" /* Wrap functions and globals used within VM instructions, if needed.\n");
2232 EMIT(" This is a trick to keep instructions readable while avoiding PC-relative\n");
2233 EMIT(" addressing, which would mess up replicated code. */\n");
2234 EMIT("#ifdef JITTER_REPLICATE\n\n");
2235
2236 /* When using replication we have to wrap C functions called from VM
2237 instructions. */
2238 EMIT(" /* Protect the C globals used in VM instructions so that they are always\n");
2239 EMIT(" referred thru a pointer (from a register or the stack) set in the\n");
2240 EMIT(" non-replicated part. This is necessary on architectures where I can't\n");
2241 EMIT(" force global references to pass thru a GOT.\n");
2242 EMIT(" [FIXME: possibly don't do this on architectures that don't need it.] */\n\n");
2243 int i; char *comma __attribute__ ((unused));
2244 FOR_LIST(i, comma, vm->wrapped_globals)
2245 {
2246 const char *name
2247 = ((const char*) gl_list_get_at (vm->wrapped_globals, i));
2248 EMIT(" typeof (%s) * volatile _my_volatile_pointer_to_%s = & %s;\n",
2249 name, name, name);
2250 EMIT(" typeof (%s) * const restrict _my_pointer_to_%s __attribute__ ((unused))\n",
2251 name, name);
2252 EMIT(" = _my_volatile_pointer_to_%s;\n", name);
2253 EMIT("# undef %s\n", name);
2254 EMIT("# define %s (* _my_pointer_to_%s)\n\n", name, name);
2255 }
2256
2257 EMIT(" /* Similarly, wrap the C functions used in VM instructions, so that they are\n");
2258 EMIT(" always called thru a function pointer. This is necessary on architectures\n");
2259 EMIT(" where call instructions represent the callee as a PC-relative address.\n");
2260 EMIT(" Unfortunately C has a special quirky syntax for function pointers, so I\n");
2261 EMIT(" can't just use the code above. [FIXME: don't do this on architectures\n");
2262 EMIT(" that don't need it.] */\n");
2263 FOR_LIST(i, comma, vm->wrapped_functions)
2264 {
2265 const char *name
2266 = ((const char*) gl_list_get_at (vm->wrapped_functions, i));
2267 EMIT(" typeof (%s) * volatile _my_volatile_pointer_to_%s = & %s;\n",
2268 name, name, name);
2269 EMIT(" typeof (%s) * const _my_%s __attribute__ ((unused))\n",
2270 name, name);
2271 EMIT(" = * _my_volatile_pointer_to_%s;\n", name);
2272 EMIT("# undef %s\n", name);
2273 EMIT("# define %s _my_%s\n\n", name, name);
2274 }
2275 EMIT("/* See the comment above about spurious -Wmaybe-uninitialized warnings. */\n");
2276 EMIT("#pragma GCC diagnostic pop\n");
2277 EMIT("#endif // #ifdef JITTER_REPLICATE\n\n");
2278 EMIT("\n");
2279 }
2280
2281 /* Emit macro definitions (and possibly inline asm statements) for the given
2282 specialized argument, occurring in the given 0-based position among all the
2283 arguments and in the given (still 0-based) position among the residual
2284 arguments of a specialized instruction. Non-fast-label residuals and
2285 fast-label "residuals" have independent counters: for example the five sargs
2286 of a specialized instruction foo_r0_nR_fR_nR_fR would have residual indices:
2287 - 0 (non-residual)
2288 - 0 (first residual non-fast-label)
2289 - 0 (first "residual" fast label)
2290 - 1 (second residual non-fast-label)
2291 - 1 (second "residual" fast label). */
2292 static void
jitterc_emit_executor_sarg_definition(FILE * f,int index,int residual_index,const struct jitterc_specialized_argument * sarg,bool have_fast_labels)2293 jitterc_emit_executor_sarg_definition
2294 (FILE *f, int index, int residual_index,
2295 const struct jitterc_specialized_argument* sarg,
2296 bool have_fast_labels)
2297 {
2298 switch (sarg->kind)
2299 {
2300 case jitterc_instruction_argument_kind_register:
2301 EMIT(" /* The %ith argument is a %s\n register. */\n",
2302 index,
2303 sarg->residual ? "slow (therefore residual, passed as an offset)"
2304 : "fast");
2305 if (sarg->residual)
2306 {
2307 EMIT(" /* Define a macro expanding to the slow register offset. */\n");
2308 EMIT("#if defined(JITTER_DISPATCH_NO_THREADING)\n");
2309 EMIT("# define JITTER_SLOW_REGISTER_OFFSET%i (JITTER_RESIDUAL_ARGUMENT_%i.fixnum)\n", index, residual_index);
2310 EMIT("#elif defined (JITTER_DISPATCH_MINIMAL_THREADING)\n");
2311 EMIT("# define JITTER_SLOW_REGISTER_OFFSET%i ((((union jitter_word*)jitter_ip)[%i]).fixnum)\n", index, residual_index);
2312 EMIT("#else\n");
2313 EMIT("# define JITTER_SLOW_REGISTER_OFFSET%i ((((union jitter_word*)jitter_ip)[%i]).fixnum)\n", index, residual_index + 1);
2314 EMIT("#endif // #if defined(JITTER_DISPATCH_NO_THREADING)\n");
2315
2316 EMIT(" /* Define a macro expanding to an l-value for the VM register content. */\n");
2317 EMIT("# define JITTER_ARG%i JITTER_SLOW_REGISTER_FROM_OFFSET(%c, JITTER_SLOW_REGISTER_OFFSET%i)\n",
2318 index, sarg->unspecialized->register_class_character, index);
2319 }
2320 else
2321 EMIT("# define JITTER_ARG%i JITTER_FAST_REGISTER(%c, %i)\n",
2322 index, sarg->unspecialized->register_class_character,
2323 (int) sarg->nonresidual_register->index);
2324 break;
2325
2326 case jitterc_instruction_argument_kind_literal:
2327 EMIT(" /* The %ith argument is a %sresidual literal. */\n",
2328 index, sarg->residual ? "" : "non");
2329 if (sarg->residual)
2330 goto residual_label_or_literal;
2331 else
2332 /* FIXME: this will need generalization with more literal kinds. */
2333 EMIT("# define JITTER_ARG%i ((const union jitter_word){.fixnum = %liL})\n",
2334 index, (long)sarg->nonresidual_literal->value.fixnum);
2335 break;
2336
2337 case jitterc_instruction_argument_kind_label:
2338 EMIT(" /* The %ith argument is a %sresidual label. */\n",
2339 index, sarg->residual ? "" : "non");
2340 if (! sarg->residual)
2341 jitter_fatal ("nonresidual label");
2342 residual_label_or_literal:
2343 EMIT("#if defined(JITTER_DISPATCH_NO_THREADING)\n");
2344 EMIT("# define JITTER_ARG%i JITTER_RESIDUAL_ARGUMENT_%i\n", index, residual_index);
2345 EMIT(" JITTER_MARK_RESIDUAL_%i_AS_SET_BY_ASSEMBLY;\n", residual_index);
2346 EMIT("#elif defined (JITTER_REPLICATE)\n");
2347 EMIT("# define JITTER_ARG%i (((union jitter_word*)jitter_ip)[%i])\n", index, residual_index);
2348 EMIT("#else\n");
2349 EMIT("# define JITTER_ARG%i (((union jitter_word*)jitter_ip)[%i])\n", index, residual_index + 1);
2350 EMIT("#endif // #if defined(JITTER_DISPATCH_NO_THREADING)\n");
2351 break;
2352
2353 case jitterc_instruction_argument_kind_fast_label:
2354 if (! sarg->residual)
2355 jitter_fatal ("nonresidual fast label");
2356
2357 if (have_fast_labels)
2358 {
2359 EMIT(" /* The %ith argument is a \"residual\" fast label. Define its\n", index);
2360 EMIT(" _ARGF macro as the residual *index* (counting only fast labels, 0-based),\n");
2361 EMIT(" so that at replication time we know what instruction address to patch in. */\n");
2362 EMIT("# define JITTER_ARGF%i %i\n", index, residual_index);
2363 EMIT(" /* JITTER_ARG%i is intentionally not defined for a fast label. */\n\n", index);
2364 }
2365 else
2366 goto residual_label_or_literal;
2367
2368 break;
2369
2370 default:
2371 jitter_fatal ("jitterc_emit_executor_sarg_definition: invalid argument kind %i", (int) sarg->kind);
2372 }
2373 EMIT("# define JITTER_ARGN%i (JITTER_ARG%i.fixnum)\n", index, index);
2374 EMIT("# define JITTER_ARGU%i (JITTER_ARG%i.ufixnum)\n", index, index);
2375 EMIT("# define JITTER_ARGP%i (JITTER_ARG%i.pointer)\n", index, index);
2376 if ((have_fast_labels && sarg->replacement) || ! have_fast_labels)
2377 {
2378 EMIT("# define JITTER_ARGF%i JITTER_ARGP%i\n", index, index);
2379 }
2380 /*
2381 else if (! have_fast_labels)
2382 EMIT("# define JITTER_ARGF%i JITTER_ARGP%i\n", index, index);
2383 */
2384 EMIT("\n");
2385 }
2386
2387 /* An internal function factoring code run twice in
2388 jitterc_emit_sarg_definitions . This emits definitions for user-visible
2389 argument-access macros, assuming fast labels are enabled or not, as per the
2390 given argument. */
2391 static void
jitterc_emit_sarg_definitions_internal(FILE * f,const struct jitterc_specialized_instruction * sins,bool have_fast_labels)2392 jitterc_emit_sarg_definitions_internal
2393 (FILE *f, const struct jitterc_specialized_instruction *sins,
2394 bool have_fast_labels)
2395 {
2396 size_t residual_arity = 0;
2397 size_t residual_label_index = 0;
2398 int j; char *comma __attribute__ ((unused));
2399 FOR_LIST(j, comma, sins->specialized_arguments)
2400 {
2401 const struct jitterc_specialized_argument* sarg
2402 = ((const struct jitterc_specialized_argument*)
2403 gl_list_get_at (sins->specialized_arguments, j));
2404 if ( have_fast_labels
2405 && sarg->kind == jitterc_instruction_argument_kind_fast_label)
2406 {
2407 jitterc_emit_executor_sarg_definition
2408 (f, j, residual_label_index, sarg, have_fast_labels);
2409 residual_label_index ++;
2410 }
2411 else
2412 jitterc_emit_executor_sarg_definition
2413 (f, j, residual_arity, sarg, have_fast_labels);
2414
2415 if ( sarg->residual
2416 && ( sarg->kind != jitterc_instruction_argument_kind_fast_label
2417 || ! have_fast_labels))
2418 residual_arity ++;
2419 }
2420 }
2421
2422 /* Emit definitions for the user-visible argument-access macros of the given
2423 instruction. The generated code is conditionalized on fast label support, if
2424 needed. */
2425 static void
jitterc_emit_sarg_definitions(FILE * f,const struct jitterc_specialized_instruction * sins)2426 jitterc_emit_sarg_definitions
2427 (FILE *f, const struct jitterc_specialized_instruction *sins)
2428 {
2429 /* Emit a conditionalized argument definition for when fast labels are used, ending
2430 in an #else case for the non-fast-label case. */
2431 if (sins->instruction->has_fast_labels)
2432 {
2433 EMIT(" /* Define argument-access macros for %s . */\n", sins->name);
2434 EMIT("#ifdef JITTER_HAVE_PATCH_IN\n");
2435 EMIT(" /* Define argument-access macros assuming that fast branches are enabled. */\n");
2436 jitterc_emit_sarg_definitions_internal (f, sins, true);
2437 EMIT("#else\n");
2438 EMIT(" /* Define argument-access macros assuming that fast branches are disabled. */\n");
2439 }
2440
2441 /* Emit the non-fast-label case, which is always there. */
2442 jitterc_emit_sarg_definitions_internal (f, sins, false);
2443
2444 /* Close the conditional we opened if there were fast labels. */
2445 if (sins->instruction->has_fast_labels)
2446 EMIT("# endif // #ifdef JITTER_HAVE_PATCH_IN\n");
2447 }
2448
2449 static void
jitterc_emit_specialized_instruction_residual_arity_definition(FILE * f,const struct jitterc_specialized_instruction * sins)2450 jitterc_emit_specialized_instruction_residual_arity_definition
2451 (FILE *f, const struct jitterc_specialized_instruction *sins)
2452 {
2453 /* How many residual arguments we have in total, including fast labels if
2454 any. */
2455 size_t residual_argument_no = 0;
2456
2457 /* The number of non-fast-label residual arguments, including both non-fast
2458 labels and non-label residuals. */
2459 size_t non_fast_label_residual_argument_no = 0;
2460
2461 /* Count non-fast-labels and all residuals. */
2462 int j; char *comma __attribute__ ((unused));
2463 FOR_LIST(j, comma, sins->specialized_arguments)
2464 {
2465 const struct jitterc_specialized_argument* sarg
2466 = ((const struct jitterc_specialized_argument*)
2467 gl_list_get_at (sins->specialized_arguments, j));
2468 if (sarg->residual)
2469 {
2470 residual_argument_no ++;
2471 if (sarg->kind != jitterc_instruction_argument_kind_fast_label)
2472 non_fast_label_residual_argument_no ++;
2473 }
2474 }
2475
2476 /* Emit the residual arity definition, making it conditional only if needed. */
2477 if (non_fast_label_residual_argument_no == residual_argument_no)
2478 {
2479 EMIT(" /* The residual arity for this instruction does not depend on fast labels. */\n");
2480 EMIT(" #define JITTER_SPECIALIZED_INSTRUCTION_RESIDUAL_ARITY %i\n",
2481 (int) non_fast_label_residual_argument_no);
2482 }
2483 else
2484 {
2485 EMIT(" /* The residual arity varies depending on whether we have fast labels. */\n");
2486 EMIT("#ifdef JITTER_HAVE_PATCH_IN\n");
2487 EMIT(" #define JITTER_SPECIALIZED_INSTRUCTION_RESIDUAL_ARITY %i\n",
2488 (int) non_fast_label_residual_argument_no);
2489 EMIT("#else\n");
2490 EMIT(" #define JITTER_SPECIALIZED_INSTRUCTION_RESIDUAL_ARITY %i\n",
2491 (int) residual_argument_no);
2492 EMIT("#endif // #ifdef JITTER_HAVE_PATCH_IN\n");
2493 }
2494 }
2495
2496 /* Names for fast-branching macros, without the prefix "JITTER_BRANCH". */
2497 static const char *
2498 jitter_fast_branch_macros []
2499 = {
2500 "",
2501 "_IF_ZERO",
2502 "_IF_NONZERO",
2503 "_IF_POSITIVE",
2504 "_IF_NONPOSITIVE",
2505 "_IF_NEGATIVE",
2506 "_IF_NONNEGATIVE",
2507 "_IF_EQUAL",
2508 "_IF_NOTEQUAL",
2509 "_IF_LESS_SIGNED",
2510 "_IF_LESS_UNSIGNED",
2511 "_IF_NOTLESS_SIGNED",
2512 "_IF_NOTLESS_UNSIGNED",
2513 "_IF_GREATER_SIGNED",
2514 "_IF_GREATER_UNSIGNED",
2515 "_IF_NOTGREATER_SIGNED",
2516 "_IF_NOTGREATER_UNSIGNED",
2517 "_IF_AND",
2518 "_IF_NOTAND",
2519 "_IF_PLUS_OVERFLOWS",
2520 "_IF_MINUS_OVERFLOWS",
2521 "_IF_TIMES_OVERFLOWS",
2522 "_IF_DIVIDED_OVERFLOWS",
2523 "_IF_REMAINDER_OVERFLOWS",
2524 "_IF_NEGATE_OVERFLOWS",
2525 /*
2526 // FIXME: I *think* I only use these internally.
2527 "_IF_NEVER_UNARY",
2528 "_IF_ALWAYS_UNARY",
2529 */
2530 /* Here the underscore is intentional: even the name with (one) initial
2531 underscore is defined conditionally, only in caller instructions. */
2532 "_AND_LINK_INTERNAL"
2533 };
2534
2535 /* How many strings jitter_fast_branch_macros has. */
2536 static const size_t
2537 jitter_fast_branch_macro_no
2538 = sizeof (jitter_fast_branch_macros) / sizeof (jitter_fast_branch_macros [0]);
2539
2540 /* Same role as jitter_fast_branch_macros above for operations fast-branching on
2541 overflow. Only the operation name is given here. */
2542 static const char *
2543 jitter_fast_branching_operation_macros []
2544 = {
2545 "PLUS",
2546 "MINUS",
2547 "TIMES",
2548 "DIVIDED",
2549 "REMAINDER",
2550 "NEGATE"
2551 };
2552 /* How many strings jitter_fast_branching_operation_macros has. */
2553 static const size_t
2554 jitter_fast_branching_operation_macro_no
2555 = sizeof (jitter_fast_branching_operation_macros)
2556 / sizeof (jitter_fast_branching_operation_macros [0]);
2557
2558 /* Emit macro definitions for fast branching. These are defined in a different
2559 way for replacement and non-replacement specialized instructions. */
2560 static void
jitterc_emit_executor_fast_branch_definitions(FILE * f,const struct jitterc_vm * vm,const struct jitterc_specialized_instruction * sins)2561 jitterc_emit_executor_fast_branch_definitions
2562 (FILE *f, const struct jitterc_vm *vm,
2563 const struct jitterc_specialized_instruction* sins)
2564 {
2565 bool is_replacement = (sins->is_replacement_of != NULL);
2566
2567 if (is_replacement)
2568 EMIT(" /* This specialized instruction is a replacement. */\n");
2569 else
2570 EMIT(" /* This specialized instruction is not a replacement. */\n");
2571 int i;
2572 for (i = 0; i < jitter_fast_branch_macro_no; i ++)
2573 {
2574 const char *macro_name = jitter_fast_branch_macros [i];
2575 EMIT("# undef JITTER_BRANCH_FAST%s\n", macro_name);
2576 if (is_replacement)
2577 EMIT("# define JITTER_BRANCH_FAST%s JITTER_BRANCH%s\n", macro_name, macro_name);
2578 else
2579 EMIT("# define JITTER_BRANCH_FAST%s _JITTER_BRANCH_FAST%s\n", macro_name, macro_name);
2580 }
2581 for (i = 0; i < jitter_fast_branching_operation_macro_no; i ++)
2582 {
2583 const char *macro_name = jitter_fast_branching_operation_macros [i];
2584 EMIT("# undef JITTER_%s_BRANCH_FAST_IF_OVERFLOW\n", macro_name);
2585 if (is_replacement)
2586 EMIT("# define JITTER_%s_BRANCH_FAST_IF_OVERFLOW JITTER_%s_BRANCH_IF_OVERFLOW\n", macro_name, macro_name);
2587 else
2588 EMIT("# define JITTER_%s_BRANCH_FAST_IF_OVERFLOW _JITTER_%s_BRANCH_FAST_IF_OVERFLOW\n", macro_name, macro_name);
2589 }
2590 }
2591
2592 static void
jitterc_emit_executor_ordinary_specialized_instructions(FILE * f,const struct jitterc_vm * vm)2593 jitterc_emit_executor_ordinary_specialized_instructions
2594 (FILE *f, const struct jitterc_vm *vm)
2595 {
2596 int i; char *comma __attribute__ ((unused));
2597
2598 /* Generate code for each ordinary specialized instruction. */
2599 EMIT(" /* Ordinary specialized instructions. */\n");
2600 FOR_LIST(i, comma, vm->specialized_instructions)
2601 {
2602 const struct jitterc_specialized_instruction* sins
2603 = ((const struct jitterc_specialized_instruction*)
2604 gl_list_get_at (vm->specialized_instructions, i));
2605 /* Ignore special specialized instructions: we have already dealt with
2606 them. */
2607 if (sins->instruction == NULL)
2608 continue;
2609
2610 const struct jitterc_instruction* uins = sins->instruction;
2611 bool is_relocatable
2612 = (sins->relocatability == jitterc_relocatability_relocatable);
2613 bool is_caller = (uins->callerness == jitterc_callerness_caller);
2614 bool is_callee = (uins->calleeness == jitterc_calleeness_callee);
2615
2616 EMIT(" JITTER_INSTRUCTION_PROLOG_(%s, %s, %s)\n",
2617 sins->name, sins->mangled_name,
2618 (sins->hotness == jitterc_hotness_hot)
2619 ? "hot"
2620 : "cold");
2621 EMIT(" {\n");
2622
2623 /* Emit definitions for fast-branch macros. The definitions will be
2624 different for replacement and non-replacement instructions. */
2625 jitterc_emit_executor_fast_branch_definitions (f, vm, sins);
2626
2627 if (! is_relocatable)
2628 {
2629 EMIT(" /* This specialized instruction is non-relocatable.\n");
2630 EMIT(" Its %i-th argument, a literal, is the return address where to jump\n",
2631 (int) (gl_list_size (sins->specialized_arguments) - 1));
2632 EMIT(" at the end, back to relocated code. */\n\n");
2633 }
2634
2635 if (is_caller)
2636 {
2637 EMIT(" /* This specialized instruction is a caller.\n");
2638 EMIT(" Its %i-th argument, a literal, is the return address where to jump\n",
2639 (int) (gl_list_size (sins->specialized_arguments) - 1));
2640 EMIT(" back after the procedure returns. Branch-and-link\n");
2641 EMIT(" functionality is enabled for this instruction. */\n");
2642 EMIT("# define JITTER_BRANCH_AND_LINK JITTER_BRANCH_AND_LINK_INTERNAL\n");
2643 EMIT("# define JITTER_BRANCH_FAST_AND_LINK JITTER_BRANCH_FAST_AND_LINK_INTERNAL\n\n");
2644 }
2645
2646 /* Define the specialized instruction opcode and name as macros, to be
2647 used in the body and, in case of fast labels, in the arguments. */
2648 EMIT("# define JITTER_SPECIALIZED_INSTRUCTION_OPCODE %i\n", i);
2649 EMIT("# define JITTER_SPECIALIZED_INSTRUCTION_NAME %s\n\n",
2650 sins->name);
2651 EMIT("# define JITTER_SPECIALIZED_INSTRUCTION_MANGLED_NAME %s\n\n",
2652 sins->mangled_name);
2653
2654 /* Emit a macro definition for the specialized instruction residual arity. */
2655 jitterc_emit_specialized_instruction_residual_arity_definition (f, sins);
2656 EMIT("\n");
2657
2658 /* Emit macro definitions for specialized arguments, to be used in the body. */
2659 jitterc_emit_sarg_definitions (f, sins);
2660 EMIT("\n");
2661
2662 if (is_callee)
2663 {
2664 EMIT(" /* This specialized instruction is a callee. Set the link\n");
2665 EMIT(" pointer if needed... */\n");
2666 EMIT(" union jitter_word _jitter_the_link;\n");
2667 EMIT(" _JITTER_PROCEDURE_PROLOG (_jitter_the_link);\n");
2668 EMIT(" /* ...And make it accessible to this instruction, read-only,\n");
2669 EMIT(" through a macro. */\n");
2670 EMIT(" #define JITTER_LINK \\\n");
2671 EMIT(" ((const void *) \\\n");
2672 EMIT(" (_jitter_the_link.pointer))\n");
2673 EMIT("\n");
2674 }
2675
2676 /* If this is a non-relocatable instruction and replication is enabled,
2677 the actual code to replicate is trivial: just a jump; then comes the
2678 epilog. After the epilog we can put the label where relocated code
2679 jumps to, which is where control flows to in the other cases. The
2680 actual user-specified code for the VM instruction comes after the
2681 label. */
2682 if (! is_relocatable)
2683 {
2684 EMIT("#ifdef JITTER_REPLICATE\n");
2685 EMIT(" /* Pretend to modify the non-relocatable code pointer, to force GCC to keep\n");
2686 EMIT(" it on the stack rather than in read-only memory. I had to do this to prevent\n");
2687 EMIT(" a GCC 8 snapshot on SH from being too clever. */\n");
2688 EMIT(" //JITTER_MARK_MEMORY_AS_SET_BY_ASSEMBLY(JITTER_SPECIALIZED_INSTRUCTION_NON_RELOCATABLE_CODE_VARIABLE);\n");
2689 EMIT(" /* FIXME: no, it's not enough. GCC 8 on SH keeps the stack pointer *offset*\n");
2690 EMIT(" in memory, as a 16-bit constant; and since it reads it with a PC-relative\n");
2691 EMIT(" load the relocated part crashes.\n");
2692 EMIT(" mov.w .L1667,r0\n");
2693 EMIT(" mov.l @(r0,r15),r1\n");
2694 EMIT(" jmp @r1\n");
2695 EMIT(" r15 is the stack pointer. The constant at .L1667 is\n");
2696 EMIT(" .L1667:\n");
2697 EMIT(" .short 232\n");
2698 EMIT(" and this explains everything: 232 doesn't fit in a byte sign-extended, so it\n");
2699 EMIT(" can't work as an immediate. Shall I keep these code pointers as a single array?\n");
2700 EMIT(" I don't know. I'll switch to GNU C nested functions for non-relocatable code,\n");
2701 EMIT(" but the problem will be the same. */\n");
2702 EMIT(" /* Jump to non-relocatable code. */\n");
2703 EMIT(" JITTER_COMPUTED_GOTO(JITTER_SPECIALIZED_INSTRUCTION_NON_RELOCATABLE_CODE_VARIABLE);\n");
2704 EMIT("\n");
2705 EMIT(" /* Here the residual arity is given as zero: it's too late to\n");
2706 EMIT(" skip residuals, since we've already jumped and this code is\n");
2707 EMIT(" unreachable. The instruction pointer, if any, is advanced\n");
2708 EMIT(" in the non-relocatable code. */\n");
2709 EMIT(" JITTER_INSTRUCTION_EPILOG_(%s, %s, 0)\n", sins->name, sins->mangled_name);
2710 EMIT("\n");
2711 EMIT(" /* Relocated code will jump to this label in non-relocated code. */\n");
2712 EMIT(" JITTER_SPECIALIZED_INSTRUCTION_NON_RELOCATABLE_CODE_LABEL:\n");
2713 EMIT(" JITTER_COMMENT_IN_ASM_(\"%s non-relocatable code\");\n", sins->name);
2714 EMIT("#endif // #ifdef JITTER_REPLICATE\n");
2715 }
2716
2717 if (is_caller)
2718 {
2719 EMIT("#if defined(JITTER_DISPATCH_NO_THREADING) \\\n");
2720 EMIT(" && ! defined(JITTER_MACHINE_SUPPORTS_PROCEDURE)\n");
2721 EMIT(" /* We use the implicit atgument at the end of the calling.\n");
2722 EMIT(" instruction to discover the procedure return address. */\n");
2723 EMIT(" const void * _jitter_return_pointer = JITTER_ARGP%i;\n",
2724 (int) (gl_list_size (sins->specialized_arguments) - 1));
2725 EMIT(" /* And make it accessible to the user (who will usually call \n");
2726 EMIT(" JITTER_BRANCH_AND_LINK) thru a nice macro. */\n");
2727 EMIT("# define JITTER_RETURN_ADDRESS _jitter_return_pointer\n");
2728 EMIT("#endif\n\n");
2729 }
2730
2731 /* Emit profiling instrumentation code for the instruction. */
2732 EMIT("#if defined (JITTER_PROFILE_SAMPLE)\n");
2733 EMIT(" JITTER_PROFILE_SAMPLE_UPDATE\n");
2734 EMIT(" (VMPREFIX_OWN_SPECIAL_PURPOSE_STATE_DATA,\n");
2735 EMIT(" JITTER_SPECIALIZED_INSTRUCTION_OPCODE);\n");
2736 EMIT(" /* Force the compiler not move sample-profiling instrumentation\n");
2737 EMIT(" beyond this point; this way the actual user code is timed.\n");
2738 EMIT(" This is still not perfect, as residuals are materialised before\n");
2739 EMIT(" we arrive here, but should be adequate at least for slow VM\n");
2740 EMIT(" instructions. */\n");
2741 EMIT(" JITTER_PRETEND_TO_POSSIBLY_JUMP_ANYWHERE ();\n");
2742 EMIT("#endif\n");
2743 EMIT("#if defined (JITTER_PROFILE_COUNT)\n");
2744 EMIT(" /* Notice that, differently from the code above, this\n");
2745 EMIT(" instrumentation code *can* be reordered freely: as long as a\n");
2746 EMIT(" VM instruction is counted, the count increment can be placed\n");
2747 EMIT(" anyehere. Let GCC move this code and possibly achieve better\n");
2748 EMIT(" throughput by exploiting instruction-level parallelism and\n");
2749 EMIT(" therefore approximate more closely a non-profiled build. */\n");
2750 EMIT(" JITTER_PROFILE_COUNT_UPDATE\n");
2751 EMIT(" (VMPREFIX_OWN_SPECIAL_PURPOSE_STATE_DATA,\n");
2752 EMIT(" JITTER_SPECIALIZED_INSTRUCTION_OPCODE);\n");
2753 EMIT("#endif\n");
2754 EMIT("\n");
2755
2756 /* Emit the user C code for the beginning of every instruction, if any. */
2757 jitterc_emit_user_c_code_to_stream
2758 (vm, f, vm->instruction_beginning_c_code, "instruction-beginning-c");
2759
2760 /* Emit user-specified code for the instruction. We have already opened a brace, so
2761 another pair is not needed. */
2762 EMIT("\n /* User code for %s . */\n", sins->name);
2763 EMIT("%s\n", uins->code);
2764 EMIT(" /* End of the user code for %s . */\n\n", sins->name);
2765
2766 /* Emit the user C code for the end of every instruction, if any. Notice
2767 that the code is not always reachable. */
2768 jitterc_emit_user_c_code_to_stream (vm, f, vm->instruction_end_c_code,
2769 "instruction-end-c");
2770
2771 if (! is_relocatable)
2772 {
2773 EMIT("#ifdef JITTER_REPLICATE\n");
2774 EMIT(" /* Advance the instruction pointer, if any, to skip residuals;\n");
2775 EMIT(" then jump back to replicated code. */\n");
2776 EMIT(" const void *_jitter_back_to_replicated_code_pointer = JITTER_ARGP%i;\n",
2777 (int) (gl_list_size (sins->specialized_arguments) - 1));
2778 EMIT(" JITTER_SKIP_RESIDUALS_;\n");
2779 EMIT(" goto * _jitter_back_to_replicated_code_pointer;\n");
2780 EMIT("#endif // #ifdef JITTER_REPLICATE\n\n");
2781 }
2782
2783 /* Undefine macros only visible in caller instructions. */
2784 if (is_caller)
2785 {
2786 EMIT(" /* Undefine macros only visible in caller instructions. */\n");
2787 EMIT("# undef JITTER_BRANCH_AND_LINK\n");
2788 EMIT("# undef JITTER_BRANCH_FAST_AND_LINK\n\n");
2789 }
2790
2791 /* Undefine argument macros. Those will be redefined before the next
2792 instruction as needed; it would be dangerous to leave previous
2793 definitions active, because some instruction body coming after this
2794 might reuse some old definition by mistake in case the new instruction
2795 doesn't override it. */
2796 EMIT(" /* Undefine the %s argument macros so they can't be used\n",
2797 sins->name);
2798 EMIT(" by mistake in the instruction body coming next. */\n");
2799 int j; char *comma __attribute__ ((unused));
2800 FOR_LIST(j, comma, sins->specialized_arguments)
2801 {
2802 EMIT("# undef JITTER_SLOW_REGISTER_OFFSET%i\n", j);
2803 EMIT("# undef JITTER_ARG%i\n", j);
2804 EMIT("# undef JITTER_ARGN%i\n", j);
2805 EMIT("# undef JITTER_ARGU%i\n", j);
2806 EMIT("# undef JITTER_ARGP%i\n", j);
2807 EMIT("# undef JITTER_ARGF%i\n", j);
2808 }
2809
2810 /* Undefine the specialized instruction opcode and name. */
2811 EMIT("\n");
2812 EMIT("# undef JITTER_SPECIALIZED_INSTRUCTION_OPCODE\n");
2813 EMIT("# undef JITTER_SPECIALIZED_INSTRUCTION_NAME\n");
2814 EMIT("# undef JITTER_SPECIALIZED_INSTRUCTION_MANGLED_NAME\n\n");
2815
2816 EMIT(" }\n");
2817
2818 /* If we have defined a link, undefine it: it is only visible in its
2819 instruction. */
2820 if (is_callee)
2821 {
2822 EMIT(" /* Undefine the link macro. */\n");
2823 EMIT("# undef JITTER_LINK\n\n");
2824 }
2825 if (is_caller)
2826 {
2827 EMIT("#if defined(JITTER_DISPATCH_NO_THREADING) \\\n");
2828 EMIT(" && ! defined(JITTER_MACHINE_SUPPORTS_PROCEDURE)\n");
2829 EMIT("# undef JITTER_RETURN_ADDRESS\n");
2830 EMIT("#endif\n\n");
2831 }
2832
2833 /* This is the instruction epilog only for relocatable instructions, and
2834 when replication is disabled. */
2835 if (! is_relocatable)
2836 EMIT("#ifndef JITTER_REPLICATE\n");
2837 EMIT(" JITTER_INSTRUCTION_EPILOG_(%s, %s, JITTER_SPECIALIZED_INSTRUCTION_RESIDUAL_ARITY)\n",
2838 sins->name, sins->mangled_name);
2839 if (! is_relocatable)
2840 EMIT("#endif // #ifndef JITTER_REPLICATE\n");
2841 EMIT("# undef JITTER_SPECIALIZED_INSTRUCTION_RESIDUAL_ARITY\n");
2842 EMIT("\n");
2843 }
2844 EMIT(" /* End of the ordinary specialized instructions. */\n\n");
2845 }
2846
2847 /* Emit the patch-in header, before the main executor. */
2848 static void
jitterc_emit_patch_in_header(FILE * f,const struct jitterc_vm * vm)2849 jitterc_emit_patch_in_header (FILE *f, const struct jitterc_vm *vm)
2850 {
2851 /* Generate the patch-in header. The generated code expands to an inline asm
2852 statement. It is convenient to keep header and footer within the main
2853 executor function, so as to guarantee that the order is respected. */
2854 EMIT("#ifdef JITTER_HAVE_PATCH_IN\n");
2855 EMIT(" /* Generate the single patch-in header for this executor as a\n");
2856 EMIT(" global asm statement. This expands into a global definition in\n");
2857 EMIT(" assembly in a separate subsection, and relies on toplevel C\n");
2858 EMIT(" definitions not being reordered: vmprefix_execute_or_initialize\n");
2859 EMIT(" will add to the same global. Do the same for defects. */\n");
2860 EMIT(" JITTER_DEFECT_HEADER(vmprefix);\n");
2861 EMIT(" JITTER_PATCH_IN_HEADER(vmprefix);\n");
2862 EMIT("#endif // #ifdef JITTER_HAVE_PATCH_IN\n\n");
2863 EMIT("#ifndef JITTER_DISPATCH_SWITCH\n");
2864 EMIT(" JITTER_DATA_LOCATION_HEADER(vmprefix);\n");
2865 EMIT("#endif // #ifndef JITTER_DISPATCH_SWITCH\n");
2866 EMIT("\n");
2867 }
2868
2869 /* Emit the patch-in footer, after the main executor. */
2870 static void
jitterc_emit_patch_in_footer(FILE * f,const struct jitterc_vm * vm)2871 jitterc_emit_patch_in_footer (FILE *f, const struct jitterc_vm *vm)
2872 {
2873 /* Generate the patch-in footer. See the comment in
2874 jitterc_emit_patch_in_header . */
2875 EMIT("#ifndef JITTER_DISPATCH_SWITCH\n");
2876 EMIT(" JITTER_DATA_LOCATION_FOOTER(vmprefix);\n");
2877 EMIT("#endif // #ifndef JITTER_DISPATCH_SWITCH\n");
2878 EMIT("#ifdef JITTER_HAVE_PATCH_IN\n");
2879 EMIT(" /* Close the patch-in global definition for this executor. This defines a\n");
2880 EMIT(" new global in the patch-in subsection, holding the descriptor number.\n");
2881 EMIT(" This is a global asm statement. Same for defects. See the comment before\n");
2882 EMIT(" the JITTER_PATCH_IN_HEADER use above. */\n");
2883 EMIT(" JITTER_PATCH_IN_FOOTER(vmprefix);\n");
2884 EMIT(" JITTER_DEFECT_FOOTER(vmprefix);\n");
2885 EMIT("#endif // #ifdef JITTER_HAVE_PATCH_IN\n\n");
2886 }
2887
2888 /* Emit the beginning of the case for a special specialized instruction in the
2889 executor. The C code for the instruction body must be emitted right after
2890 this. */
2891 static void
jitterc_emit_executor_special_specialized_instruction_beginning(FILE * f,const struct jitterc_vm * vm,const char * name,enum jitter_specialized_instruction_opcode opcode,const char * hotness,int residual_arity)2892 jitterc_emit_executor_special_specialized_instruction_beginning
2893 (FILE *f, const struct jitterc_vm *vm,
2894 const char *name,
2895 enum jitter_specialized_instruction_opcode opcode,
2896 const char *hotness, int residual_arity)
2897 {
2898 EMIT("JITTER_INSTRUCTION_PROLOG_(%s, %s, %s)\n",
2899 name, jitterc_mangle (name), hotness);
2900 EMIT("#define JITTER_SPECIALIZED_INSTRUCTION_RESIDUAL_ARITY %i\n",
2901 residual_arity);
2902 EMIT("#define JITTER_SPECIALIZED_INSTRUCTION_OPCODE %i\n", opcode);
2903 EMIT("#define JITTER_SPECIALIZED_INSTRUCTION_NAME %s\n", name);
2904 EMIT("#define JITTER_SPECIALIZED_INSTRUCTION_MANGLED_NAME %s\n",
2905 jitterc_mangle (name));
2906 EMIT("{\n");
2907 }
2908
2909 /* Emit the end of the case for a special specialized instruction in the
2910 executor. This must follow the emission of the C instruction body. */
2911 static void
jitterc_emit_executor_special_specialized_instruction_end(FILE * f,const struct jitterc_vm * vm,const char * name,enum jitter_specialized_instruction_opcode opcode,const char * hotness,int residual_arity)2912 jitterc_emit_executor_special_specialized_instruction_end
2913 (FILE *f, const struct jitterc_vm *vm,
2914 const char *name,
2915 enum jitter_specialized_instruction_opcode opcode,
2916 const char *hotness, int residual_arity)
2917 {
2918 EMIT("}\n");
2919 EMIT("JITTER_INSTRUCTION_EPILOG_(%s, %s, %i)\n",
2920 name, jitterc_mangle (name), residual_arity);
2921 EMIT("#undef JITTER_SPECIALIZED_INSTRUCTION_OPCODE\n");
2922 EMIT("#undef JITTER_SPECIALIZED_INSTRUCTION_NAME\n");
2923 EMIT("#undef JITTER_SPECIALIZED_INSTRUCTION_MANGLED_NAME\n");
2924 EMIT("#undef JITTER_SPECIALIZED_INSTRUCTION_RESIDUAL_ARITY\n");
2925 EMIT("\n");
2926 }
2927
2928 /* Emit the case for a special specialized instruction in the executor. */
2929 static void
jitterc_emit_executor_special_specialized_instruction(FILE * f,const struct jitterc_vm * vm,const char * name,enum jitter_specialized_instruction_opcode opcode,const char * hotness,int residual_arity,const char * c_code)2930 jitterc_emit_executor_special_specialized_instruction
2931 (FILE *f, const struct jitterc_vm *vm,
2932 const char *name,
2933 enum jitter_specialized_instruction_opcode opcode,
2934 const char *hotness, int residual_arity,
2935 const char *c_code)
2936 {
2937 jitterc_emit_executor_special_specialized_instruction_beginning
2938 (f, vm, name, opcode, hotness, residual_arity);
2939 EMIT("\n%s\n", c_code);
2940 jitterc_emit_executor_special_specialized_instruction_end
2941 (f, vm, name, opcode, hotness, residual_arity);
2942 }
2943
2944 /* Emit macro calls to generate data locations in a separate subsection. This
2945 needs to be called as the body of the special specialized instruction
2946 !DATALOCATIONS . */
2947 static void
jitterc_emit_executor_data_locations(FILE * f,const struct jitterc_vm * vm)2948 jitterc_emit_executor_data_locations (FILE *f, const struct jitterc_vm *vm)
2949 {
2950 int i, j; char *comma __attribute__ ((unused));
2951 EMIT("#ifndef JITTER_DISPATCH_SWITCH\n");
2952
2953 /* First emit reserved registers: these are in fact guaranteed to be
2954 registers. */
2955
2956 /* Instruction pointer, if any. */
2957 EMIT("#ifndef JITTER_DISPATCH_NO_THREADING\n");
2958 EMIT(" JITTER_DATA_LOCATION_DATUM (\"instruction pointer\", jitter_ip);\n");
2959 EMIT("#endif // #ifndef JITTER_DISPATCH_NO_THREADING\n");
2960
2961 /* Base. */
2962 EMIT(" JITTER_DATA_LOCATION_DATUM (\"base\", jitter_array_base);\n");
2963
2964 /* Scratch, if any. */
2965 EMIT("#ifdef JITTER_DISPATCH_NO_THREADING\n");
2966 EMIT("#ifdef JITTER_SCRATCH_REGISTER\n");
2967 EMIT(" JITTER_DATA_LOCATION_DATUM (\"scratch\", jitter_residual_argument_scratch_register_variable);\n");
2968 EMIT("#endif // #ifdef JITTER_SCRATCH_REGISTER\n\n");
2969 EMIT("#endif // #ifdef JITTER_DISPATCH_NO_THREADING\n");
2970
2971 /* Residual registers, if any. */
2972 EMIT("#ifdef JITTER_DISPATCH_NO_THREADING\n");
2973 for (i = 0; i < vm->max_residual_arity; i ++)
2974 {
2975 EMIT("#if (%i < JITTER_RESIDUAL_REGISTER_NO)\n", i);
2976 EMIT(" JITTER_DATA_LOCATION_DATUM (\"residual %i\", jitter_residual_argument_%i_register_variable);\n", i, i);
2977 EMIT("#endif // #if (%i < JITTER_RESIDUAL_REGISTER_NO)\n", i);
2978 }
2979 EMIT("#endif // #ifdef JITTER_DISPATCH_NO_THREADING\n");
2980
2981 /* Link register, if any. */
2982 EMIT("#if defined(JITTER_DISPATCH_SWITCH) \\\n");
2983 EMIT(" || defined(JITTER_DISPATCH_DIRECT_THREADING) \\\n");
2984 EMIT(" || defined(JITTER_DISPATCH_MINIMAL_THREADING) \\\n");
2985 EMIT(" || ( defined(JITTER_DISPATCH_NO_THREADING) \\\n");
2986 EMIT(" && ! defined(JITTER_MACHINE_SUPPORTS_PROCEDURE))\n");
2987 EMIT("\n");
2988 EMIT(" JITTER_DATA_LOCATION_DATUM (\"link register\", jitter_state_runtime._jitter_link);\n");
2989 EMIT("#endif // link register\n");
2990
2991 /* For each stack... */
2992 FOR_LIST(i, comma, vm->stacks)
2993 {
2994 const struct jitterc_stack *stack = gl_list_get_at (vm->stacks, i);
2995 const char * stack_name = stack->lower_case_long_name;
2996 if (stack->implementation == jitterc_stack_implementation_tos)
2997 {
2998 EMIT(" JITTER_DATA_LOCATION_DATUM (\"%s top\", \n", stack_name);
2999 EMIT(" JITTER_STACK_TOS_TOP_NAME (whatever, jitter_state_runtime., %s));\n",
3000 stack_name);
3001 EMIT(" JITTER_DATA_LOCATION_DATUM (\"%s undertop ptr\", \n", stack_name);
3002 EMIT(" JITTER_STACK_TOS_UNDER_TOP_POINTER_NAME (whatever, jitter_state_runtime., %s));\n",
3003 stack_name);
3004 }
3005 else if (stack->implementation == jitterc_stack_implementation_no_tos)
3006
3007 {
3008 EMIT(" JITTER_DATA_LOCATION_DATUM (\"%s top ptr\", \n", stack_name);
3009 EMIT(" JITTER_STACK_NTOS_TOP_POINTER_NAME (whatever, jitter_state_runtime., %s));\n",
3010 stack_name);
3011 }
3012 else
3013 jitter_fatal ("stack implementation unknown: this should not happen");
3014
3015 }
3016
3017 /* For each register class... */
3018 FOR_LIST(i, comma, vm->register_classes)
3019 {
3020 const struct jitterc_register_class *c
3021 = (gl_list_get_at (vm->register_classes, i));
3022 /* Emit each fast register as a datum. */
3023 for (j = 0; j < c->fast_register_no; j ++)
3024 EMIT("JITTER_DATA_LOCATION_DATUM(\"%%%%%c%i\", JITTER_REGISTER_%c_%i);\n",
3025 c->letter, j, c->letter, j);
3026 }
3027 EMIT("#endif // #ifndef JITTER_DISPATCH_SWITCH\n");
3028 }
3029
3030 static void
jitterc_emit_executor_main_function(FILE * f,const struct jitterc_vm * vm)3031 jitterc_emit_executor_main_function
3032 (FILE *f, const struct jitterc_vm *vm)
3033 {
3034 /* Generate the actual executor main function. */
3035 EMIT("static void\n");
3036 EMIT("vmprefix_execute_or_initialize (bool jitter_initialize,\n");
3037 EMIT(" vmprefix_program_point jitter_initial_program_point,\n");
3038 EMIT(" struct vmprefix_state * const jitter_original_state)\n");
3039 EMIT("{\n");
3040
3041 /* Emit debugging prints. FIXME: implement something like this, cleanly, in a
3042 different function. */
3043 /*
3044 EMIT("#ifdef JITTER_DISPATCH_NO_THREADING\n");
3045 EMIT(" printf (\"JITTER_RESIDUAL_REGISTER_NO is %%i\\n\", (int)JITTER_RESIDUAL_REGISTER_NO);\n");
3046 EMIT("#endif // #ifdef JITTER_DISPATCH_NO_THREADING\n");
3047 EMIT(" printf (\"VMPREFIX_MAX_RESIDUAL_ARITY is %%i\\n\", (int)VMPREFIX_MAX_RESIDUAL_ARITY);\n");
3048 EMIT(" printf (\"VMPREFIX_MAX_MEMORY_RESIDUAL_ARITY is %%i\\n\", (int)VMPREFIX_MAX_MEMORY_RESIDUAL_ARITY);\n");
3049 EMIT(" {int q;\n");
3050 EMIT("#ifdef JITTER_REPLICATE\n");
3051 EMIT(" for (q = JITTER_RESIDUAL_REGISTER_NO; q < VMPREFIX_MAX_MEMORY_RESIDUAL_ARITY; q ++)\n");
3052 EMIT(" printf (\"VMPREFIX_RESIDUAL_OFFSET(%%i) is %%i or 0x%%x\\n\", q, (int)VMPREFIX_RESIDUAL_OFFSET(q), (int)VMPREFIX_RESIDUAL_OFFSET(q));\n");
3053 EMIT("#endif // #ifdef JITTER_REPLICATE\n");
3054 EMIT(" printf (\"VMPREFIX_REGISTER_r_FAST_REGISTER_NO is %%i\\n\", (int)VMPREFIX_REGISTER_r_FAST_REGISTER_NO);\n");
3055 EMIT(" for (q = VMPREFIX_REGISTER_r_FAST_REGISTER_NO; q < (VMPREFIX_REGISTER_r_FAST_REGISTER_NO + 10); q ++)\n");
3056 EMIT(" printf (\"VMPREFIX_SLOW_REGISTER_OFFSET(r, %%i) is %%i or 0x%%x\\n\", q, (int)VMPREFIX_SLOW_REGISTER_OFFSET(r, q), (int)VMPREFIX_SLOW_REGISTER_OFFSET(r, q));\n");
3057 EMIT(" }\n");
3058 EMIT(" asm volatile (\"\\n.pushsection .rodata\\n\"\n");
3059 EMIT(" \"\\nFOO:\\n\"\n");
3060 EMIT(" \"\\n.asciz \\\"" JITTER_STRINGIFY(jitter_initial_program_point) " is at %%[thing]\\\"\\n\"\n");
3061 EMIT(" \"\\n.popsection\\n\"\n");
3062 EMIT(" :\n");
3063 EMIT(" : [thing] \"X\" (jitter_initial_program_point)\n");
3064 EMIT(" );\n");
3065 EMIT("\n\n");
3066 */
3067 EMIT("#ifdef JITTER_DISPATCH_NO_THREADING\n");
3068 EMIT(" /* Save the values in the registers we reserved as global variables,\n");
3069 EMIT(" since from the point of view of the other C compilation units such\n");
3070 EMIT(" registers are callee-save. FIXME: this is not really needed when\n");
3071 EMIT(" initializing, if I've been careful; but for the time being I want\n");
3072 EMIT(" to play it safe. */\n");
3073 EMIT(" union jitter_word jitter_register_buffer [VMPREFIX_REGISTER_BUFFER_ELEMENT_NO];\n");
3074 EMIT(" vmprefix_save_registers (jitter_register_buffer);\n");
3075 EMIT("#endif // #ifdef JITTER_DISPATCH_NO_THREADING\n\n");
3076
3077 /* Emit the patch-in header. This must come before the frist patch-in or
3078 defect use. */
3079 jitterc_emit_patch_in_header (f, vm);
3080
3081 /* The main executor function begins with three big static arrays containing
3082 the labels where every specialized instruction begins and ends, and their sizes
3083 (only when replication is enabled), to be used only at initialization. */
3084 EMIT(" /* Initialization. This is only called once at startup. */\n");
3085 EMIT(" if (__builtin_expect (jitter_initialize, false))\n");
3086 EMIT(" {\n");
3087 EMIT(" /* Make sure that vm1 and vm2 were macroexpanded consistently\n");
3088 EMIT(" with respect to instrumentation macros. This relies on the\n");
3089 EMIT(" enum values for each feature working as individual bits in a\n");
3090 EMIT(" bitmask: see the comment in jitter/jitter-vm.h . */\n");
3091 EMIT(" enum jitter_vm_instrumentation correct_instrumentation\n");
3092 EMIT(" = jitter_vm_instrumentation_none;\n");
3093 EMIT("#if defined (JITTER_PROFILE_COUNT)\n");
3094 EMIT(" correct_instrumentation |= jitter_vm_instrumentation_count;\n");
3095 EMIT("#endif\n");
3096 EMIT("#if defined (JITTER_PROFILE_SAMPLE)\n");
3097 EMIT(" correct_instrumentation |= jitter_vm_instrumentation_sample;\n");
3098 EMIT("#endif\n");
3099 EMIT(" if (vmprefix_vm_configuration->instrumentation != correct_instrumentation)\n");
3100 EMIT(" jitter_fatal (\"vm1 and vm2 were compiled with different profiling \"\n");
3101 EMIT(" \"instrumentation macros. Please recompile with coherent \"\n");
3102 EMIT(" \"CPPFLAGS\");\n");
3103 EMIT("\n");
3104
3105 EMIT("#if defined (JITTER_PROFILE_SAMPLE)\n");
3106 EMIT(" /* Initialise the sample-profile subsystem, once and for all. */\n");
3107 EMIT(" vmprefix_profile_sample_initialize ();\n");
3108 EMIT("#endif // #if defined (JITTER_PROFILE_SAMPLE)\n");
3109 EMIT("\n");
3110
3111 EMIT("#ifndef JITTER_DISPATCH_SWITCH\n");
3112 EMIT(" /* FIXME: I can do this with only one relocation, by keeping\n");
3113 EMIT(" a pointer to the first VM instruction beginning in a static\n");
3114 EMIT(" variable, and then having a static vector of offsets with\n");
3115 EMIT(" respect to the first pointer. This will slightly complicate\n");
3116 EMIT(" my initialization code, but should make startup faster.\n");
3117 EMIT(" FIXME: that won't work on AVR, according to the GCC\n");
3118 EMIT(" documentation. Do I care? Probably not, since AVRs can't\n");
3119 EMIT(" address more than 2^16 bytes, which is too little to run my\n");
3120 EMIT(" VMs. */\n");
3121 EMIT(" static const jitter_thread vmprefix_the_threads []\n");
3122 EMIT(" = {\n");
3123 int i; char *comma;
3124 FOR_LIST(i, comma, vm->specialized_instructions)
3125 {
3126 const struct jitterc_specialized_instruction* sins
3127 = ((const struct jitterc_specialized_instruction*)
3128 gl_list_get_at (vm->specialized_instructions, i));
3129 EMIT(" && JITTER_SPECIALIZED_INSTRUCTION_BEGIN_LABEL_OF(%s)%s\n",
3130 sins->mangled_name, comma);
3131 }
3132 EMIT(" };\n");
3133
3134 /* Also generate thread ends. */
3135 EMIT(" static const jitter_thread vmprefix_the_thread_ends []\n");
3136 EMIT(" = {\n");
3137 FOR_LIST(i, comma, vm->specialized_instructions)
3138 {
3139 const struct jitterc_specialized_instruction* sins
3140 = ((const struct jitterc_specialized_instruction*)
3141 gl_list_get_at (vm->specialized_instructions, i));
3142 EMIT(" && JITTER_SPECIALIZED_INSTRUCTION_END_LABEL_OF(%s)%s\n",
3143 sins->mangled_name, comma);
3144 }
3145 EMIT(" };\n");
3146 EMIT(" static const long\n");
3147 EMIT(" vmprefix_the_thread_sizes [VMPREFIX_SPECIALIZED_INSTRUCTION_NO]\n");
3148 EMIT(" = {\n");
3149 FOR_LIST(i, comma, vm->specialized_instructions)
3150 {
3151 const struct jitterc_specialized_instruction* sins
3152 = ((const struct jitterc_specialized_instruction*)
3153 gl_list_get_at (vm->specialized_instructions, i));
3154 EMIT(" (long) ((jitter_int) (&& JITTER_SPECIALIZED_INSTRUCTION_END_LABEL_OF(%s))\n",
3155 sins->mangled_name);
3156 EMIT(" - (jitter_int) (&& JITTER_SPECIALIZED_INSTRUCTION_BEGIN_LABEL_OF(%s)))%s\n",
3157 sins->mangled_name, comma);
3158 }
3159 EMIT(" };\n");
3160 EMIT(" vmprefix_thread_sizes = vmprefix_the_thread_sizes;\n");
3161 EMIT(" vmprefix_threads = vmprefix_the_threads;\n");
3162 EMIT(" vmprefix_thread_ends = vmprefix_the_thread_ends;\n");
3163
3164 /// FIXME: this is for debugging: begin
3165 EMIT("#ifdef JITTER_PROFILE\n");
3166 EMIT(" fprintf (stderr, \"VM instruction range: \");\n");
3167 const struct jitterc_specialized_instruction* first_sins
3168 = ((const struct jitterc_specialized_instruction*)
3169 gl_list_get_at (vm->specialized_instructions, 0));
3170 const struct jitterc_specialized_instruction* last_sins
3171 = ((const struct jitterc_specialized_instruction*)
3172 gl_list_get_at (vm->specialized_instructions,
3173 gl_list_size (vm->specialized_instructions) - 1));
3174 EMIT(" fprintf (stderr, \"[%%p, \", && JITTER_SPECIALIZED_INSTRUCTION_BEGIN_LABEL_OF(%s));\n",
3175 first_sins->mangled_name);
3176 EMIT(" fprintf (stderr, \"%%p)\", && JITTER_SPECIALIZED_INSTRUCTION_END_LABEL_OF(%s));\n",
3177 last_sins->mangled_name);
3178 EMIT(" fprintf (stderr, \"\\n\");\n");
3179 EMIT("#endif // #ifdef JITTER_PROFILE\n");
3180 /// FIXME: this is for debugging: end
3181
3182 EMIT("#endif // #ifndef JITTER_DISPATCH_SWITCH\n");
3183 EMIT("\n");
3184 EMIT(" /* Back to regular C, without our reserved registers if any; I can share\n");
3185 EMIT(" the end code with the non-initialization case. */\n");
3186 EMIT("#ifdef JITTER_HAVE_PATCH_IN\n");
3187 EMIT(" //JITTER_DUMP_PATCH_IN_DESCRIPTORS(vmprefix);\n");
3188 EMIT("#endif // #ifdef JITTER_HAVE_PATCH_IN\n");
3189 EMIT(" goto jitter_possibly_restore_registers_and_return_label;\n");
3190 EMIT(" }\n");
3191 EMIT("\n\n");
3192
3193 EMIT(" /* Here is the actual *executor* initialization, to be run before\n");
3194 EMIT(" actually running the code. */\n\n");
3195
3196 jitterc_emit_executor_global_wrappers (f, vm);
3197
3198 /* If control flow reaches this point then we are actually executing code. */
3199 EMIT(" /* Make an automatic struct holding a copy of the state whose pointer was given.\n");
3200 EMIT(" The idea is that the copy should be in registers, as far as possible. */\n");
3201 EMIT(" struct vmprefix_state_runtime jitter_state_runtime\n");
3202 EMIT(" = jitter_original_state->vmprefix_state_runtime;\n\n");
3203
3204 EMIT(" /* Initialize a pointer to The Array base. This pointer will be in a\n");
3205 EMIT(" global register variable with no-threading dispatch, and with\n");
3206 EMIT(" other dispatches in an automatic variable, still hopefully kept\n");
3207 EMIT(" in a register. */\n");
3208 EMIT("/* About the pragma, look for \"-Wmaybe-uninitialized\" in the comments above. FIXME: this is to avoid a GCC warning with profiling. Check with profiling on. */\n");
3209 EMIT("#pragma GCC diagnostic push\n");
3210 EMIT("#pragma GCC diagnostic ignored \"-Wmaybe-uninitialized\"\n");
3211 EMIT("#ifdef JITTER_DISPATCH_NO_THREADING\n");
3212 EMIT("# define jitter_array_base vmprefix_array_base_register_variable\n");
3213 EMIT("#else\n");
3214 EMIT(" char * restrict jitter_array_base __attribute__ ((unused));\n");
3215 EMIT("#endif // #ifdef JITTER_DISPATCH_NO_THREADING\n");
3216 EMIT("#pragma GCC diagnostic pop\n");
3217 EMIT(" jitter_array_base\n");
3218 EMIT(" = (((char *) jitter_original_state->vmprefix_state_backing.jitter_array)\n");
3219 EMIT(" + JITTER_ARRAY_BIAS);\n");
3220 EMIT("\n");
3221
3222 EMIT(" /* Declare the instruction pointer from the thread array, unless the dispatching\n");
3223 EMIT(" model is no-threading, in which case no thread array even exists. */\n");
3224 EMIT(" vmprefix_program_point jitter_ip = NULL; /* Invalidate to catch errors. */\n");
3225
3226 /* EMIT(" /\* Declare a variable to be supposedly used as a computed goto target for jumping;\n"); */
3227 /* EMIT(" to any VM instruction; in actuality the variable is not ever accessed by reachable\n"); */
3228 /* EMIT(" code, but only mentioned in inline assembly constraints to force GCC to keep its\n"); */
3229 /* EMIT(" register allocation compatible between the end of a VM instruction and the beginning\n"); */
3230 /* EMIT(" of any other. Assembly constraints will always require jitter_anywhere_label to be\n"); */
3231 /* EMIT(" in memory rather than in a register, so as not to waste one register on this. *\/\n"); */
3232 /* EMIT(" volatile union jitter_word jitter_anywhere_variable __attribute__ ((unused));\n\n"); */
3233
3234 EMIT("#ifdef JITTER_REPLICATE\n");
3235 EMIT(" /* Save an instruction address within this function, to jump to at VM exit\n");
3236 EMIT(" time; that way we can be sure that at exit time we are back to\n");
3237 EMIT(" non-replicated code, and stuff like PC-relative addressing work again\n");
3238 EMIT(" without special tricks. This variable may safely (and actually should,\n");
3239 EMIT(" for performance) be kept on the stack. We need it to be volatile to\n");
3240 EMIT(" prevent the compiler from being too clever and jump to it using a\n");
3241 EMIT(" PC-relative displacement from replicated code. It must not be static,\n");
3242 EMIT(" since non-automatic variables are problematic to access from replicated\n");
3243 EMIT(" code, which might use PC-relative addressing. */\n");
3244 EMIT(" volatile typeof (&& jitter_exit_vm_label) restrict\n");
3245 EMIT(" jitter_saved_exit_non_replicated_code_pointer = &&jitter_exit_vm_label;\n");
3246 EMIT(" JITTER_MARK_MEMORY_AS_SET_BY_ASSEMBLY(jitter_saved_exit_non_replicated_code_pointer);\n");
3247 EMIT("#endif // #ifdef JITTER_REPLICATE\n");
3248 EMIT("\n\n");
3249
3250 // FIXME: move to a new function: BEGIN
3251 /* Generate a variable per non-relocatable specialized instruction holding the
3252 address where to jump out of the relocated code. This will be useful as a
3253 jump target, in the first implementation of non-relocatability. */
3254 EMIT("#ifdef JITTER_REPLICATE\n");
3255 EMIT(" /* FIXME: comment. */\n");
3256 FOR_LIST(i, comma, vm->specialized_instructions)
3257 {
3258 const struct jitterc_specialized_instruction* sins
3259 = ((const struct jitterc_specialized_instruction*)
3260 gl_list_get_at (vm->specialized_instructions, i));
3261
3262 /* Ignore special and relocatable specialized instructions. */
3263 if (sins->instruction == NULL
3264 || sins->relocatability == jitterc_relocatability_relocatable)
3265 continue;
3266
3267 EMIT(" volatile void *JITTER_SPECIALIZED_INSTRUCTION_NON_RELOCATABLE_CODE_VARIABLE_OF(%s)\n",
3268 sins->mangled_name);
3269 EMIT(" = && JITTER_SPECIALIZED_INSTRUCTION_NON_RELOCATABLE_CODE_LABEL_OF(%s);\n",
3270 sins->mangled_name);
3271 EMIT(" asm volatile (\"#pretend to affect \" JITTER_STRINGIFY(JITTER_SPECIALIZED_INSTRUCTION_NON_RELOCATABLE_CODE_VARIABLE_OF(%s)) \"\\n\"\n", sins->mangled_name);
3272 EMIT(" : \"+m\" (JITTER_SPECIALIZED_INSTRUCTION_NON_RELOCATABLE_CODE_VARIABLE_OF(%s)));\n", sins->mangled_name);
3273 }
3274 EMIT("#endif // #ifdef JITTER_REPLICATE\n");
3275 // FIXME: move to a new function: END
3276
3277 /* Insert C code from the user. This is supposed to come in right before
3278 execution starts. */
3279 EMIT(" /* Initialization C code from the user */\n");
3280 EMIT("%s", vm->initialization_c_code);
3281 EMIT(" /* End of the initialization C code from the user */\n\n");
3282 EMIT("\n");
3283
3284 /* Insert architecture-specific execution-beginning code. */
3285 EMIT(" /* Execute architecture-specific execution-beginning code, if any.\n");
3286 EMIT(" Make sure it is safe to expand the macro without do..while\n");
3287 EMIT(" (false). */\n");
3288 EMIT(" {}; JITTER_EXECUTION_BEGINNING_; {};\n");
3289 EMIT("\n");
3290
3291 EMIT("#if defined (JITTER_PROFILE_SAMPLE)\n");
3292 EMIT(" /* Start sample-profiling: this starts the periodic timer signal,\n");
3293 EMIT(" whose handler will look at the current instruction field within\n");
3294 EMIT(" the special-purpose struct in the Array. */\n");
3295 EMIT(" vmprefix_profile_sample_start (VMPREFIX_OWN_STATE);\n");
3296 EMIT("#endif // #if defined (JITTER_PROFILE_SAMPLE)\n");
3297 EMIT("\n");
3298
3299 EMIT(" /* Jump to the first instruction. If replication is enabled this point\n");
3300 EMIT(" marks the boundary between the ordinary world of C compiled code and\n");
3301 EMIT(" the more fragile replicated code, where PC-relative address does\n");
3302 EMIT(" not work as intended (which prevents the use of global and static\n");
3303 EMIT(" variables, string literals and possibly large literal constants), and\n");
3304 EMIT(" GDB gets easily confused. */\n");
3305 EMIT(" jitter_ip = jitter_initial_program_point;\n\n");
3306 EMIT(" /* This is the actual jump to the first instruction: it's not an\n");
3307 EMIT(" inline asm constraint lie like below. */\n\n");
3308 EMIT("# if defined(JITTER_DISPATCH_SWITCH)\n");
3309 EMIT(" goto jitter_dispatching_switch_label;\n");
3310 EMIT("# elif (defined(JITTER_DISPATCH_DIRECT_THREADING) \\\n");
3311 EMIT(" || defined(JITTER_DISPATCH_MINIMAL_THREADING))\n");
3312 EMIT(" goto * (jitter_ip->label);\n");
3313 EMIT("# elif defined(JITTER_DISPATCH_NO_THREADING)\n");
3314 EMIT(" /* On no-threading we only use jitter_ip for the first instruction.\n");
3315 EMIT(" Make it an alias for the base, which will be enough to satisfy\n");
3316 EMIT(" inline assembly code which pretends to alter the instruction\n");
3317 EMIT(" pointer in ways invisible to the compiler.\n");
3318 EMIT(" At least in my tests this trick frees up one hardware register,\n");
3319 EMIT(" which is not surprising. */\n");
3320 EMIT(" goto * jitter_ip;\n");
3321 EMIT("# define jitter_ip vmprefix_array_base_register_variable\n");
3322 EMIT("# else\n");
3323 EMIT("# error \"unknown dispatch\"\n");
3324 EMIT("# endif // if ... dispatch\n");
3325
3326 EMIT(" /* FIXME: comment: this is the fake dispatch routine. */\n");
3327 // FIXME: Is clobbering memory really needed? It would be better if I didn't do this.
3328 // I should explicitly mark as set the base and possibly the instruction pointer,
3329 // but nothing more.
3330 //EMIT(" asm volatile (\"\" : : : \"memory\");\n");
3331 EMIT(" /* The label is unused (from the compiler's point of view) for simple\n");
3332 EMIT(" dispatches when not profiling. (In reality it is always unused.)\n");
3333 EMIT(" FIXME: comment. */\n");
3334 EMIT(" jitter_dispatch_label: __attribute__ ((hot, unused))\n");
3335 // FIXME: same.
3336 //EMIT(" asm volatile (\"\\njitter_dispatch_label_asm:\\n\" : : : \"memory\");\n");
3337 EMIT("#if defined(JITTER_DISPATCH_SWITCH)\n");
3338 EMIT(" /* This code is unreachable, but the compiler does not know it. FIXME: comment. */\n");
3339 EMIT(" goto jitter_dispatching_switch_label;\n");
3340 EMIT("#elif defined(JITTER_DISPATCH_DIRECT_THREADING)\n");
3341 EMIT(" /* Again this code is unreachable, but the compiler does not know it. FIXME: comment. */\n");
3342 EMIT(" goto * jitter_ip;\n");
3343 EMIT("#endif\n");
3344 EMIT("#ifdef JITTER_REPLICATE\n");
3345 EMIT(" asm volatile (\"\\njitter_dispatch_label_asm:\\n\" :);\n");
3346 EMIT(" JITTER_PRETEND_TO_UPDATE_IP_;\n");
3347 FOR_LIST(i, comma, vm->specialized_instructions)
3348 {
3349 EMIT(" JITTER_PRETEND_TO_UPDATE_IP_;\n");
3350 const struct jitterc_specialized_instruction* sins
3351 = ((const struct jitterc_specialized_instruction*)
3352 gl_list_get_at (vm->specialized_instructions, i));
3353 EMIT(" JITTER_PRETEND_TO_POSSIBLY_JUMP_TO_(JITTER_SPECIALIZED_INSTRUCTION_BEGIN_LABEL_OF(%s));\n",
3354 sins->mangled_name);
3355 /*
3356 EMIT(" JITTER_PRETEND_TO_UPDATE_IP_;\n");
3357 EMIT(" JITTER_PRETEND_TO_POSSIBLY_JUMP_TO_(JITTER_SPECIALIZED_INSTRUCTION_END_LABEL_OF(%s));\n",
3358 sins->mangled_name);
3359 */
3360 }
3361 //EMIT(" JITTER_PRETEND_TO_POSSIBLY_JUMP_TO_(a_label);\n");
3362 EMIT(" JITTER_PRETEND_TO_UPDATE_IP_;\n");
3363 EMIT(" JITTER_PRETEND_TO_POSSIBLY_JUMP_TO_(jitter_exit_vm_label);\n");
3364 EMIT(" JITTER_PRETEND_TO_UPDATE_IP_;\n");
3365 EMIT(" JITTER_PRETEND_TO_POSSIBLY_JUMP_TO_(jitter_possibly_restore_registers_and_return_label);\n");
3366 EMIT(" goto jitter_dispatch_label;\n");
3367 EMIT("#endif // #ifdef JITTER_REPLICATE\n\n");
3368
3369 /* EMIT("#ifdef JITTER_REPLICATE\n"); */
3370 /* EMIT(" /\* This is actually unreachable, but I use GCC inline assembly with\n"); */
3371 /* EMIT(" constraints declaring to jump here just to force the compiler to\n"); */
3372 /* EMIT(" allocate registers at the end of each VM instruction in a compatible\n"); */
3373 /* EMIT(" way with the beginning of any other. This code could, in theory,\n"); */
3374 /* EMIT(" jump to any label within this function -- in practice it would\n"); */
3375 /* EMIT(" crash horribly if ever reached, but that is not a problem. *\/\n"); */
3376 /* EMIT(" jitter_jump_anywhere_label: __attribute__ ((cold, unused));\n"); */
3377 /* EMIT(" jitter_next_program_point = && jitter_dispatch_label;\n"); */
3378 /* EMIT(" asm (JITTER_ASM_COMMENT_UNIQUE(\"Pretend to alter next_program_point\"\n"); */
3379 /* EMIT(" \" at %%[next_program_point] based on\"\n"); */
3380 /* EMIT(" \" jitter_state_runtime at %%[runtime]\"\n"); */
3381 /* EMIT(" \" and * jitter_original_state %%[jitter_original_state].\")\n"); */
3382 /* EMIT(" : [next_program_point] \"+m\" (jitter_next_program_point) // m\n"); */
3383 /* /\* About the constraints on [runtime], GCC 8 20170430 snapshot, */
3384 /* tested on the JitterLisp VM: */
3385 /* - "X": */
3386 /* aarch64: invalid 'asm': invalid expression as operand */
3387 /* alpha: ok */
3388 /* sh: ok */
3389 /* - "ro", "rom", "romg", "roX": */
3390 /* aarch64: ok */
3391 /* alpha: cannot reload integer constant operand in 'asm' */
3392 /* sh: cannot reload integer constant operand in 'asm' */
3393 /* Any constraint works on the other architectures I'm testing. */
3394
3395 /* This is ugly. I consider SH to be important, and Aarch64 is popular. */
3396 /* Alpha is lower-priority, but I like to support it as well. This will */
3397 /* need a conditional. The "X" constraint is more reasonable, so I will */
3398 /* single out aarch64. *\/ */
3399 /* EMIT(" : [runtime] \"X\" (jitter_state_runtime) // \"X\"\n"); */
3400 /* EMIT(" , [jitter_original_state] \"m\" (* jitter_original_state) // m\n"); */
3401 /* EMIT(" );\n"); */
3402 /* EMIT(" goto * jitter_next_program_point;\n"); */
3403 /* EMIT("#endif // #ifdef JITTER_REPLICATE\n"); */
3404 /* EMIT("\n"); */
3405
3406 /* Generate the switch dispatcher, which expands to nothing unless
3407 switch-dispatching is enabled. */
3408 EMIT("#ifdef JITTER_DISPATCH_SWITCH\n");
3409 EMIT(" /* This is the dispatching switch. At the beginning of the first VM\n");
3410 EMIT(" VM instruction and at the end of each other, control jumps here. */\n");
3411 EMIT(" jitter_dispatching_switch_label:\n");
3412 EMIT(" switch (jitter_ip->fixnum)\n");
3413 EMIT(" {\n");
3414 EMIT("#endif // #ifdef JITTER_DISPATCH_SWITCH\n");
3415 EMIT("\n");
3416
3417 /* Generate code for special specialized instructions. This has to be kept
3418 manually synchronized with jitterc-vm.c in case I add, remove or change
3419 any special specialized instruction. */
3420
3421 jitterc_emit_executor_special_specialized_instruction
3422 (f, vm, "!INVALID",
3423 jitter_specialized_instruction_opcode_INVALID,
3424 "cold", 0,
3425 "jitter_fatal (\"reached the !INVALID instruction\");");
3426 jitterc_emit_executor_special_specialized_instruction
3427 (f, vm, "!BEGINBASICBLOCK",
3428 jitter_specialized_instruction_opcode_BEGINBASICBLOCK,
3429 "hot", /* This zero is a special case. FIXME: explain. */0,
3430 "#ifdef JITTER_DISPATCH_MINIMAL_THREADING\n"
3431 " JITTER_SET_IP (jitter_ip + 1);\n"
3432 "#endif // #ifdef JITTER_DISPATCH_MINIMAL_THREADING\n");
3433 jitterc_emit_executor_special_specialized_instruction
3434 (f, vm, "!EXITVM",
3435 jitter_specialized_instruction_opcode_EXITVM,
3436 "cold", 0, "JITTER_EXIT();");
3437 jitterc_emit_executor_special_specialized_instruction_beginning
3438 (f, vm, "!DATALOCATIONS",
3439 jitter_specialized_instruction_opcode_DATALOCATIONS,
3440 "cold", 0);
3441 jitterc_emit_executor_data_locations (f, vm);
3442 jitterc_emit_executor_special_specialized_instruction_end
3443 (f, vm, "!DATALOCATIONS",
3444 jitter_specialized_instruction_opcode_DATALOCATIONS,
3445 "cold", 0);
3446 jitterc_emit_executor_special_specialized_instruction
3447 (f, vm, "!NOP",
3448 jitter_specialized_instruction_opcode_NOP,
3449 "cold", 0, " /* Do nothing. */;");
3450 jitterc_emit_executor_special_specialized_instruction
3451 (f, vm, "!UNREACHABLE0",
3452 jitter_specialized_instruction_opcode_UNREACHABLE0,
3453 "cold", 0,
3454 "jitter_fatal (\"reached the !UNREACHABLE0 instruction\");");
3455 jitterc_emit_executor_special_specialized_instruction
3456 (f, vm, "!UNREACHABLE1",
3457 jitter_specialized_instruction_opcode_UNREACHABLE1,
3458 "cold", 0,
3459 "jitter_fatal (\"reached the !UNREACHABLE1 instruction\");");
3460 jitterc_emit_executor_special_specialized_instruction
3461 (f, vm, "!UNREACHABLE2",
3462 jitter_specialized_instruction_opcode_UNREACHABLE2,
3463 "cold", 0,
3464 "jitter_fatal (\"reached the !UNREACHABLE2 instruction\");");
3465
3466 /* Generate code for the ordinary specialized instructions as specified in
3467 user code. */
3468 jitterc_emit_executor_ordinary_specialized_instructions (f, vm);
3469
3470 /* Close the dispatcher switch; of course this will expand to nothing unless
3471 switch-dispatching is enabled. */
3472 EMIT("#ifdef JITTER_DISPATCH_SWITCH\n");
3473 EMIT(" default:\n");
3474 EMIT(" jitter_fatal (\"invalid opcode %%li for VM specialized instruction\",\n");
3475 EMIT(" (long) jitter_ip->fixnum);\n");
3476 EMIT(" } /* switch */\n");
3477 EMIT("#endif // #ifdef JITTER_DISPATCH_SWITCH\n");
3478 EMIT("\n");
3479
3480 /* Emit the final part of the function, consisting in the label to jump to
3481 before exiting from the executor. */
3482 EMIT(" /* The code jumps here when executing the special specialized instruction\n");
3483 EMIT(" EXITVM, or on a call to the macro JITTER_EXIT from an ordinary specialized\n");
3484 EMIT(" instruction. This code is *not* replicated: when replication is enabled\n");
3485 EMIT(" jumping here means crossing the boundary from the fragaile replicated\n");
3486 EMIT(" code back into ordinary compiled C, where PC-relative addressing works. */\n");
3487 EMIT(" jitter_exit_vm_label: __attribute__ ((cold));\n");
3488 EMIT(" JITTER_COMMENT_IN_ASM_(\"About to exit the function\");\n");
3489 EMIT(" // fprintf (stderr, \"Restoring the VM state to the struct...\\n\");\n");
3490 EMIT(" /* Copy the VM state from the local copy we have modified back to\n");
3491 EMIT(" the structure to which we received a pointer. */\n");
3492 EMIT(" jitter_original_state->vmprefix_state_runtime = jitter_state_runtime;\n");
3493 EMIT("\n");
3494 EMIT(" // fprintf (stderr, \"Exiting the VM...\\n\");\n\n");
3495 EMIT("\n");
3496 EMIT("#if defined (JITTER_PROFILE_SAMPLE)\n");
3497 EMIT(" /* Stop sample-profiling: this stops the periodic timer signal, while\n");
3498 EMIT(" we are no longer updating the current instruction field within the\n");
3499 EMIT(" special-purpose struct in the Array. */\n");
3500 EMIT(" vmprefix_profile_sample_stop ();\n");
3501 EMIT("#endif // #if defined (JITTER_PROFILE_SAMPLE)\n");
3502 EMIT("\n");
3503
3504 /* Emit the patch-in footer. This must come after every patch-in or defect
3505 use. */
3506 jitterc_emit_patch_in_footer (f, vm);
3507
3508 /* Insert C code from the user. This is supposed to come in right after
3509 execution ends. */
3510 EMIT(" /* Finalization C code from the user */\n");
3511 EMIT("%s", vm->finalization_c_code);
3512 EMIT(" /* End of the finalization C code from the user */\n\n");
3513 EMIT("\n");
3514
3515 /* Insert architecture-specific execution-end code. */
3516 EMIT(" /* Execute architecture-specific execution-end code, if any. Make \n");
3517 EMIT(" sure it is safe to expand the macro without do..while (false). */\n");
3518 EMIT(" {}; JITTER_EXECUTION_END_; {};\n");
3519 EMIT("\n");
3520
3521 EMIT(" /* This program point is reachable for both thread initialization and\n");
3522 EMIT(" execution. In either case it is not performance-critical. */\n");
3523 EMIT(" jitter_possibly_restore_registers_and_return_label: __attribute__ ((cold));\n");
3524 EMIT(" //if (jitter_initialize) puts (\"-- RETURNING FROM INITIALIZATION\\n\");\n");
3525 EMIT("#ifdef JITTER_DISPATCH_NO_THREADING\n");
3526 EMIT(" /* Back to regular C without our reserved registers: restore the\n");
3527 EMIT(" values held in such registers at entry. */\n");
3528 EMIT(" vmprefix_restore_registers (jitter_register_buffer);\n");
3529 EMIT("#endif // #ifdef JITTER_DISPATCH_NO_THREADING\n");
3530
3531 // FIXME: this is a test, for profiling: begin
3532 EMIT("#ifdef JITTER_PROFILE\n");
3533 EMIT("#define PROFILING_SPACE (1024 * 1024 * 100)\n");
3534 EMIT(" if (jitter_initialize)\n");
3535 EMIT(" fprintf (stderr, \"Profiling space: [%%p, %%p)\\n\", && vmprefix_profiling_space, ((char *) (&& vmprefix_profiling_space)) + PROFILING_SPACE);\n");
3536 EMIT(" /* Do an indirect jump to the return statement rather than a simple\n");
3537 EMIT(" conditional. With this trick I can afford even a very large gap\n");
3538 EMIT(" within the code for a single C function, without being constrained\n");
3539 EMIT(" by branch offset limits on any architecture. */\n");
3540 EMIT(" void *return_address_variable = && return_label;\n");
3541 EMIT(" JITTER_MARK_LVALUE_AS_SET_BY_ASSEMBLY (return_address_variable);\n");
3542 EMIT(" goto *return_address_variable;\n");
3543 EMIT(" vmprefix_profiling_space: __attribute__ ((unused)) // FIXME: do this from assembly\n");
3544 EMIT(" asm volatile (\".fill (\" JITTER_STRINGIFY(PROFILING_SPACE) \")\");\n");
3545 EMIT(" return_label:\n");
3546 EMIT("#endif // #ifdef JITTER_PROFILE\n");
3547 EMIT(" return;\n");
3548 // FIXME: this is a test, for profiling: end
3549 EMIT("}\n");
3550 EMIT("\n");
3551 }
3552
3553 /* FIXME: move to a template. This might need a forward declarartion for the
3554 main execute-or-initialize function, currently relying on complicated
3555 function attributes; but that will be simplified. */
3556 void
jitterc_emit_executor_wrappers(FILE * f,const struct jitterc_vm * vm)3557 jitterc_emit_executor_wrappers
3558 (FILE *f, const struct jitterc_vm *vm)
3559 {
3560 /* This function is the most critical to compile with the right GCC options;
3561 for any threading model more sophisticated than direct threading this is a
3562 matter of correctness, not just efficiency. */
3563 EMIT("/* The definition of this is machine-generated in vmprefix-vm2.c , and the\n");
3564 EMIT(" function is not intended for the user. If initializing then set\n");
3565 EMIT(" structuredvm_threads and structuredvm_thread_sizes and just return, ignoring\n");
3566 EMIT(" the other fieldsp and s. If not initializing then actually enter VM code\n");
3567 EMIT(" starting from the given program point in the pointed state. */\n");
3568 EMIT("static void\n");
3569 EMIT("vmprefix_execute_or_initialize (bool jitter_initialize,\n");
3570 EMIT(" vmprefix_program_point jitter_initial_program_point,\n");
3571 EMIT(" struct vmprefix_state * const jitter_original_state)\n");
3572 EMIT(" __attribute__ ((noclone, noinline));\n");
3573 EMIT("\n");
3574 EMIT("void\n");
3575 EMIT("vmprefix_execute_executable_routine (const struct jitter_executable_routine *er,\n");
3576 EMIT(" struct vmprefix_state *s)\n");
3577 EMIT("{\n");
3578 EMIT(" vmprefix_make_place_for_slow_registers (s, er->slow_register_per_class_no);\n");
3579 EMIT(" jitter_program_point initial_program_point\n");
3580 EMIT(" = VMPREFIX_EXECUTABLE_ROUTINE_BEGINNING (er);\n");
3581 EMIT(" vmprefix_execute_or_initialize (false, initial_program_point, s);\n");
3582 EMIT("}\n");
3583 EMIT("\n");
3584 EMIT("\n");
3585 EMIT("/* Threads or pointers to native code blocks of course don't exist with\n");
3586 EMIT(" switch-dispatching. */\n");
3587 EMIT("#ifndef JITTER_DISPATCH_SWITCH\n");
3588 EMIT("const jitter_thread *\n");
3589 EMIT("vmprefix_threads;\n");
3590 EMIT("\n");
3591 EMIT("const jitter_thread *\n");
3592 EMIT("vmprefix_thread_ends;\n");
3593 EMIT("\n");
3594 EMIT("const long *\n");
3595 EMIT("vmprefix_thread_sizes;\n");
3596 EMIT("#endif // #ifndef JITTER_DISPATCH_SWITCH\n");
3597 EMIT("\n");
3598
3599 EMIT("void\n");
3600 EMIT("vmprefix_initialize_threads (void)\n");
3601 EMIT("{\n");
3602 EMIT(" vmprefix_execute_or_initialize (true, NULL, NULL);\n");
3603 EMIT("}\n");
3604 EMIT("\n");
3605
3606 EMIT("void\n");
3607 EMIT("vmprefix_branch_to_program_point (vmprefix_program_point p, struct vmprefix_state *s)\n");
3608 EMIT("{\n");
3609 EMIT(" vmprefix_execute_or_initialize (false, p, s);\n");
3610 EMIT("}\n");
3611 EMIT("\n");
3612 }
3613
3614 /* Emit definitions for JITTER_VM_PREFIX_LOWER_CASE and
3615 JITTER_VM_PREFIX_UPPER_CASE . These should not go to public headers, but
3616 they are convenient to have in more than one generated C file. */
3617 static void
jitterc_emit_vm_name_macros(const struct jitterc_vm * vm,const char * basename)3618 jitterc_emit_vm_name_macros (const struct jitterc_vm *vm, const char *basename)
3619 {
3620 FILE *f = jitterc_fopen_a_basename (vm, basename);
3621 /* Generate private macro definitions in the JITTER_ namespace, not exported
3622 to the user via headers. These are useful to compose VM-specific
3623 identifiers via CPP token concatenation, in a way which is unobstrusive to
3624 the user. */
3625 EMIT("/* These two macros are convenient for making VM-specific identifiers\n");
3626 EMIT(" using VM-independent macros from a public header, without polluting\n");
3627 EMIT(" the global namespace. */\n");
3628 EMIT("#define JITTER_VM_PREFIX_LOWER_CASE %s\n", vm->lower_case_prefix);
3629 EMIT("#define JITTER_VM_PREFIX_UPPER_CASE %s\n", vm->upper_case_prefix);
3630 EMIT("\n");
3631 jitterc_fclose (f);
3632 }
3633
3634 /* Do the job of jitterc_emit_vm_name_macros for the two generated .c files */
3635 static void
jitterc_emit_vm_name_macros_vm1(const struct jitterc_vm * vm)3636 jitterc_emit_vm_name_macros_vm1 (const struct jitterc_vm *vm)
3637 {
3638 jitterc_emit_vm_name_macros (vm, "vm1.c");
3639 }
3640 static void
jitterc_emit_vm_name_macros_vm2(const struct jitterc_vm * vm)3641 jitterc_emit_vm_name_macros_vm2 (const struct jitterc_vm *vm)
3642 {
3643 jitterc_emit_vm_name_macros (vm, "vm2.c");
3644 }
3645
3646 static void
jitterc_emit_executor_general_purpose_state_data_access_macros(FILE * f,const struct jitterc_vm * vm)3647 jitterc_emit_executor_general_purpose_state_data_access_macros
3648 (FILE *f, const struct jitterc_vm *vm)
3649 {
3650 EMIT("/* Most of the needed macros are in jitter-executor.h . This however\n");
3651 EMIT(" needs to be here, as it relies on a prefix to be substituted. */\n");
3652 EMIT("#define JITTER_STATE_BACKING \\\n");
3653 EMIT(" (jitter_original_state->vmprefix_state_backing)\n");
3654 }
3655
3656 /* Emit access macros for special-purpose data, to be used from VM code. */
3657 static void
jitterc_emit_executor_special_purpose_state_data_access_macros(FILE * f,const struct jitterc_vm * vm)3658 jitterc_emit_executor_special_purpose_state_data_access_macros
3659 (FILE *f, const struct jitterc_vm *vm)
3660 {
3661 EMIT("/* Expand to an l-value evaluating to the pending_notification field for\n");
3662 EMIT(" the current state. */\n");
3663 EMIT("#define JITTER_PENDING_NOTIFICATIONS \\\n");
3664 EMIT(" (VMPREFIX_OWN_SPECIAL_PURPOSE_STATE_DATA->pending_notifications)\n");
3665 EMIT("/* Expand to an l-value evaluating to the pending field of the struct\n");
3666 EMIT(" jitter_signal_notification element for the given signal, for the\n");
3667 EMIT(" current state. */\n");
3668 EMIT("#define JITTER_PENDING_SIGNAL_NOTIFICATION(signal_id) \\\n");
3669 EMIT(" ((VMPREFIX_OWN_SPECIAL_PURPOSE_STATE_DATA->pending_signal_notifications + (signal_id))->pending)\n");
3670 EMIT("\n");
3671 }
3672
3673 static void
jitterc_emit_executor(const struct jitterc_vm * vm)3674 jitterc_emit_executor (const struct jitterc_vm *vm)
3675 {
3676 FILE *f = jitterc_fopen_a_and_remember_basename (vm, "vm2.c");
3677 EMIT("//#include <config.h>\n\n");
3678
3679 EMIT("#include <stdbool.h>\n");
3680 EMIT("#include <stdio.h>\n");
3681 EMIT("#include <stdlib.h>\n\n");
3682
3683 /* Insert C code from the user. This is supposed to come in very early,
3684 before most includes. */
3685 EMIT("/* Early C code from the user. */\n");
3686 EMIT("%s", vm->early_c_code);
3687 EMIT("/* End of the early C code from the user. */\n\n");
3688
3689 EMIT("#include <jitter/jitter.h>\n");
3690 EMIT("#include <jitter/jitter-instruction.h>\n\n");
3691 EMIT("#define JITTER_THIS_CAN_INCLUDE_JITTER_EXECUTOR_H\n");
3692 EMIT("#include <jitter/jitter-executor.h>\n\n");
3693
3694 EMIT("#ifdef JITTER_ENABLE_ASSEMBLY\n");
3695 EMIT("#include <jitter/jitter-machine-common.h>\n");
3696 EMIT("#include <jitter/machine/jitter-machine.h>\n");
3697 EMIT("#endif // #ifdef JITTER_ENABLE_ASSEMBLY\n");
3698
3699 EMIT("#include <jitter/jitter-fatal.h>\n");
3700 EMIT("#include <jitter/jitter-malloc.h>\n\n");
3701
3702 EMIT("#include \"vmprefix-vm.h\"\n");
3703 EMIT("//#include \"vmprefix-meta-instructions.h\"\n");
3704 EMIT("//#include \"vmprefix-specialized-instructions.h\"\n");
3705 EMIT("//#include \"vmprefix-state.h\"\n\n");
3706
3707 EMIT("/* Include stack data structure support. */\n");
3708 EMIT("#include <jitter/jitter-stack.h>\n\n");
3709
3710 EMIT("/* Include patch-in definitions, only if patch-in is enabled. We knoe whether it is\n");
3711 EMIT(" by checking JITTER_HAVE_PATCH_IN , defined in jitter/jitter-patch-in.h . */\n");
3712 EMIT("#include <jitter/jitter-patch-in.h>\n");
3713 EMIT("#ifdef JITTER_HAVE_PATCH_IN\n");
3714 EMIT("# include <jitter/jitter-fast-branch.h>\n");
3715 EMIT("\n");
3716 EMIT(" JITTER_DEFECT_DESCRIPTOR_DECLARATIONS_(vmprefix);\n");
3717 EMIT(" JITTER_PATCH_IN_DESCRIPTOR_DECLARATIONS_(vmprefix);\n");
3718 EMIT("#endif // #ifdef JITTER_HAVE_PATCH_IN\n\n");
3719
3720 EMIT("/* Always include fast-branch definitions, which use patch-ins where possible\n");
3721 EMIT(" or consist in fallback definitions otherwise. */\n");
3722 EMIT("#include <jitter/jitter-fast-branch.h>\n\n");
3723 EMIT("#define JITTER_FAST_BRANCH_PREFIX vmprefix_\n\n");
3724
3725 /* Emit macros to access general-purpose state data. */
3726 jitterc_emit_executor_general_purpose_state_data_access_macros (f, vm);
3727
3728 /* Emit macros to access special-purpose state data. */
3729 jitterc_emit_executor_special_purpose_state_data_access_macros (f, vm);
3730
3731 /* Emit register-access macros. */
3732 jitterc_emit_executor_register_access_macros (f, vm);
3733
3734 /* Emit global register code. */
3735 jitterc_emit_executor_reserve_registers (f, vm);
3736
3737 /* Emit CPP definitions for stack operations. */
3738 jitterc_emit_stack_operation_definitions (f, vm);
3739
3740 /* Insert C code from the user. This is supposed to come in late, after CPP
3741 includes and definitions, right before the executor functions. */
3742 EMIT("/* Late C code from the user. */\n");
3743 EMIT("%s", vm->before_main_c_code);
3744 EMIT("/* End of the late C code from the user. */\n\n");
3745
3746 /* Generate a few easy wrapper functions calling vmprefix_execute_or_initialize ,
3747 which are the actual entry points into this compilation unit. */
3748 jitterc_emit_executor_wrappers (f, vm);
3749
3750 /* Emit the main executor/initialization function. */
3751 jitterc_emit_executor_main_function (f, vm);
3752
3753 jitterc_fclose (f);
3754 }
3755
3756
3757
3758
3759 /* File copying utility.
3760 * ************************************************************************** */
3761
3762 static void
jitterc_copy_file_to_tmp(struct jitterc_vm * vm,const char * to_basename,const char * from_pathname)3763 jitterc_copy_file_to_tmp (struct jitterc_vm *vm,
3764 const char *to_basename,
3765 const char *from_pathname)
3766 {
3767 FILE *to_stream = jitterc_fopen_a_and_remember_basename (vm, to_basename);
3768 FILE *from_stream = jitterc_fopen_r_pathname (from_pathname);
3769 while (! feof (from_stream))
3770 {
3771 int c = fgetc (from_stream);
3772 if (c == EOF)
3773 break;
3774 EMIT_TO(to_stream, "%c", c);
3775 }
3776 jitterc_fclose (to_stream);
3777 jitterc_fclose (from_stream);
3778 }
3779
3780 static void
jitterc_copy_template_to_tmp(struct jitterc_vm * vm,const char * basename)3781 jitterc_copy_template_to_tmp (struct jitterc_vm *vm,
3782 const char *basename)
3783 {
3784 size_t basename_size
3785 = strlen (vm->template_directory) + 1 + strlen (basename) + 1;
3786 char *from_pathname = xmalloc (basename_size);
3787 sprintf (from_pathname, "%s/%s", vm->template_directory, basename);
3788
3789 jitterc_copy_file_to_tmp (vm, basename, from_pathname);
3790 free (from_pathname);
3791 }
3792
3793 static void
jitterc_copy_templates_to_tmp(struct jitterc_vm * vm,bool generate_frontend)3794 jitterc_copy_templates_to_tmp (struct jitterc_vm *vm,
3795 bool generate_frontend)
3796 {
3797 jitterc_copy_template_to_tmp (vm, "vm1.c");
3798 jitterc_copy_template_to_tmp (vm, "vm.h");
3799 if (generate_frontend)
3800 jitterc_copy_template_to_tmp (vm, "vm-main.c");
3801 }
3802
3803
3804
3805
3806 /* Template and temporary file handling.
3807 * ************************************************************************** */
3808
3809 /* Copy files from the temporary directory to the actual output directory,
3810 replacing prefixes. */
3811
3812 /* Return a malloc-allocated string holding the full content of the named
3813 text file, failing fatally on any error. */
3814 static char *
jitterc_file_content(const char * pathname)3815 jitterc_file_content (const char *pathname)
3816 {
3817 /* Read the whole input into core. */
3818 FILE *from_stream = jitterc_fopen_r_pathname (pathname);
3819 size_t allocated_length = 15;
3820 char *buffer = xmalloc (allocated_length + 1);
3821 size_t used_size = 0;
3822 while (! feof (from_stream))
3823 {
3824 int c = fgetc (from_stream);
3825 if (c == EOF)
3826 break;
3827
3828 buffer [used_size ++] = c;
3829 if ((used_size + 1) >= allocated_length)
3830 buffer = xrealloc (buffer, allocated_length *= 2);
3831 }
3832 assert (used_size < allocated_length);
3833 buffer [used_size] = '\0';
3834 jitterc_fclose (from_stream);
3835
3836 /* Return the buffer, trimmed so as not to waste memory. */
3837 return xrealloc (buffer, strlen (buffer) + 1);
3838 }
3839
3840 /* Replace every occurrence of from_string with to_string within in_string,
3841 which must be malloc-allocated. Free in_string and return a new copy of it,
3842 allocated with malloc, with the substitution performed.
3843 Doing this in core sounds inefficient in terms of memory use, but I don't
3844 feel like implementing Knuth-Morris-Pratt from scratch when in practice we
3845 will always work with files of modest size. */
3846 __attribute__ ((warn_unused_result, nonnull (1, 2, 3)))
3847 static char*
jitterc_filter_and_realloc_string(char * in_string,const char * to_string,const char * from_string)3848 jitterc_filter_and_realloc_string (char *in_string,
3849 const char *to_string,
3850 const char *from_string)
3851 {
3852 /* It's not clear what the right thing to do would be if from_string were an
3853 empty string; it's probably a useless case to support anyway. Instead
3854 to_string and in_string are allowed to be empty. */
3855 size_t from_string_length = strlen (from_string);
3856 assert (from_string_length > 0);
3857 size_t to_string_length = strlen (to_string);
3858 size_t in_string_length = strlen (in_string);
3859
3860 /* Compute a safe upper bound on the result size, and allocate a sufficiently
3861 large buffer. */
3862 size_t greater_length = (from_string_length > to_string_length)
3863 ? from_string_length
3864 : to_string_length;
3865 size_t out_string_size
3866 = (size_t)
3867 (in_string_length * ((double) greater_length) / from_string_length)
3868 /* Add one unit in case we round up, plus another for the final '\0'. */
3869 + 1 + 1;
3870 char *out_string = xmalloc (out_string_size);
3871
3872 /* Copy the input buffer text to the output stream, with replacements. */
3873 char *in_pointer = in_string, *out_pointer = out_string;
3874 char *next_occurrence;
3875 /* As long as we can find an occurrence of from_string ... */
3876 while ((next_occurrence = strstr (in_pointer, from_string)) != NULL)
3877 {
3878 /* We found an occurrence. Copy the part of the text we haven't copied
3879 yet. */
3880 size_t literally_copied_length = next_occurrence - in_pointer;
3881 memcpy (out_pointer, in_pointer, literally_copied_length);
3882
3883 /* We stopped right before the occurrence of from_string in the input
3884 text. But of course instead of writing from_string now we need to
3885 write its replacement. */
3886 memcpy (out_pointer + literally_copied_length, to_string,
3887 to_string_length);
3888
3889 /* The next point to search in the input starts right after the end of
3890 from_string in the input buffer. Advance to_pointer as well by
3891 skipping the length of to_string . */
3892 in_pointer = next_occurrence + from_string_length;
3893 out_pointer += literally_copied_length + to_string_length;
3894 }
3895 /* Copy the input text after the last occurrence until the end, including the
3896 final '\0'. */
3897 strcpy (out_pointer, in_pointer);
3898
3899 /* Free the input string and return the output string we filled, trimmed so as
3900 not to waste memory. */
3901 free (in_string);
3902 return xrealloc (out_string, strlen (out_string) + 1);
3903 }
3904
3905
3906
3907
3908 /* Template and temporary file moving.
3909 * ************************************************************************** */
3910
3911 /* Move a single file from the given path to the given path, replacing the VM
3912 prefix in the content. */
3913 static void
jitterc_fix_and_move(const struct jitterc_vm * vm,const char * to_pathname,const char * from_pathname)3914 jitterc_fix_and_move (const struct jitterc_vm *vm,
3915 const char *to_pathname,
3916 const char *from_pathname)
3917 {
3918 /* Read the input file to core. */
3919 char *content = jitterc_file_content (from_pathname);
3920
3921 /* Perform the replacements. */
3922 content
3923 = jitterc_filter_and_realloc_string (content,
3924 vm->lower_case_prefix,
3925 INPUT_LOWER_CASE_PREFIX);
3926 content
3927 = jitterc_filter_and_realloc_string (content,
3928 vm->upper_case_prefix,
3929 INPUT_UPPER_CASE_PREFIX);
3930
3931 /* Write the modified text to the output file, and free it. */
3932 FILE *to_stream = jitterc_fopen_w_pathname (to_pathname);
3933 EMIT_TO(to_stream, "%s", content);
3934 jitterc_fclose (to_stream);
3935 free (content);
3936
3937 /* Remove the original file, which is supposed to be in the temporary
3938 directory if this function is called as intended. Errors are not fatal
3939 here. FIXME: warn? */
3940 unlink (from_pathname);
3941 }
3942
3943 /* Move generated files from the temporary directory to the final directory,
3944 replacing the prefix in the content and prepending the prefix to
3945 basenames. */
3946 static void
jitterc_fix_and_move_files_from_tmp(const struct jitterc_vm * vm)3947 jitterc_fix_and_move_files_from_tmp (const struct jitterc_vm *vm)
3948 {
3949 int i; char *comma __attribute__ ((unused));
3950 size_t to_directory_length = strlen (vm->directory);
3951 size_t tmp_directory_length = strlen (vm->tmp_directory);
3952 size_t prefix_length = strlen (vm->lower_case_prefix);
3953 FOR_LIST(i, comma, vm->written_file_names)
3954 {
3955 const char *basename = gl_list_get_at (vm->written_file_names, i);
3956 size_t tmp_pathname_length
3957 = tmp_directory_length + 1 + strlen (basename) + 1;
3958 char *tmp_pathname = xmalloc (tmp_pathname_length);
3959 sprintf (tmp_pathname, "%s/%s", vm->tmp_directory, basename);
3960 size_t to_pathname_length
3961 = to_directory_length + 1 + prefix_length + 1 + strlen (basename) + 1;
3962 char *to_pathname = xmalloc (to_pathname_length);
3963 sprintf (to_pathname, "%s/%s-%s",
3964 vm->directory, vm->lower_case_prefix, basename);
3965 jitterc_fix_and_move (vm, to_pathname, tmp_pathname);
3966 free (tmp_pathname);
3967 free (to_pathname);
3968 }
3969
3970 /* Remove the temporary directory. It makes no sense to fail fatally in this
3971 case, since the result is usable. FIXME: warn? */
3972 rmdir (vm->tmp_directory);
3973 }
3974
3975
3976
3977 /* Entry point.
3978 * ************************************************************************** */
3979
3980 void
jitterc_generate(struct jitterc_vm * vm,bool generate_frontend,const char * template_directory,const char * output_directory)3981 jitterc_generate (struct jitterc_vm *vm,
3982 bool generate_frontend,
3983 const char *template_directory,
3984 const char *output_directory)
3985 {
3986 assert (vm->template_directory == NULL);
3987 assert (vm->directory == NULL);
3988 assert (vm->tmp_directory == NULL);
3989
3990 /* Set directories in the VM data structure. Make output directories if needed. */
3991 vm->template_directory = jitter_clone_string (template_directory);
3992 vm->directory = jitter_clone_string (output_directory);
3993 jitterc_mkdir (vm->directory);
3994 char *tmp = getenv ("TMPDIR");
3995 if (tmp == NULL)
3996 tmp = "/tmp";
3997 char *tmp_directory_basename = "jitterc-XXXXXX";
3998 vm->tmp_directory
3999 = xmalloc (strlen (tmp) + 1 + strlen (tmp_directory_basename) + 1);
4000 sprintf (vm->tmp_directory, "%s/%s", tmp, tmp_directory_basename);
4001 if (mkdtemp (vm->tmp_directory) == NULL)
4002 jitter_fatal ("could not make the temporary directory %s",
4003 vm->tmp_directory);
4004
4005 /* Emit the code part coming *before* templates. */
4006 const char *initial_comment
4007 = "/* This code is machine-generated. See its source for license\n"
4008 " information. This software is derived from software\n"
4009 " distributed under the GNU GPL version 3 or later. */\n\n";
4010 jitterc_emit_text_to_stream (vm, "vm.h", initial_comment);
4011 jitterc_emit_initial_header_c (vm);
4012 jitterc_emit_text_to_stream (vm, "vm1.c", initial_comment);
4013 jitterc_emit_initial_vm1_c (vm);
4014 jitterc_emit_text_to_stream (vm, "vm2.c", initial_comment);
4015 jitterc_emit_initial_vm2_c (vm);
4016 if (generate_frontend)
4017 {
4018 /* Nothing is really customizable in vm-main.c ; but I can emit user code,
4019 and only that, if vm-main.c is actually used. */
4020 jitterc_emit_text_to_stream (vm, "vm-main.c", initial_comment);
4021 jitterc_emit_initial_vm_main_c (vm);
4022 }
4023
4024 /* Copy all the templates to the temporary directory. */
4025 jitterc_copy_templates_to_tmp (vm, generate_frontend);
4026
4027 /* Append machine-generated code to the copied templates in the temporary
4028 directory, and generate a separate file for the heavyweight part. Perform
4029 no prefix-replacement yet. */
4030 jitterc_emit_early_header_c (vm);
4031 jitterc_emit_configuration_macros (vm);
4032 jitterc_emit_register_classes_h (vm);
4033 jitterc_emit_state_h (vm);
4034 jitterc_emit_meta_instructions_h (vm);
4035 jitterc_emit_specialized_instructions_h (vm);
4036 jitterc_emit_register_access_macros_h (vm);
4037 jitterc_emit_late_header_c (vm);
4038 jitterc_emit_header_closing (vm);
4039
4040 /* From this point on the generated code goes to vm1.c . */
4041 jitterc_emit_vm_name_macros_vm1 (vm);
4042 jitterc_emit_printer_c (vm);
4043 jitterc_emit_meta_instructions (vm);
4044 jitterc_emit_register_classes (vm);
4045 jitterc_emit_specialized_instruction_names (vm);
4046 jitterc_emit_specialized_instruction_residual_arities (vm);
4047 jitterc_emit_specialized_instruction_label_bitmasks (vm);
4048 jitterc_emit_specialized_instruction_fast_label_bitmasks (vm);
4049 jitterc_emit_specialized_instruction_relocatables (vm);
4050 jitterc_emit_specialized_instruction_callers (vm);
4051 jitterc_emit_specialized_instruction_callees (vm);
4052 jitterc_emit_specialized_instruction_to_unspecialized_instruction (vm);
4053 jitterc_emit_worst_case_defect_table (vm);
4054 jitterc_emit_rewriter (vm);
4055 jitterc_emit_specializer (vm);
4056 jitterc_emit_state (vm);
4057
4058 /* From this point on the generated code goes to vm2.c . */
4059 jitterc_emit_vm_name_macros_vm2 (vm);
4060 jitterc_emit_executor (vm);
4061
4062 /* Move files from the temporary directory to their actual destination,
4063 replacing prefixes in the content and also prepending the prefix to
4064 the final basenames. */
4065 jitterc_fix_and_move_files_from_tmp (vm);
4066 }
4067
4068
4069 /* This Emacs Lisp function is convenient for turning hand-written C code into
4070 code for generating it. It's not necessarily intended for the user, but
4071 comes in handy for editing this file.
4072
4073 (defun replace-region-with-emits (beginning end)
4074 (interactive "r")
4075 (save-mark-and-excursion
4076 (save-restriction
4077 (narrow-to-region beginning end)
4078 (let ((pairs '(("\\\\" . "\\\\\\\\")
4079 ("%" . "%%")
4080 ("\"" . "\\\\\"")
4081 ("^" . "EMIT(\"")
4082 ("$" . "\\\\n\");")))
4083 (case-replace t)
4084 (case-fold-search t)
4085 (fill-prefix nil)
4086 (indent-region-function nil))
4087 (dolist (pair pairs)
4088 (goto-char (point-min))
4089 (replace-regexp (car pair) (cdr pair)))))))
4090 */
4091
4092 /* FIXME: what about this hack?
4093 #define STRING(...) #__VA_ARGS__
4094
4095 It works fine, but the C++ (and, I guess C as well) standard only requires
4096 compilers to accept a limited-length logical line. This limit is 65536
4097 characters, which should be enough if long literal code is split across
4098 different macro calls once in a while. Anyway, this is dumb. I'm sure
4099 GCC, and any other well-designed compiler, has no such artificial limit. */
4100