1 /* Jitter: patch-in functionality.
2 
3    Copyright (C) 2017 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 <jitter/jitter-patch-in.h>
24 
25 
26 /* Do nothing if not using fast branches.
27  * ************************************************************************** */
28 
29 /* This whole source file expands to nothing if patch-ins are not supported in
30    this configuration.  The CPP inclusion above suffices to make the CPP
31    definition of JITTER_HAVE_PATCH_IN visible, if it exists. */
32 
33 #ifdef JITTER_HAVE_PATCH_IN
34 
35 
36 
37 
38 /* Include headers.
39  * ************************************************************************** */
40 
41 #include <stdbool.h>
42 
43 #include <jitter/jitter.h>
44 #include <jitter/jitter-malloc.h>
45 
46 
47 
48 
49 /* Patch-in efficient data structures.
50  * ************************************************************************** */
51 
52 struct patch_in_table_entry *
jitter_make_patch_in_table(const struct jitter_patch_in_descriptor * descs,size_t desc_no,size_t specialized_instruction_no)53 jitter_make_patch_in_table (const struct jitter_patch_in_descriptor *descs,
54                             size_t desc_no,
55                             size_t specialized_instruction_no)
56 {
57   /* Make an array of empty dynamic buffers. */
58   struct jitter_dynamic_buffer *dbs
59     = jitter_xmalloc (sizeof (struct jitter_dynamic_buffer)
60                       * specialized_instruction_no);
61   int i;
62   for (i = 0; i < specialized_instruction_no; i ++)
63     jitter_dynamic_buffer_initialize_with_allocated_size (dbs + i, 0);
64 
65   /* Scan the unordered descriptors, adding a pointer to each element in the
66      appropriate place. */
67   for (i = 0; i < desc_no; i ++)
68     {
69       const struct jitter_patch_in_descriptor *desc = descs + i;
70       int opcode = desc->specialized_instruction_opcode;
71       jitter_dynamic_buffer_push
72          (dbs + opcode,
73           & desc,
74           sizeof (const struct jitter_patch_in_descriptor *));
75     }
76 
77   /* Now build the result from the dynamic buffers, destroying them in the
78      process. */
79   struct patch_in_table_entry *res
80     = jitter_xmalloc (sizeof (struct patch_in_table_entry)
81                       * specialized_instruction_no);
82   for (i = 0; i < specialized_instruction_no; i ++)
83     {
84       struct jitter_dynamic_buffer *db = dbs + i;
85       struct patch_in_table_entry *entry = res + i;
86       entry->descriptor_no
87         = (db->used_size / sizeof (const struct jitter_patch_in_descriptor *));
88       if (entry->descriptor_no == 0)
89         {
90           /* Don't bother extracting an array of no elements, to be copied.  We
91              can save a little memory by releasing the useless empty dynamic
92              buffer immediately, and using a NULL pointer in the result
93              instead. */
94           entry->descriptors = NULL;
95           jitter_dynamic_buffer_finalize (db);
96         }
97       else
98         /* Here I reuse the malloc-allocated memory for the dynamic buffer in
99            the result, and don't need to finalize the dynamic buffer. */
100         entry->descriptors = jitter_dynamic_buffer_extract_trimmed (db);
101     }
102   free (dbs);
103 
104   /* We have built the result data structure. */
105   return res;
106 }
107 
108 void
jitter_destroy_patch_in_table(struct patch_in_table_entry * table,size_t specialized_instruction_no)109 jitter_destroy_patch_in_table (struct patch_in_table_entry *table,
110                                size_t specialized_instruction_no)
111 {
112   int i;
113   for (i = 0; i < specialized_instruction_no; i ++)
114     {
115       /* When there are no entries I use NULL pointers instead of a
116          malloc-allocated array; therefore I have to call free only for
117          specialized instructions having at least one patch-in descriptor. */
118       struct patch_in_table_entry *entry = table + i;
119       if (entry->descriptor_no != 0)
120         free (entry->descriptors);
121     }
122   free (table);
123 }
124 
125 
126 
127 
128 /* Patch-in debugging.
129  * ************************************************************************** */
130 
131 /* Write user-readable textual information from the pointed patch-in to the
132    pointed stream, prepending the given prefix string to each line. */
133 void
jitter_dump_patch_in_descriptor_with_prefix(FILE * f,const char * prefix,const struct jitter_patch_in_descriptor * p)134 jitter_dump_patch_in_descriptor_with_prefix
135    (FILE *f,
136     const char *prefix,
137     const struct jitter_patch_in_descriptor *p)
138 {
139   fprintf (f, "%sopcode: %lu\n", prefix, (unsigned long) p->specialized_instruction_opcode);
140   fprintf (f, "%soffset: %lu\n", prefix, (unsigned long) p->offset);
141   fprintf (f, "%slength: %luB\n", prefix, (unsigned long) p->length);
142   fprintf (f, "%scase: %lu\n", prefix, (unsigned long) p->patch_in_case);
143   fprintf (f, "%sresidual index: %lu\n", prefix, (unsigned long) p->residual_index);
144   fprintf (f, "%scase-dependend word 1: %lx\n", prefix,
145            (unsigned long) p->case_dependent_word_1_uint);
146   fprintf (f, "%scase-dependend word 2: %lx\n", prefix,
147            (unsigned long) p->case_dependent_word_2_uint);
148   fprintf (f, "%scase-dependend word 3: %lx\n", prefix,
149            (unsigned long) p->case_dependent_word_3_uint);
150 }
151 
152 /* Like jitter_dump_patch_in_descriptor_internal with an empty prefix.  This is
153    meant for the user. */
154 void
jitter_dump_patch_in_descriptor(FILE * f,const struct jitter_patch_in_descriptor * p)155 jitter_dump_patch_in_descriptor (FILE *f,
156                                  const struct jitter_patch_in_descriptor *p)
157 {
158   jitter_dump_patch_in_descriptor_with_prefix (f, "", p);
159 }
160 
161 /* Given an initial pointer to the patch-in descriptor array and the number of
162    its elements, print textual information about each patch-in to the pointed
163    stream. */
164 void
jitter_dump_patch_in_descriptors(FILE * f,const struct jitter_patch_in_descriptor descriptors[],size_t descriptor_no)165 jitter_dump_patch_in_descriptors
166    (FILE *f,
167     const struct jitter_patch_in_descriptor descriptors[],
168     size_t descriptor_no)
169 {
170   fprintf (f, "descriptor_no is %lu\n", (unsigned long) descriptor_no);
171   int i;
172   for (i = 0; i < descriptor_no; i ++)
173     {
174       const struct jitter_patch_in_descriptor *p = descriptors + i;
175       fprintf (f, "The %i-th descriptor is at %p:\n", i, p);
176       jitter_dump_patch_in_descriptor_with_prefix (f, "    ", p);
177     }
178 }
179 
180 #endif // #ifdef JITTER_HAVE_PATCH_IN
181