1 /* VM library: specializer.
2 
3    Copyright (C) 2016, 2017, 2018, 2019, 2020 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 <assert.h>
23 
24 #include <jitter/jitter-malloc.h>
25 #include <jitter/jitter-fatal.h>
26 
27 #include <jitter/jitter.h>
28 #include <jitter/jitter-instruction.h>
29 #include <jitter/jitter-mutable-routine.h>
30 #include <jitter/jitter-dynamic-buffer.h>
31 #include <jitter/jitter-specialize.h>
32 #include <jitter/jitter-replicate.h>
33 #include <jitter/jitter-vm.h>
34 #include <jitter/jitter-mmap.h>  /* For executable deallocation. */
35 
36 
37 /* Executable routines: initialization and finalization.
38  * ************************************************************************** */
39 
40 /* Initialize the pointed executable routine from the pointed non-executable
41    routine, without filling in the actual routine data.
42    Fail fatally if the routine already has another executable routine. */
43 static void
jitter_initialize_executable_routine(struct jitter_executable_routine * er,struct jitter_mutable_routine * r)44 jitter_initialize_executable_routine (struct jitter_executable_routine *er,
45                                       struct jitter_mutable_routine *r)
46 {
47   //fprintf (stderr, "[Making an executable routine at %p]\n", er);
48   /* Fail if this executable routine is not the first for the routine. */
49   if (r->executable_routine != NULL)
50     jitter_fatal ("cannot generate an executable routine from %p twice", r);
51 
52   /* Link the two routines together thru pointers, so that destroying one can
53      update the other. */
54   r->executable_routine = er;
55   er->routine = r;
56   er->vm = r->vm;
57 
58   /* Initialize the other fields, where we already have enough information. */
59   er->reference_count = 1;
60   er->slow_register_per_class_no = r->slow_register_per_class_no;
61 
62   /* The remaining fields are still uninitialized. */
63 }
64 
65 void
jitter_destroy_executable_routine(struct jitter_executable_routine * er)66 jitter_destroy_executable_routine (struct jitter_executable_routine *er)
67 {
68   //fprintf (stderr, "[Destroying executable routine at %p]\n", er);
69   /* If the non-executable routine which was translated into *er still exists
70      then unlink this. */
71   struct jitter_mutable_routine *r = er->routine;
72   if (r != NULL)
73     r->executable_routine = NULL;
74 
75   /* Check that the reference count is exactly one.  It is sensible to require
76      that when this function is called by the user the reference count be
77      exactly one; when called by jitter_unpin_executable_routine this field is
78      automatically set to 1 before arriving here, just in order to pass this
79      check. */
80   if (er->reference_count != 1)
81     jitter_fatal ("destroying executable routine with reference count %lu",
82                   er->reference_count);
83 
84   /* Destroy heap-allocated fields reachable from the compiled routine. */
85 #if   (defined(JITTER_DISPATCH_SWITCH)                \
86        || defined(JITTER_DISPATCH_DIRECT_THREADING))
87   free (er->specialized_program);
88 #elif (defined(JITTER_DISPATCH_MINIMAL_THREADING)  \
89        || defined(JITTER_DISPATCH_NO_THREADING))
90   jitter_executable_deallocate (er->native_code);
91 #else
92 # error "unknown dispatch: this should not happen"
93 #endif /* dispatch */
94 
95   /* Release memory for the struct itself. */
96   free (er);
97 }
98 
99 
100 
101 
102 /* Reference counting.
103  * ************************************************************************** */
104 
105 void
jitter_pin_executable_routine(struct jitter_executable_routine * er)106 jitter_pin_executable_routine (struct jitter_executable_routine *er)
107 {
108   /* Just increment the field.  This operation is easy and fast, as it never
109      involves construction or destruction. */
110   er->reference_count ++;
111 }
112 
113 void
jitter_unpin_executable_routine(struct jitter_executable_routine * er)114 jitter_unpin_executable_routine (struct jitter_executable_routine *er)
115 {
116   /* Decrement the field.  If the new value does not reach zero then we are
117      done. */
118   er->reference_count --;
119   if (er->reference_count > 0)
120     return;
121 
122   /* If we arrived here the reference count has reached zero. */
123 
124   /* Destroy the mutable companion, if it still exists. */
125   struct jitter_mutable_routine *r = er->routine;
126   if (r != NULL)
127     jitter_destroy_mutable_routine (r);
128 
129   /* Destroy the executable routine itself.  Temporarily set the reference count
130      field to one, as the executable destruction function expects, then call the
131      executable destruction function. */
132   er->reference_count = 1;
133   jitter_destroy_executable_routine (er);
134 }
135 
136 
137 
138 
139 /* Specialization.
140  * ************************************************************************** */
141 
142 void
jitter_add_specialized_instruction_opcode(struct jitter_mutable_routine * p,jitter_uint specialized_opcode)143 jitter_add_specialized_instruction_opcode
144    (struct jitter_mutable_routine *p,
145     /* This is actually an enum vmprefix_specialized_instruction_opcode , but
146        the type is VM-dependent. */
147     jitter_uint specialized_opcode)
148 {
149   // FIXME: this comment is probably obsolete.
150   /* Without replication p->specialized_program holds direct-threaded code (each
151      VM thread followed by its zero or more residual arguments); without
152      replication p->specialized_program does *not* hold threads, but only
153      residual arguments.
154 
155      In either case we push a new element onto p->replicated_blocks , which is
156      useful in one case at specialization time, and in the other only for
157      disassembling. */
158   struct jitter_replicated_block replicated_block = {specialized_opcode, NULL, 0};
159   jitter_dynamic_buffer_push (& p->replicated_blocks,
160                                    & replicated_block,
161                                    sizeof (struct jitter_replicated_block));
162 #ifndef JITTER_REPLICATE
163 # if   defined(JITTER_DISPATCH_SWITCH)
164   union jitter_word w = {.fixnum = specialized_opcode};
165 # elif defined(JITTER_DISPATCH_DIRECT_THREADING)
166   union jitter_word w = {.thread = p->vm->threads [specialized_opcode]};
167 # else
168 #   error "replication enabled, but not switch nor direct-threading"
169 # endif// #if defined(JITTER_DISPATCH_SWITCH)...
170   jitter_dynamic_buffer_push (& p->specialized_program, & w, sizeof (w));
171 #endif // #ifndef JITTER_REPLICATE
172 }
173 
174 void
jitter_add_specialized_instruction_literal(struct jitter_mutable_routine * p,jitter_uint literal)175 jitter_add_specialized_instruction_literal (struct jitter_mutable_routine *p,
176                                             jitter_uint literal)
177 {
178   // fprintf (stderr, "Adding specialized instruction literal %i\n", (int)literal);
179   // FIXME: this will need generalization once more literal kinds are supported.
180   union jitter_word w = {.ufixnum = literal};
181   jitter_dynamic_buffer_push (& p->specialized_program, & w, sizeof (w));
182 }
183 
184 void
jitter_add_specialized_instruction_label_index(struct jitter_mutable_routine * p,jitter_label_as_index unspecialized_instruction_index)185 jitter_add_specialized_instruction_label_index (struct jitter_mutable_routine *p,
186                                                 jitter_label_as_index
187                                                 unspecialized_instruction_index)
188 {
189   // fprintf (stderr, "Adding specialized instruction label_index %i\n", (int)unspecialized_instruction_index);
190   jitter_int next_word_index
191     = jitter_dynamic_buffer_size (& p->specialized_program)
192       / sizeof (jitter_int);
193   union jitter_word w
194     = {.ufixnum  = unspecialized_instruction_index};
195   jitter_dynamic_buffer_push (& p->specialized_program, & w, sizeof (w));
196   jitter_dynamic_buffer_push (& p->specialized_label_indices,
197                               & next_word_index, sizeof (jitter_int));
198 }
199 
200 static void
jitter_backpatch_labels_in_specialized_routine(struct jitter_mutable_routine * p)201 jitter_backpatch_labels_in_specialized_routine (struct jitter_mutable_routine *p)
202 {
203   union jitter_word *specialized_program
204     = jitter_dynamic_buffer_to_pointer (& p->specialized_program);
205   const jitter_int *specialized_label_indices
206     = jitter_dynamic_buffer_to_pointer (& p->specialized_label_indices);
207   const jitter_int * const instruction_index_to_specialized_instruction_offset
208     = p->instruction_index_to_specialized_instruction_offset;
209   const int specialized_label_indices_no
210     = jitter_dynamic_buffer_size (& p->specialized_label_indices)
211       / sizeof (jitter_int);
212 
213   int i;
214   for (i = 0; i < specialized_label_indices_no; i ++)
215     {
216       union jitter_word *argument
217         = specialized_program + specialized_label_indices[i];
218       argument->pointer
219         = (union jitter_word *)
220           ((char*)specialized_program
221            + instruction_index_to_specialized_instruction_offset
222              [argument->ufixnum]);
223     }
224 }
225 
226 /* Add implicit instructions at the end of an unspecialized program. */
227 static void
jitter_mutable_routine_add_epilog(struct jitter_mutable_routine * p)228 jitter_mutable_routine_add_epilog (struct jitter_mutable_routine *p)
229 {
230   /* Add the final instructions which are supposed to close every VM routine.
231      Having each label, including the ones at the very end of the program when
232      they exist, associated to an actual unspecialized instruction makes
233      replication easier. */
234   if (p->options.add_final_exitvm)
235     jitter_mutable_routine_append_meta_instruction
236        (p, p->vm->exitvm_meta_instruction);
237   else
238     jitter_mutable_routine_append_meta_instruction
239        (p, p->vm->unreachable_meta_instruction);
240 }
241 
242 
243 
244 
245 /* Making an executable routine.
246  * ************************************************************************** */
247 
248 struct jitter_executable_routine*
jitter_make_executable_routine(struct jitter_mutable_routine * p)249 jitter_make_executable_routine (struct jitter_mutable_routine *p)
250 {
251   if (p->stage != jitter_routine_stage_unspecialized)
252     jitter_fatal ("specializing non-unspecialized program");
253   if (p->expected_parameter_no != 0)
254     jitter_fatal ("specializing program with last instruction incomplete");
255   if (p->native_code != NULL)
256     jitter_fatal ("specializing program with native code already defined");
257 
258   /* Add epilog instructions.  This way we can be sure that the program
259      ends with an "exitvm" or "unreachable" instruction. */
260   jitter_mutable_routine_add_epilog (p);
261 
262   /* Resolve label arguments in unspecialized instruction parameters. */
263   jitter_mutable_routine_resolve_labels (p);
264   /* Now label arguments refer unspecialized instruction indices. */
265 
266   /* Compute jump targets. */
267   assert (p->jump_targets == NULL);
268   p->jump_targets = jitter_mutable_routine_jump_targets (p);
269 
270   /* Now that we know how many instructions there are we can allocate
271      p->instruction_index_to_specialized_instruction_offset once and for all.
272      Its content will still be uninitialized. */
273   const int instruction_no = jitter_mutable_routine_instruction_no (p);
274   assert (p->instruction_index_to_specialized_instruction_offset == NULL);
275   p->instruction_index_to_specialized_instruction_offset
276     = jitter_xmalloc (sizeof (jitter_int) * instruction_no);
277 
278 #ifdef JITTER_REPLICATE
279   /* Whenever some specialized instruction is the first one, or is reachable by
280      a jump, we need to insert a BEGINBASICBLOCK specialized instruction
281      before its specialization.  This is needed for VM branches in minimal-threaded
282      code: there are no real threads in the thread array, only residual arguments;
283      however for every jump target we have to introduce a thread as the residual
284      argument of a BEGINBASICBLOCK special specialized instruction, which does
285      nothing but advancing the thread pointer past the argument.
286 
287      We need this special case out of the loop to support empty programs, whose
288      specialization must still begin by a BEGINBASICBLOCK.  Dealing with
289      this case within a loop is messy, because if the first instruction is
290      also a jump target then we need to set
291        p->instruction_index_to_specialized_instruction_offset [0]
292      before adding BEGINBASICBLOCK ; except that
293        p->instruction_index_to_specialized_instruction_offset [0]
294      it out of bounds if the program is empty.
295 
296      In the no-threading case BEGINBASICBLOCK specialized instructions are
297      redundant but they cost nothing at run time, since they expand to zero
298      assembly instructions.  FIXME: can I just not generate them in the
299      no-threading case by changing CPP conditionals?  Test. */
300   if (instruction_no == 0)
301     jitter_insert_beginbasicblock (p);
302 #endif // #ifdef JITTER_REPLICATE
303 
304   /* Specialize instructions, filling
305      p->instruction_index_to_specialized_instruction_offset at the same time. */
306   const struct jitter_instruction **instructions
307     = (const struct jitter_instruction **)
308       jitter_dynamic_buffer_to_pointer (& p->instructions);
309   int (* const specialize_instruction) (struct jitter_mutable_routine *p,
310                                         const struct jitter_instruction *ins)
311     = p->vm->specialize_instruction;
312   int instruction_index = 0;
313   while (instruction_index < instruction_no)
314     {
315       const struct jitter_instruction *next_instruction
316         = instructions [instruction_index];
317 
318       /* The next specialized instruction will begin where the (current) free
319          space in specialized program begins.  Notice that this may leave
320          uninitialized holes in
321          p->instruction_index_to_specialized_instruction_offset , at the indices
322          corresponding to some instructions specialized into
323          superinstructions.  Also notice that the next generated native instructions
324          might belong to a translation of BEGINBASICBLOCK . */
325       p->instruction_index_to_specialized_instruction_offset [instruction_index]
326         = jitter_dynamic_buffer_size (& p->specialized_program);
327 
328 #ifdef JITTER_REPLICATE
329       /* See the comment above about BEGINBASICBLOCK . */
330       if (instruction_index == 0 || p->jump_targets [instruction_index])
331         jitter_insert_beginbasicblock (p);
332 #endif // #ifdef JITTER_REPLICATE
333 
334       /* Specialize the next instruction, obtaining as result the number of
335          unspecialized instructions covered by the one specialized instruction
336          they are translated into.  This adds as many words as needed to
337          p->specialized_program . */
338       instruction_index += specialize_instruction (p, next_instruction);
339     }
340 
341   /* Notice that p->instruction_index_to_specialized_instruction_offset is
342      accessed only when needed to patch labels, and it's harmless to leave its
343      content undefined in places where no labels are involved. */
344 
345   /* Now that p->instruction_index_to_specialized_instruction_offset is filled
346      we have enough information to resolve label literals. */
347   jitter_backpatch_labels_in_specialized_routine (p);
348 
349   /* The program is now specialized.  FIXME: shall I free p->jump_targets
350      and set it to NULL now? */
351   p->stage = jitter_routine_stage_specialized;
352 
353 #ifdef JITTER_REPLICATE
354   /* If replication is enabled then build the native code; this will change the
355      program stage again. */
356   jitter_replicate_program (p);
357 #endif // #ifdef JITTER_REPLICATE
358 
359   /* Make an executable routine containing what we need to actually run the
360      code. */
361   struct jitter_executable_routine *res
362     = jitter_xmalloc (sizeof (struct jitter_executable_routine));
363   jitter_initialize_executable_routine (res, p);
364 
365   /* Transfer the relevant fields from the non-executable routine to the
366      executable routine, invalidating the originals to avoid double freeing. */
367 
368   /* Set the specialized_program field, where it exists. */
369 #if (defined(JITTER_DISPATCH_SWITCH)                 \
370      || defined(JITTER_DISPATCH_DIRECT_THREADING)    \
371      || defined(JITTER_DISPATCH_MINIMAL_THREADING))
372   res->specialized_program
373     = jitter_dynamic_buffer_extract (& p->specialized_program);
374 #elif defined(JITTER_DISPATCH_NO_THREADING)
375   /* Nothing. */
376 #else
377 # error "unknown dispatch: this should not happen"
378 #endif /* dispatch */
379 
380   /* Set the native_code and native_code_size fields, where they exist. */
381 #if (defined(JITTER_DISPATCH_SWITCH)             \
382   || defined(JITTER_DISPATCH_DIRECT_THREADING))  \
383   /* Nothing. */
384 #elif (defined(JITTER_DISPATCH_MINIMAL_THREADING)  \
385      || defined(JITTER_DISPATCH_NO_THREADING))
386   res->native_code = p->native_code;
387   res->native_code_size = p->native_code_size;
388   p->native_code = NULL;
389 #else
390 # error "unknown dispatch: this should not happen"
391 #endif /* dispatch */
392 
393   /* Return a pointer to the executable routine. */
394   return res;
395 }
396