1 /* Jitter: VM-independent mutable routine data structures.
2
3 Copyright (C) 2016, 2017, 2018, 2019, 2020 Luca Saiu
4 Updated in 2021 by Luca Saiu
5 Written by Luca Saiu
6
7 This file is part of Jitter.
8
9 Jitter is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 Jitter is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with Jitter. If not, see <http://www.gnu.org/licenses/>. */
21
22
23 #include <stdio.h>
24 #include <stdbool.h>
25 #include <string.h>
26
27 #include <jitter/jitter.h>
28 #include <jitter/jitter-mmap.h>
29 #include <jitter/jitter-mutable-routine.h>
30 #include <jitter/jitter-vm.h>
31 #include <jitter/jitter-rewrite.h>
32 #include <jitter/jitter-specialize.h>
33
34 #include <jitter/jitter-hash.h>
35 #include <jitter/jitter-malloc.h>
36 #include <jitter/jitter-fatal.h>
37
38
39 /* Routine options.
40 * ************************************************************************** */
41
42 /* Set the pointed mutable-routine-option struct to the default state. */
43 static void
jitter_initialize_options(struct jitter_mutable_routine_options * op)44 jitter_initialize_options (struct jitter_mutable_routine_options *op)
45 {
46 op->can_change = true;
47 op->slow_registers_only = false;
48 op->slow_literals_only = false;
49 op->add_final_exitvm = true;
50 op->optimization_rewriting = true;
51 }
52
53 /* Change the options in the given routine to make options unchangeable from now
54 on. This is harmless to call even if the options are already unchangeable.
55 In practice this is called when appending labels and meta-instructions; it is
56 not necessary to call when appending instruction parameters, as those always
57 follow meta-instructions. Based on the same reasoning, rewriting rules
58 always follow instruction appending, so the low-level API only used for
59 rewriting does not need to use this. */
60 static void
jitter_routine_make_options_unchangeable(struct jitter_mutable_routine * p)61 jitter_routine_make_options_unchangeable (struct jitter_mutable_routine *p)
62 {
63 p->options.can_change = false;
64 }
65
66 /* Fail fatally if the options in the pointed routine are no changeable. */
67 static void
jitter_fail_unless_options_changeable(struct jitter_mutable_routine * p)68 jitter_fail_unless_options_changeable (struct jitter_mutable_routine *p)
69 {
70 if (! p->options.can_change)
71 jitter_fatal ("cannot change options in non-empty routine");
72 }
73
74 void
jitter_set_mutable_routine_option_slow_registers_only(struct jitter_mutable_routine * p,bool option)75 jitter_set_mutable_routine_option_slow_registers_only
76 (struct jitter_mutable_routine *p, bool option)
77 {
78 jitter_fail_unless_options_changeable (p);
79 p->options.slow_registers_only = option;
80 }
81
82 void
jitter_set_mutable_routine_option_slow_literals_only(struct jitter_mutable_routine * p,bool option)83 jitter_set_mutable_routine_option_slow_literals_only
84 (struct jitter_mutable_routine *p, bool option)
85 {
86 jitter_fail_unless_options_changeable (p);
87 p->options.slow_literals_only = option;
88 }
89
90 void
jitter_set_mutable_routine_option_slow_literals_and_registers_only(struct jitter_mutable_routine * p,bool option)91 jitter_set_mutable_routine_option_slow_literals_and_registers_only
92 (struct jitter_mutable_routine *p, bool option)
93 {
94 jitter_set_mutable_routine_option_slow_registers_only (p, option);
95 jitter_set_mutable_routine_option_slow_literals_only (p, option);
96 }
97
98 void
jitter_set_mutable_routine_option_add_final_exitvm(struct jitter_mutable_routine * p,bool option)99 jitter_set_mutable_routine_option_add_final_exitvm
100 (struct jitter_mutable_routine *p, bool option)
101 {
102 jitter_fail_unless_options_changeable (p);
103 p->options.add_final_exitvm = option;
104 }
105
106 void
jitter_set_mutable_routine_option_optimization_rewriting(struct jitter_mutable_routine * p,bool option)107 jitter_set_mutable_routine_option_optimization_rewriting
108 (struct jitter_mutable_routine *p, bool option)
109 {
110 jitter_fail_unless_options_changeable (p);
111 p->options.optimization_rewriting = option;
112 }
113
114
115
116 /* Initialization and finalization
117 * ************************************************************************** */
118
119 static void
jitter_initialize_routine(struct jitter_mutable_routine * p)120 jitter_initialize_routine (struct jitter_mutable_routine *p)
121 {
122 p->stage = jitter_routine_stage_unspecialized;
123
124 jitter_initialize_options (& p->options);
125 p->expected_parameter_no = 0;
126 p->rewritable_instruction_no = 0;
127 p->current_instruction = NULL;
128 p->next_uninitialized_parameter = NULL; /* An intentionally invalid value. */
129 p->next_expected_parameter_type = NULL; /* An intentionally invalid value. */
130
131 jitter_dynamic_buffer_initialize (& p->instructions);
132 p->next_unused_opaque_label = 0;
133 jitter_hash_initialize (& p->label_name_to_opaque_label);
134 jitter_dynamic_buffer_initialize (& p->opaque_label_to_instruction_index);
135 p->jump_targets = NULL;
136 p->instruction_index_to_specialized_instruction_offset = NULL;
137
138 jitter_dynamic_buffer_initialize (& p->specialized_program);
139 jitter_dynamic_buffer_initialize (& p->replicated_blocks);
140 p->native_code = NULL;
141 jitter_dynamic_buffer_initialize (& p->specialized_label_indices);
142
143 /* No slow registers have been seen yet. */
144 p->slow_register_per_class_no = 0;
145
146 /* No executable routine exists yet for this routine. */
147 p->executable_routine = NULL;
148 }
149
150 static void
jitter_finalize_routine(struct jitter_mutable_routine * p)151 jitter_finalize_routine (struct jitter_mutable_routine *p)
152 {
153 struct jitter_dynamic_buffer * const is = & p->instructions;
154 while (jitter_dynamic_buffer_size (is) != 0)
155 {
156 struct jitter_instruction *i
157 = * (struct jitter_instruction **)
158 jitter_dynamic_buffer_pop (is, sizeof (struct jitter_instruction*));
159 jitter_destroy_instruction (i);
160 }
161 jitter_dynamic_buffer_finalize (is);
162
163 jitter_string_hash_finalize (& p->label_name_to_opaque_label, NULL);
164 jitter_dynamic_buffer_finalize (& p->opaque_label_to_instruction_index);
165
166 if (p->jump_targets != NULL)
167 free (p->jump_targets);
168 if (p->instruction_index_to_specialized_instruction_offset != NULL)
169 free (p->instruction_index_to_specialized_instruction_offset);
170
171 /* The specialized_program field may have been extracted, if this routine has
172 been made executable; in any case, this finalization will be valid. */
173 jitter_dynamic_buffer_finalize (& p->specialized_program);
174
175 jitter_dynamic_buffer_finalize (& p->replicated_blocks);
176
177 #ifdef JITTER_REPLICATE
178 /* The native_code field may be NULL because native code has never been
179 generated, but also if the routine was made executable. In either case the
180 pointer field here will be NULL, so that we don't deallocate twice. */
181 if (p->native_code != NULL)
182 jitter_executable_deallocate (p->native_code);
183 #endif // #ifdef JITTER_REPLICATE
184 jitter_dynamic_buffer_finalize (& p->specialized_label_indices);
185 }
186
187 struct jitter_mutable_routine*
jitter_make_mutable_routine(const struct jitter_vm * vm)188 jitter_make_mutable_routine (const struct jitter_vm *vm)
189 {
190 struct jitter_mutable_routine *res = jitter_xmalloc (sizeof (struct jitter_mutable_routine));
191 jitter_initialize_routine (res);
192 res->vm = vm;
193 return res;
194 }
195
196 void
jitter_destroy_mutable_routine(struct jitter_mutable_routine * p)197 jitter_destroy_mutable_routine (struct jitter_mutable_routine *p)
198 {
199 /* Unlink the executable routine, if any. */
200 if (p->executable_routine != NULL)
201 p->executable_routine->routine = NULL;
202
203 if (p == NULL)
204 return;
205
206 jitter_finalize_routine (p);
207 free (p);
208 }
209
210 size_t
jitter_mutable_routine_instruction_no(const struct jitter_mutable_routine * p)211 jitter_mutable_routine_instruction_no (const struct jitter_mutable_routine *p)
212 {
213 return jitter_dynamic_buffer_size (& p->instructions)
214 / sizeof (struct jitter_instruction*);
215 }
216
217
218
219
220 /* Label handing.
221 * ************************************************************************** */
222
223 jitter_label
jitter_fresh_label(struct jitter_mutable_routine * p)224 jitter_fresh_label (struct jitter_mutable_routine *p)
225 {
226 /* Allocate an identifier. */
227 jitter_label res = p->next_unused_opaque_label ++;
228
229 /* Associate the label to an invalid instruction index. */
230 jitter_int invalid_instruction_index = -1;
231 jitter_dynamic_buffer_push (& p->opaque_label_to_instruction_index,
232 & invalid_instruction_index,
233 sizeof (invalid_instruction_index));
234
235 /* Return the identifier. */
236 return res;
237 }
238
239 jitter_label
jitter_symbolic_label(struct jitter_mutable_routine * p,const char * symbolic_name)240 jitter_symbolic_label (struct jitter_mutable_routine *p, const char *symbolic_name)
241 {
242 /* If the name is already known, return its label. */
243 if (jitter_string_hash_table_has (& p->label_name_to_opaque_label,
244 symbolic_name))
245 return jitter_string_hash_table_get (& p->label_name_to_opaque_label,
246 symbolic_name).fixnum;
247
248 /* The name is new. Allocate a new label, bind it to a copy of the name
249 (copies are handled by the hash table routines), and return the label. */
250 jitter_label res = jitter_fresh_label (p);
251 union jitter_word datum = {.fixnum = res};
252 jitter_string_hash_table_add (& p->label_name_to_opaque_label,
253 symbolic_name,
254 datum);
255 return res;
256 }
257
258 /* Return the unspecialized instruction index for the given label in the pointed
259 routine, or -1 if the label is not associated to any instruction.
260 Unspecified behavior if the label is out of bounds. */
261 static jitter_int
jitter_get_label_instruction_index(struct jitter_mutable_routine * p,jitter_label label)262 jitter_get_label_instruction_index (struct jitter_mutable_routine *p,
263 jitter_label label)
264 {
265 jitter_int *array
266 = jitter_dynamic_buffer_to_pointer (& p->opaque_label_to_instruction_index);
267
268 return array [label];
269 }
270
271 /* Associate the given label in the pointed routine to the given unspecialized
272 instruction index. Fail fatally if the label was already associated to an
273 index. Unspecified behavior if the label is out of bounds. */
274 static void
jitter_set_label_instruction_index(struct jitter_mutable_routine * p,jitter_label label,jitter_int instruction_index)275 jitter_set_label_instruction_index (struct jitter_mutable_routine *p,
276 jitter_label label,
277 jitter_int instruction_index)
278 {
279 jitter_int *array
280 = jitter_dynamic_buffer_to_pointer (& p->opaque_label_to_instruction_index);
281 jitter_int previous_index = array [label];
282 if (previous_index != -1)
283 jitter_fatal ("label %li appended twice", (long) label);
284
285 array [label] = instruction_index;
286 }
287
288
289
290
291 /* Routine construction API.
292 * ************************************************************************** */
293
294 void
jitter_mutable_routine_append_label(struct jitter_mutable_routine * p,jitter_label label)295 jitter_mutable_routine_append_label (struct jitter_mutable_routine *p, jitter_label label)
296 {
297 if (p->stage != jitter_routine_stage_unspecialized)
298 jitter_fatal ("appending label in non non-unspecialized routine");
299 if (p->expected_parameter_no != 0)
300 jitter_fatal ("appending label %li with previous instruction "
301 "incomplete", (long) label);
302 jitter_routine_make_options_unchangeable (p);
303
304 jitter_int instruction_index = jitter_mutable_routine_instruction_no (p);
305 jitter_set_label_instruction_index (p, label, instruction_index);
306
307 /* We added a label. Everything before it can no longer be rewritten. */
308 p->rewritable_instruction_no = 0;
309 }
310
311 jitter_label
jitter_mutable_routine_append_symbolic_label(struct jitter_mutable_routine * p,const char * label_name)312 jitter_mutable_routine_append_symbolic_label (struct jitter_mutable_routine *p, const char *label_name)
313 {
314 jitter_label res = jitter_symbolic_label (p, label_name);
315 jitter_mutable_routine_append_label (p, res);
316 return res;
317 }
318
319 /* Close the current instruction which must have all of its parameters already
320 added (fail fatally otherwise), by calling the rewriter on it. Set pointers
321 about the next parameter in the routine to reflect the fact that its address
322 is not known yet, and a new instruction is expected first. Increment the
323 instruction counter. */
324 static void
jitter_close_current_instruction(struct jitter_mutable_routine * p)325 jitter_close_current_instruction (struct jitter_mutable_routine *p)
326 {
327 if (p->stage != jitter_routine_stage_unspecialized)
328 jitter_fatal ("closing instruction in non-unspecialized routine");
329 if (p->expected_parameter_no != 0)
330 jitter_fatal ("closing an instruction still expecting parameters");
331
332 p->next_uninitialized_parameter = NULL;
333 p->next_expected_parameter_type = NULL;
334
335 /* The instruction we just added is a candidate for rewriting, along with the
336 previous ones which were candidate already. */
337 p->rewritable_instruction_no ++;
338
339 /* Unless optimization rewrites were disabled for this routine, rewrite the
340 last part of the routine, using the instruction we have just closed; that
341 instruction, along with some others preceding it, might very well change or
342 disappear after rewriting is done. */
343 if (p->options.optimization_rewriting)
344 p->vm->rewrite (p);
345 }
346
347 /* Check that the pointed routine's last instruction is incomplete, and that the next
348 parameter it expects is compatible with the given actual type and, in case it's a
349 register, register class. Fail fatally if that's not the case. */
350 static void
jitter_check_paremater_compatibility(struct jitter_mutable_routine * p,enum jitter_parameter_type actual_type,const struct jitter_register_class * register_class)351 jitter_check_paremater_compatibility
352 (struct jitter_mutable_routine *p,
353 enum jitter_parameter_type actual_type,
354 const struct jitter_register_class *register_class)
355 {
356 /* Check that the routine is in the right stage, and that we're
357 actually expecting a parameter. */
358 if (p->stage != jitter_routine_stage_unspecialized)
359 jitter_fatal ("appending parameter in non-unspecialized routine");
360 if (p->expected_parameter_no == 0)
361 jitter_fatal ("appending parameter with previous instruction complete");
362 if (p->next_expected_parameter_type == NULL)
363 jitter_fatal ("impossible if we passed the previous check");
364
365 /* Check that the parameter type is compatible with what we expect. */
366 const struct jitter_meta_instruction_parameter_type * expected_type =
367 p->next_expected_parameter_type;
368 enum jitter_meta_instruction_parameter_kind expected_kind =
369 expected_type->kind;
370 switch (actual_type)
371 {
372 case jitter_parameter_type_register_id:
373 if ( expected_kind
374 != jitter_meta_instruction_parameter_kind_register
375 && expected_kind
376 != jitter_meta_instruction_parameter_kind_register_or_literal_fixnum
377 && expected_kind
378 != jitter_meta_instruction_parameter_kind_register_or_literal_label
379 && expected_kind
380 != jitter_meta_instruction_parameter_kind_register_or_literal_fixnum_or_literal_label)
381 jitter_fatal ("appending register argument not admitted by instruction");
382 if (expected_type->register_class != register_class)
383 jitter_fatal ("invalid register class for register argument");
384 break;
385 case jitter_parameter_type_literal:
386 if ( expected_kind
387 != jitter_meta_instruction_parameter_kind_literal_fixnum
388 && expected_kind
389 != jitter_meta_instruction_parameter_kind_literal_fixnum_or_literal_label
390 && expected_kind
391 != jitter_meta_instruction_parameter_kind_register_or_literal_fixnum
392 && expected_kind
393 != jitter_meta_instruction_parameter_kind_register_or_literal_fixnum_or_literal_label)
394 jitter_fatal ("appending immediate argument not admitted by instruction");
395 break;
396 case jitter_parameter_type_label:
397 if ( expected_kind
398 != jitter_meta_instruction_parameter_kind_literal_label
399 && expected_kind
400 != jitter_meta_instruction_parameter_kind_literal_fixnum_or_literal_label
401 && expected_kind
402 != jitter_meta_instruction_parameter_kind_register_or_literal_label
403 && expected_kind
404 != jitter_meta_instruction_parameter_kind_register_or_literal_fixnum_or_literal_label)
405 jitter_fatal ("appending label argument not admitted by instruction");
406 break;
407 default:
408 jitter_fatal ("jitter_mutable_routine_append_uninitialized_paremater: "
409 "invalid actual argument type %lu",
410 (unsigned long) actual_type);
411 }
412 }
413
414 /* Make the current instruction, which must be incomplete, have the next
415 expected parameter as its own and start a new instruction if that parameter
416 was the last, but *don't* close the old instruction. Don't make checks. */
417 static void
jitter_advance_past_next_parameter(struct jitter_mutable_routine * p)418 jitter_advance_past_next_parameter (struct jitter_mutable_routine *p)
419 {
420 if ((-- p->expected_parameter_no) != 0)
421 {
422 const struct jitter_instruction *in = p->current_instruction;
423 const struct jitter_meta_instruction *min = in->meta_instruction;
424
425 /* There are other parameters expected in the current instruction after
426 the one we have just added. Point to the next one. */
427 p->next_uninitialized_parameter
428 = in->parameters [min->parameter_no - p->expected_parameter_no];
429 p->next_expected_parameter_type ++;
430 }
431 }
432
433 /* Add a parameter of the given parameter type (which is a
434 jitter_parameter_type, therefore an "actual" type and *not* a
435 jitter_meta_instruction_parameter type, expressing the set of "formal"
436 accepted types) to the last instruction of the given unspecialized routine,
437 which must be incomplete. A register class is also given to check that it
438 matches with the expected parameter, in case of a register-type parameter; it
439 is ignored otherwise.
440 Fail fatally if the routine is not unspecialized
441 or its last instruction is complete, or if the kind or register class is
442 wrong. Return a pointer to the parameter data structure, to be filled in by
443 the caller. In any case, do *not* close the instruction, even if the appended
444 parameter was the last; doing that would interfere badly with rewriting, which
445 has to see every parameter correctly initialized.
446 This is used by jitter_mutable_routine_append_literal_parameter ,
447 jitter_mutable_routine_append_register_parameter and
448 jitter_mutable_routine_append_label_parameter . */
449 static struct jitter_parameter *
jitter_mutable_routine_append_uninitialized_paremater(struct jitter_mutable_routine * p,enum jitter_parameter_type actual_type,const struct jitter_register_class * register_class)450 jitter_mutable_routine_append_uninitialized_paremater
451 (struct jitter_mutable_routine *p,
452 enum jitter_parameter_type actual_type,
453 const struct jitter_register_class *register_class)
454 {
455 /* Check that the parameter is compatbile; fail fatally if it isn't. */
456 jitter_check_paremater_compatibility (p, actual_type, register_class);
457
458 /* Keep a pointer to the next uninitialized parameter to be returned; it will
459 no longer be the next at the end of this function. */
460 struct jitter_parameter *res = p->next_uninitialized_parameter;
461
462 /* Advance pointers in the routine past this parameter, starting a new
463 instruction if needed -- but don't close the current instruction: see the
464 comment before this function. */
465 jitter_advance_past_next_parameter (p);
466
467 return res;
468 }
469
470 /* Close the current instruction if the last appended parameter was the last
471 one. See the comment before as to why this is not done there. */
472 static void
jitter_close_instruction_when_no_more_parameters(struct jitter_mutable_routine * p)473 jitter_close_instruction_when_no_more_parameters (struct jitter_mutable_routine *p)
474 {
475 if (p->expected_parameter_no == 0)
476 jitter_close_current_instruction (p);
477 }
478
479 void
jitter_mutable_routine_append_literal_parameter(struct jitter_mutable_routine * p,union jitter_word immediate)480 jitter_mutable_routine_append_literal_parameter (struct jitter_mutable_routine *p,
481 union jitter_word immediate)
482 {
483 struct jitter_parameter * const pa
484 = jitter_mutable_routine_append_uninitialized_paremater (p, jitter_parameter_type_literal,
485 NULL);
486
487 pa->type = jitter_parameter_type_literal;
488 pa->literal = immediate;
489 jitter_close_instruction_when_no_more_parameters (p);
490 }
491
492 /* This is just a convenience wrapper around jitter_mutable_routine_append_literal_parameter
493 . */
494 void
jitter_mutable_routine_append_signed_literal_parameter(struct jitter_mutable_routine * p,jitter_int immediate)495 jitter_mutable_routine_append_signed_literal_parameter (struct jitter_mutable_routine *p,
496 jitter_int immediate)
497 {
498 union jitter_word immediate_union = {.fixnum = immediate};
499 jitter_mutable_routine_append_literal_parameter (p, immediate_union);
500 }
501
502 /* This is just a convenience wrapper around jitter_mutable_routine_append_literal_parameter
503 . */
504 void
jitter_mutable_routine_append_unsigned_literal_parameter(struct jitter_mutable_routine * p,jitter_uint immediate)505 jitter_mutable_routine_append_unsigned_literal_parameter (struct jitter_mutable_routine *p,
506 jitter_uint immediate)
507 {
508 union jitter_word immediate_union = {.ufixnum = immediate};
509 jitter_mutable_routine_append_literal_parameter (p, immediate_union);
510 }
511
512 /* This is just a convenience wrapper around jitter_mutable_routine_append_literal_parameter
513 . */
514 void
jitter_mutable_routine_append_pointer_literal_parameter(struct jitter_mutable_routine * p,void * immediate)515 jitter_mutable_routine_append_pointer_literal_parameter (struct jitter_mutable_routine *p,
516 void *immediate)
517 {
518 union jitter_word immediate_union = {.pointer = immediate};
519 jitter_mutable_routine_append_literal_parameter (p, immediate_union);
520 }
521
522 void
jitter_mutable_routine_append_register_parameter(struct jitter_mutable_routine * p,const struct jitter_register_class * register_class,jitter_register_index register_index)523 jitter_mutable_routine_append_register_parameter
524 (struct jitter_mutable_routine *p,
525 const struct jitter_register_class *register_class,
526 jitter_register_index register_index)
527 {
528 /* If we have to always residualize registers, then increment this register
529 index by the number of fast registers in the class. This way it is
530 guaranteed that the actual register used in execution will be slow. (When
531 printing out the routine the register index will be shown *decremented* by
532 the number of fast registers in the class to compensate for this.) */
533 if (p->options.slow_registers_only)
534 register_index += register_class->fast_register_no;
535
536 /* Append the register parameter. */
537 struct jitter_parameter * const pa
538 = jitter_mutable_routine_append_uninitialized_paremater
539 (p, jitter_parameter_type_register_id, register_class);
540 pa->type = jitter_parameter_type_register_id;
541 pa->register_index = register_index;
542 pa->register_class = register_class;
543 jitter_close_instruction_when_no_more_parameters (p);
544
545 /* If this register is slow and its slow index is the highest up to this
546 point, record it: it will be needed to know how many slow registers to
547 allocate. Notice that a negative slow_index (indicating a fast register)
548 will never satisfy the if condition, as p->slow_register_per_class_no is
549 initialized to zero and non-decreasing. */
550 jitter_int slow_index = register_index - register_class->fast_register_no;
551 jitter_int slow_register_no = slow_index + 1;
552 if (slow_register_no > p->slow_register_per_class_no)
553 p->slow_register_per_class_no = slow_register_no;
554 }
555
556 jitter_label
jitter_mutable_routine_append_symbolic_label_parameter(struct jitter_mutable_routine * p,const char * label_name)557 jitter_mutable_routine_append_symbolic_label_parameter (struct jitter_mutable_routine *p,
558 const char *label_name)
559 {
560 jitter_label res = jitter_symbolic_label (p, label_name);
561 jitter_mutable_routine_append_label_parameter (p, res);
562 return res;
563 }
564 void
jitter_mutable_routine_append_label_parameter(struct jitter_mutable_routine * p,jitter_label label)565 jitter_mutable_routine_append_label_parameter (struct jitter_mutable_routine *p,
566 jitter_label label)
567 {
568 struct jitter_parameter * const pa
569 = jitter_mutable_routine_append_uninitialized_paremater
570 (p, jitter_parameter_type_label, NULL);
571 pa->type = jitter_parameter_type_label;
572 pa->label = label;
573 jitter_close_instruction_when_no_more_parameters (p);
574 }
575
576 void
jitter_mutable_routine_append_meta_instruction(struct jitter_mutable_routine * p,const struct jitter_meta_instruction * const mi)577 jitter_mutable_routine_append_meta_instruction (struct jitter_mutable_routine *p,
578 const struct jitter_meta_instruction * const mi)
579 {
580 if (p->stage != jitter_routine_stage_unspecialized)
581 jitter_fatal ("appending instruction %s in non-unspecialized routine",
582 mi->name);
583 if (p->expected_parameter_no != 0)
584 jitter_fatal ("appending instruction %s with previous instruction"
585 " incomplete", mi->name);
586 jitter_routine_make_options_unchangeable (p);
587
588 /* Make the instruction. */
589 struct jitter_instruction *i
590 = p->current_instruction
591 = jitter_make_instruction (mi);
592
593 /* Add a pointer to it to the dynamic buffer for instructions within the
594 routine. */
595 jitter_dynamic_buffer_push (& p->instructions,
596 & i,
597 sizeof (struct jitter_meta_instruction *));
598
599 /* If this instruction has zero parameters then we're already done with it, and
600 we can close it immediately. Otherwise set parameter pointers to the frist
601 parameter to be appended. */
602 if ((p->expected_parameter_no = mi->parameter_no) == 0)
603 jitter_close_current_instruction (p);
604 else
605 {
606 p->next_uninitialized_parameter = i->parameters [0];
607 p->next_expected_parameter_type = mi->parameter_types;
608 }
609 }
610
611 void
jitter_mutable_routine_append_instruction_id(struct jitter_mutable_routine * p,const struct jitter_meta_instruction * const mis,size_t meta_instruction_no,unsigned unspecialized_opcode)612 jitter_mutable_routine_append_instruction_id (struct jitter_mutable_routine *p,
613 const struct jitter_meta_instruction * const mis,
614 size_t meta_instruction_no,
615 unsigned unspecialized_opcode)
616 {
617 /* Sanity check. */
618 if (unspecialized_opcode >= meta_instruction_no)
619 jitter_fatal ("jitter_mutable_routine_append_instruction_id: invalid id %u",
620 unspecialized_opcode);
621
622 /* Find the address of the appropriate meta-instruction in the array. */
623 const struct jitter_meta_instruction * const mi
624 = mis + unspecialized_opcode;
625
626 /* Append the meta-instruction. */
627 jitter_mutable_routine_append_meta_instruction (p, mi);
628 }
629
630 void
jitter_mutable_routine_append_instruction_name(struct jitter_mutable_routine * p,const char * instruction_name)631 jitter_mutable_routine_append_instruction_name (struct jitter_mutable_routine *p,
632 const char *instruction_name)
633 {
634 const struct jitter_meta_instruction * const mi
635 = jitter_lookup_meta_instruction (p->vm->meta_instruction_string_hash,
636 instruction_name);
637 jitter_mutable_routine_append_meta_instruction (p, mi);
638 }
639
640
641
642
643 /* Lower-level routine-construction API.
644 * ************************************************************************** */
645
646 void
jitter_mutable_routine_append_instruction(struct jitter_mutable_routine * p,const struct jitter_instruction * ip)647 jitter_mutable_routine_append_instruction (struct jitter_mutable_routine *p,
648 const struct jitter_instruction *ip)
649 {
650 if (p->stage != jitter_routine_stage_unspecialized)
651 jitter_fatal ("jitter_mutable_routine_append_instruction: non non-unspecialized routine");
652 if (p->expected_parameter_no != 0)
653 jitter_fatal ("jitter_mutable_routine_append_instruction: previous instruction incomplete");
654 fprintf (stderr, "Pushing instruction at %p (%s)\n", ip,
655 ip->meta_instruction->name);
656
657 /* Add the provided instruction. There is no need to touch the fields about
658 expected parameters, since the previous instruction was already closed. */
659 jitter_dynamic_buffer_push (& p->instructions,
660 & ip,
661 sizeof (struct jitter_instruction*));
662
663 /* Close the new instruction. This increments the number of rewritable
664 instructions and triggers rewriting. Notice that the instruction that was
665 just added, along with some others preceding it, might very well change or
666 disappear after rewriting is done. */
667 jitter_close_current_instruction (p);
668 }
669
670 void
jitter_mutable_routine_append_parameter_copy(struct jitter_mutable_routine * p,const struct jitter_parameter * pp)671 jitter_mutable_routine_append_parameter_copy (struct jitter_mutable_routine *p,
672 const struct jitter_parameter *pp)
673 {
674 /* Check that the parameter is compatbile with what we are expecting; fail
675 fatally if it isn't. */
676 jitter_check_paremater_compatibility (p, pp->type, pp->register_class);
677
678 /* The next parameter is pre-allocated. Copy the pointed one into it. */
679 jitter_copy_instruction_parameter (p->next_uninitialized_parameter, pp);
680
681 /* Advance pointers in the routine past this parameter, starting a new
682 instruction if needed. This however doesn't close the instruction... */
683 jitter_advance_past_next_parameter (p);
684
685 /* ...So do it if needed. */
686 jitter_close_instruction_when_no_more_parameters (p);
687 }
688
689
690
691
692 /* Jump target computation on unspecialized routines.
693 * ************************************************************************** */
694
695 bool*
jitter_mutable_routine_jump_targets(const struct jitter_mutable_routine * p)696 jitter_mutable_routine_jump_targets (const struct jitter_mutable_routine *p)
697 {
698 if (p->expected_parameter_no != 0)
699 jitter_fatal ("computing jump targets with an instruction incomplete");
700
701 const int instruction_no = jitter_mutable_routine_instruction_no (p);
702 const struct jitter_instruction **ins
703 = (const struct jitter_instruction **)
704 jitter_dynamic_buffer_to_const_pointer (& p->instructions);
705 bool *res = jitter_xmalloc (sizeof (bool) * instruction_no);
706
707 /* Initialize: no instruction is a jump target by default. */
708 int i;
709 for (i = 0; i < instruction_no; i ++)
710 res [i] = false;
711
712 /* Scan every instruction... */
713 for (i = 0; i < instruction_no; i ++)
714 {
715 const struct jitter_parameter **ps
716 = (const struct jitter_parameter **) ins[i]->parameters;
717
718 /* Any callee instruction is a branch target, reachable by a
719 branch-and-link. */
720 if (ins [i]->meta_instruction->callee)
721 res [i] = true;
722
723 /* Any instruction directly *following* a caller instruction is a branch
724 target, implicitly reachable by a return. */
725 if (ins [i]->meta_instruction->caller && (i + 1) < instruction_no)
726 res [i + 1] = true;
727
728 /* Look at every argument of the i-th instruction: for every one referring
729 another instruction as a jump target, set the target to true. */
730 const int arity = ins[i]->meta_instruction->parameter_no;
731 int j;
732 for (j = 0; j < arity; j ++)
733 {
734 const struct jitter_parameter *p = ps [j];
735 if (p->type == jitter_parameter_type_label)
736 {
737 const long target = p->label_as_index;
738 if (target < 0 || target >= instruction_no)
739 {
740 printf ("# Warning: invalid label literal in instruction "
741 "at L%li\n", (long) i);
742 res [i] = true; /* Make the invalid instruction visible. */
743 }
744 else
745 res [target] = true;
746 }
747 } /* inner for: parameter loop. */
748 } /* outer for: instruction loop. */
749
750 return res;
751 }
752
753
754
755
756 /* Unspecialized routine printer.
757 * ************************************************************************** */
758
759 /* Return the length of the longest instruction name actually used in this
760 routine. */
761 static size_t
jitter_maximum_instruction_name_length(const struct jitter_mutable_routine * p)762 jitter_maximum_instruction_name_length (const struct jitter_mutable_routine *p)
763 {
764 const int instruction_no = jitter_mutable_routine_instruction_no (p);
765 const struct jitter_instruction **ins
766 = (const struct jitter_instruction **)
767 jitter_dynamic_buffer_to_const_pointer (& p->instructions);
768
769 /* Iterate on every instruction, and find the maximum length. */
770 size_t res = 0;
771 int i;
772 for (i = 0; i < instruction_no; i ++)
773 {
774 const struct jitter_instruction * in = ins [i];
775 const struct jitter_meta_instruction * mi = in->meta_instruction;
776 size_t instruction_name_length = strlen (mi->name);
777 if (instruction_name_length > res)
778 res = instruction_name_length;
779 }
780 return res;
781 }
782
783 /* Begin using a class in the given print context, where the class name is
784 formed by the concatenation of the lower-case prefix for the VM of the
785 pointed mutable routine, concatenated to a dash, concatenated to the
786 given suffix.
787 For example, if the mutable routine r belonged to a VM named "foo",
788 jitter_mutable_routine_begin_class (ctx, r, "label")
789 would open a class in the context ctx named "foo-label". */
790 static void
jitter_mutable_routine_begin_class(jitter_print_context ctx,const struct jitter_mutable_routine * p,const char * suffix)791 jitter_mutable_routine_begin_class (jitter_print_context ctx,
792 const struct jitter_mutable_routine *p,
793 const char *suffix)
794 {
795 char *prefix = p->vm->configuration->lower_case_prefix;
796 size_t size = strlen (prefix) + 1 + strlen (suffix) + 1;
797 char *buffer = jitter_xmalloc (size);
798 sprintf (buffer, "%s-%s", prefix, suffix);
799 jitter_print_begin_class (ctx, buffer);
800 free (buffer);
801 }
802
803 void
jitter_mutable_routine_print(jitter_print_context ctx,const struct jitter_mutable_routine * r)804 jitter_mutable_routine_print (jitter_print_context ctx,
805 const struct jitter_mutable_routine *r)
806 {
807 const bool slow_registers_only = r->options.slow_registers_only;
808 const int instruction_no = jitter_mutable_routine_instruction_no (r);
809 const struct jitter_instruction **ins
810 = (const struct jitter_instruction **)
811 jitter_dynamic_buffer_to_const_pointer (& r->instructions);
812
813 /* We need to keep track of which instructions are jump targets. If we
814 already have the information, which is computed at specialization time,
815 then use it; otherwise compute it now. */
816 bool *is_target;
817 if (r->stage >= jitter_routine_stage_specialized)
818 is_target = r->jump_targets;
819 else
820 is_target = jitter_mutable_routine_jump_targets (r);
821
822 /* Prepare a printf format string leaving the correct amount of space to align
823 the first argument of every instruction to the same column. The format
824 string describes a single conversion specification, the instruction name as
825 a string. */
826 size_t max_instruction_name_length
827 = jitter_maximum_instruction_name_length (r);
828 size_t max_label_name_length
829 = (/* "$L" */ 2
830 + jitter_digit_no_radix_10 (instruction_no - 1)
831 + /* ":" */ 1);
832 int i;
833 for (i = 0; i < instruction_no; i ++)
834 {
835 const struct jitter_instruction * in = ins [i];
836 const struct jitter_meta_instruction * mi = in->meta_instruction;
837 const struct jitter_parameter **ps
838 = (const struct jitter_parameter **) in->parameters;
839
840 bool newline_after_label = false; // FIXME: configuration parameter?
841 int indentation_width = max_label_name_length + 1;
842 int printed_char_no_for_this_line = 0;
843 if (is_target [i])
844 {
845 /* It is okay to use "$L" followed by an unspecialized index as a
846 label name; this way we have a guarantee that all label names are
847 unique. */
848 char label_name_buffer [100];
849 sprintf (label_name_buffer, "$L%i", i);
850 jitter_mutable_routine_begin_class (ctx, r, "label");
851 jitter_print_char_star (ctx, label_name_buffer);
852 jitter_print_end_class (ctx);
853 jitter_mutable_routine_begin_class (ctx, r, "punctuation");
854 jitter_print_char (ctx, ':');
855 jitter_print_end_class (ctx);
856 if (newline_after_label)
857 jitter_print_char (ctx, '\n');
858 else
859 printed_char_no_for_this_line = strlen (label_name_buffer) + 1;
860 }
861 int j;
862 for (j = printed_char_no_for_this_line; j < indentation_width; j ++)
863 jitter_print_char (ctx, ' ');
864 jitter_mutable_routine_begin_class (ctx, r, "instruction");
865 jitter_print_char_star (ctx, mi->name);
866 jitter_print_end_class (ctx);
867 if (mi->parameter_no > 0)
868 {
869 int j;
870 for (j = strlen (mi->name); j < max_instruction_name_length + 1; j ++)
871 jitter_print_char (ctx, ' ');
872 }
873 const int arity = mi->parameter_no;
874 for (j = 0; j < arity; j ++)
875 {
876 const struct jitter_parameter *p = ps [j];
877 switch (p->type)
878 {
879 case jitter_parameter_type_uninitialized:
880 jitter_mutable_routine_begin_class (ctx, r, "invalid");
881 jitter_print_char_star (ctx, "<uninitialized>");
882 jitter_print_end_class (ctx);
883 break;
884 case jitter_parameter_type_register_id:
885 {
886 int register_index = p->register_index;
887 /* If the routine has been modified to use slow registers only,
888 unmodify it for printing: the modification simply consists in
889 changing register indices so that the first one maps to the
890 first slow register for each class. */
891 const struct jitter_register_class *register_class
892 = mi->parameter_types [j].register_class;
893 if (slow_registers_only)
894 register_index -= register_class->fast_register_no;
895 /* Print the possibly unmodified register. */
896 jitter_mutable_routine_begin_class (ctx, r, "register");
897 jitter_print_char (ctx, '%');
898 jitter_print_char (ctx, register_class->character);
899 jitter_print_int (ctx, 10, register_index);
900 jitter_print_end_class (ctx);
901 break;
902 }
903 case jitter_parameter_type_literal:
904 {
905 const jitter_literal_parameter_printer printer
906 = mi->parameter_types [j].literal_printer;
907 /* If the printer is the default printer than use the number
908 class; otherwise let the printer itself deal with classes. */
909 if (printer == jitter_default_literal_parameter_printer)
910 jitter_mutable_routine_begin_class (ctx, r, "number");
911 printer (ctx, p->literal.ufixnum);
912 if (printer == jitter_default_literal_parameter_printer)
913 jitter_print_end_class (ctx);
914 break;
915 }
916 case jitter_parameter_type_label:
917 jitter_mutable_routine_begin_class (ctx, r, "label");
918 jitter_print_char_star (ctx, "$L");
919 jitter_print_long (ctx, 10, (long) p->label_as_index);
920 jitter_print_end_class (ctx);
921 break;
922 default:
923 /* Even if in the future I remove some parameter types this
924 default case remains useful for debugging. Don't touch it. */
925 jitter_mutable_routine_begin_class (ctx, r, "invalid");
926 jitter_print_char_star (ctx, "<INVALID-ARGUMENT-TYPE>");
927 jitter_print_end_class (ctx);
928 break;
929 } /* switch */
930 if (j + 1 != arity)
931 {
932 jitter_mutable_routine_begin_class (ctx, r, "punctuation");
933 jitter_print_char (ctx, ',');
934 jitter_print_end_class (ctx);
935 jitter_print_char (ctx, ' ');
936 }
937 } /* inner for: parameter loop. */
938 jitter_print_char (ctx, '\n');
939 } /* outer for: instruction loop. */
940
941 /* If we have allocated the boolean array here then free it; if not then we
942 were reusing some part of the routine, and of course we should not break
943 it. */
944 if (r->stage < jitter_routine_stage_specialized)
945 free (is_target);
946 }
947
948
949
950
951 /* Label resolution.
952 * ************************************************************************** */
953
954 void
jitter_mutable_routine_resolve_labels(struct jitter_mutable_routine * pr)955 jitter_mutable_routine_resolve_labels (struct jitter_mutable_routine *pr)
956 {
957 if (pr->stage != jitter_routine_stage_unspecialized)
958 jitter_fatal ("resolving unspecialized labels in non-unspecialized routine");
959
960 const int instruction_no = jitter_mutable_routine_instruction_no (pr);
961 struct jitter_instruction **ins
962 = jitter_dynamic_buffer_to_pointer (& pr->instructions);
963
964 /* Scan instructions sequentially, and for each of them scan parameters
965 sequentially, replacing opaque labels with instruction indices. This
966 relies of parameters *not* being shared: each label parameter must be
967 touched exactly once. */
968
969 /* For every instruction... */
970 int i;
971 for (i = 0; i < instruction_no; i ++)
972 {
973 const struct jitter_instruction * in = ins [i];
974 const struct jitter_meta_instruction * mi = in->meta_instruction;
975 struct jitter_parameter **ps = in->parameters;
976
977 /* ...For every instruction parameter... */
978 const int arity = mi->parameter_no;
979 int j;
980 for (j = 0; j < arity; j ++)
981 {
982 struct jitter_parameter *p = ps [j];
983 /* ...If the parameter is a label... */
984 if (p->type == jitter_parameter_type_label)
985 {
986 /* Replace the label with its instruction index. */
987 jitter_label label = p->label;
988 jitter_int label_instruction_index
989 = jitter_get_label_instruction_index (pr, label);
990 if (label_instruction_index == -1)
991 jitter_fatal ("undefined label %li", (long) label);
992
993 /* Notice that this assignment invalidates p->label . */
994 p->label_as_index = label_instruction_index;
995 }
996 }
997 }
998 }
999