1 /* VM library: specializer header file.
2 
3    Copyright (C) 2016, 2017, 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 #ifndef JITTER_SPECIALIZE_H_
23 #define JITTER_SPECIALIZE_H_
24 
25 #include <jitter/jitter.h>
26 #include <jitter/jitter-mutable-routine.h>
27 #include <jitter/jitter-instruction.h>
28 
29 
30 /* Executable routines.
31  * ************************************************************************** */
32 
33 /* An executable routine is a data structure obtained from a routine, with a
34    different internal representation meant for direct execution rather than
35    modificaion -- the internal representation is in fact *very* different,
36    particularly in sophisticated dispatching modes involving native code.
37 
38    Only an executable routine can be run on a VM, and only a non-executable
39    routine can be modified by adding instructions and labels.
40 
41    Each non-executable routine can generate at most one executable routine.
42 
43    Once the executable routine has been generated (thru
44    jitter_make_executable_routine ) the user is free to destroy the original
45    non-executable routine in ordre to free resources, while the executable
46    routine can be safely executed.  Destroying a non-executable routine is
47    always allowed but may make disassembly and debugging information less
48    precise. */
49 
50 /* The internal representation of an executable routine.  This should be treated
51    as an abstract data type. */
52 struct jitter_executable_routine
53 {
54   /* The non-executable version of this routine, if one still exists.  This
55      field, non-NULL at initialization, becomes NULL if the original
56      non-executable routine is destroyed. */
57   struct jitter_mutable_routine *routine;
58 
59   /* A pointer to the VM this belongs to, which is never invalidated even
60      if the mutable routine is destroyed. */
61   const struct jitter_vm *vm;
62 
63   /* How many live pointers there are to this executable routine.  This is set
64      to 1 at initialization, then updated manually with
65      jitter_pin_executable_routine and jitter_unpin_executable_routine ,
66      declared below.
67 
68      The executable routine is automatically destroyed, along with its companion
69      mutable routine, when the reference count reaches zero.  Notice that, by
70      contrast, when the user explicitly destroys an executable routine its
71      mutable companion is *not* automatically destroyed. */
72   unsigned long reference_count;
73 
74   /* The following fields, including the ones conditionalized over the
75      dispatching mode, have the same meaning as the fields with the same name
76      from struct jitter_mutable_routine, and are copied from there.  See the comments in
77      jitter-routine.h .
78      The fields represented as struct jitter_dynamic_buffer in struct
79      jitter_routine, for ease of incremental construction, here are simply
80      heap-allocated buffers, whose size will no longer change.  In fact their
81      heap storage is the same allocated within struct jitter_mutable_routine, obtained
82      by extraction.  The finalization API for struct jitter_mutable_routine keeps this
83      into account, and of course avoids freeing heap memory twice. */
84   jitter_int slow_register_per_class_no;
85 #if   (defined(JITTER_DISPATCH_SWITCH)                 \
86        || defined(JITTER_DISPATCH_DIRECT_THREADING)    \
87        || defined(JITTER_DISPATCH_MINIMAL_THREADING))
88   union jitter_specialized_word *specialized_program;
89 #elif defined(JITTER_DISPATCH_NO_THREADING)
90   /* Nothing. */
91 #elif ! defined (JITTER_INTERNAL)
92 # error "unknown dispatch: this should not happen"
93 #else
94   /* This is a dispatch-independent compilation, either part of the Jitter
95      utility library or of the C code generator.  The specific fields of this
96      struct do not matter. */
97 #endif /* dispatch */
98 #if (defined(JITTER_DISPATCH_SWITCH)                \
99      || defined(JITTER_DISPATCH_DIRECT_THREADING))
100   /* Nothing. */
101 #elif (defined(JITTER_DISPATCH_MINIMAL_THREADING)  \
102        || defined(JITTER_DISPATCH_NO_THREADING))
103   char *native_code;
104   size_t native_code_size;
105 #elif ! defined (JITTER_INTERNAL)
106 # error "unknown dispatch: this should not happen"
107 #else
108   /* This is a dispatch-independent compilation, either part of the Jitter
109      utility library or of the C code generator.  The specific fields of this
110      struct do not matter. */
111 #endif /* dispatch */
112 };
113 
114 /* Translate the pointed routine into a fresh executable routine, and return a
115    pointer to it.
116    The warn_unused_result attribute serves to aid for early users who may be
117    surprised by an API change.  Early versions of this function used to return
118    void. */
119 struct jitter_executable_routine*
120 jitter_make_executable_routine (struct jitter_mutable_routine *p)
121   __attribute__ ((nonnull (1), returns_nonnull));
122 
123 /* Destroy the pointed executable routine, freeing its resources.  If its
124    original non-executable routine still exists -- in case it has been destroyed
125    already its destruction function has updated a field in the executable
126    routine, and this function will not free the non-executable routine twice.
127    After this function is called it is no longer possible to run any code
128    belonging to the executable routine, even if execution was already in
129    progress or if the function is called from a VM instruction.
130 
131    When the user calls this function the reference count of the routine must be
132    exactly one, otherwise this function fails fatally.  About destruction by
133    jitter_unpin_executable_routine and the difference in behaviour compared to a
134    direct use of this function, see the comment about the reference_count struct
135    field above. */
136 void
137 jitter_destroy_executable_routine (struct jitter_executable_routine *p)
138   __attribute__ ((nonnull (1)));
139 
140 /* Increment the reference_count field of the pointed executable routine,
141    notifying the system that one more reference handled by the user has been
142    added. */
143 void
144 jitter_pin_executable_routine (struct jitter_executable_routine *er);
145 
146 /* Decrement the reference_count field of the pointed executable routine,
147    notifying the system that one reference to the executable routine has been
148    destroyed.
149    If the count reaches zero immediately destroy the executable routine and, if
150    still existing, its mutable companion.  Notice that the behavior of
151    jitter_destroy_executable_routine is different, in that
152    jitter_destroy_executable_routine does not destroy the mutable companion. */
153 void
154 jitter_unpin_executable_routine (struct jitter_executable_routine *er);
155 
156 
157 
158 
159 /* Program points.
160  * ************************************************************************** */
161 
162 /* The type of a program point at run time in an executable routine.  This is
163    the type of object than can be passed to JITTER_BRANCH , and its actual
164    definition depends on the dispatching model.  Notice that however, in every
165    case, a program point is a pointer-to-constant type and therefore fits in a
166    word. */
167 #ifdef JITTER_DISPATCH_NO_THREADING
168   /* With no-threading dispatch a program point is the address of a machine
169      instruction -- from C, it's what a goto * statement accepts.  I don't
170      need to worry about non-GCC compilers, since no-threading relies on GCC
171      extensions. */
172   typedef const void *
173   jitter_program_point;
174 #else
175   /* On every other dispatching model a program point is a pointer to a word
176      in the executable routine -- in the case of switch dispatching that word
177      will contain a specialized opcode, with threading it will contain the
178      address of a machine instruction (see the case above) followed by the
179      VM instruction arguments. */
180   typedef const union jitter_word *
181   jitter_program_point;
182 #endif // #ifdef JITTER_DISPATCH_NO_THREADING
183 
184 /* Expand to an expression evaluating to the program point of the first
185    instruction in the pointed executable routine, as some object which is
186    correct to pass to JITTER_BRANCH.  The expression type will be
187    jitter_program_point.
188 
189    This macro is usable from within VM instructions, which might for example
190    perform a jump to the beginning of a different VM routine.  The expansion of
191    this macro is guaranteed not to contain function calls, and is safe to use
192    without extra C function wrappers. */
193 #ifdef JITTER_DISPATCH_NO_THREADING
194   /* In this case the executable routine contains a separate pointer to the
195      beginning of the executable region for the native routine.  Of course
196      the first instruction is at the beginning of the region. */
197 # define JITTER_EXECUTABLE_ROUTINE_BEGINNING(_jitter_executable_routine_ptr)  \
198     ((_jitter_executable_routine_ptr)->native_code)
199 #else
200   /* With switch dispatching or threading the first program point is a pointer
201      to the beginning of the specialized routine array. */
202 # define JITTER_EXECUTABLE_ROUTINE_BEGINNING(_jitter_executable_routine_ptr)  \
203     ((jitter_program_point)                                                   \
204      ((_jitter_executable_routine_ptr)->specialized_program))
205 #endif // ifdef JITTER_DISPATCH_NO_THREADING
206 
207 
208 
209 
210 /* Internal declarations.
211  * ************************************************************************** */
212 
213 /* What follows is not for the user. */
214 
215 /* Some specialized instruction opcodes whose values must always be valid,
216    independently from the VM.  This is checked with assertions at the first
217    run of the specializer -- see templates/vm1.c . */
218 enum jitter_specialized_instruction_opcode
219   {
220     jitter_specialized_instruction_opcode_INVALID = 0,
221     jitter_specialized_instruction_opcode_BEGINBASICBLOCK = 1,
222     jitter_specialized_instruction_opcode_EXITVM = 2,
223     jitter_specialized_instruction_opcode_DATALOCATIONS = 3,
224     jitter_specialized_instruction_opcode_NOP = 4,
225     jitter_specialized_instruction_opcode_UNREACHABLE0 = 5,
226     jitter_specialized_instruction_opcode_UNREACHABLE1 = 6,
227     jitter_specialized_instruction_opcode_UNREACHABLE2 = 7,
228   };
229 
230 /* Add an opcode to the specialized program which is being built.  This is an
231    auxiliary function used by vmprefix_specialize_instruction .  The opcode type
232    should actually be the VM-dependent enum
233    vmprefix_specialized_instruction_opcode , but it's safe to use a sufficiently
234    wide unsigned type so that this code is VM-independent. */
235 void
236 jitter_add_specialized_instruction_opcode
237    (struct jitter_mutable_routine *p,
238     /* This is actually an enum vmprefix_specialized_instruction_opcode , but
239        the type is VM-dependent. */
240     jitter_uint opcode);
241 
242 /* Add a fixnum literal to the specialized program which is being built.  This
243    is an auxiliary function used by vmprefix_specialize_instruction . */
244 void
245 jitter_add_specialized_instruction_literal (struct jitter_mutable_routine *p,
246                                             jitter_uint literal);
247 
248 /* Add a label literal (as an instruction index) to the specialized program
249    which is being built.  This is an auxiliary function used by
250    vmprefix_specialize_instruction . */
251 void
252 jitter_add_specialized_instruction_label_index (struct jitter_mutable_routine *p,
253                                                 jitter_label_as_index
254                                                 unspecialized_instruction_index);
255 
256 #endif // #ifndef JITTER_SPECIALIZE_H_
257