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