Add packaging files for Tizen
[profile/ivi/yasm.git] / libyasm / linemap.c
1 /*
2  * YASM assembler virtual line mapping handling (for parse stage)
3  *
4  *  Copyright (C) 2002-2007  Peter Johnson
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  */
27 #include "util.h"
28
29 #include "coretype.h"
30 #include "hamt.h"
31
32 #include "errwarn.h"
33 #include "linemap.h"
34
35
36 typedef struct line_mapping {
37     /* monotonically increasing virtual line */
38     unsigned long line;
39
40     /* related info */
41     /* "original" source filename */
42     /*@null@*/ /*@dependent@*/ const char *filename;
43     /* "original" source base line number */
44     unsigned long file_line;
45     /* "original" source line number increment (for following lines) */
46     unsigned long line_inc;
47 } line_mapping;
48
49 typedef struct line_source_info {
50     /* first bytecode on line; NULL if no bytecodes on line */
51     /*@null@*/ /*@dependent@*/ yasm_bytecode *bc;
52
53     /* source code line */
54     /*@owned@*/ char *source;
55 } line_source_info;
56
57 struct yasm_linemap {
58     /* Shared storage for filenames */
59     /*@only@*/ /*@null@*/ HAMT *filenames;
60
61     /* Current virtual line number. */
62     unsigned long current;
63
64     /* Mappings from virtual to physical line numbers */
65     struct line_mapping *map_vector;
66     unsigned long map_size;
67     unsigned long map_allocated;
68
69     /* Bytecode and source line information */
70     /*@only@*/ line_source_info *source_info;
71     size_t source_info_size;
72 };
73
74 static void
75 filename_delete_one(/*@only@*/ void *d)
76 {
77     yasm_xfree(d);
78 }
79
80 void
81 yasm_linemap_set(yasm_linemap *linemap, const char *filename,
82                  unsigned long virtual_line, unsigned long file_line,
83                  unsigned long line_inc)
84 {
85     char *copy;
86     unsigned long i;
87     int replace = 0;
88     line_mapping *mapping = NULL;
89
90     if (virtual_line == 0) {
91         virtual_line = linemap->current;
92     }
93
94     /* Replace all existing mappings that have line numbers >= this one. */
95     for (i = linemap->map_size; i > 0; i--) {
96         if (linemap->map_vector[i-1].line < virtual_line) {
97             if (i < linemap->map_size) {
98                 mapping = &linemap->map_vector[i];
99                 linemap->map_size = i + 1;
100             }
101             break;
102         }
103     }
104
105     if (mapping == NULL) {
106         /* Create a new mapping in the map */
107         if (linemap->map_size >= linemap->map_allocated) {
108             /* allocate another size bins when full for 2x space */
109             linemap->map_vector = yasm_xrealloc(linemap->map_vector,
110                 2*linemap->map_allocated*sizeof(line_mapping));
111             linemap->map_allocated *= 2;
112         }
113         mapping = &linemap->map_vector[linemap->map_size];
114         linemap->map_size++;
115     }
116
117     /* Fill it */
118
119     if (!filename) {
120         if (linemap->map_size >= 2)
121             mapping->filename =
122                 linemap->map_vector[linemap->map_size-2].filename;
123         else
124             filename = "unknown";
125     }
126     if (filename) {
127         /* Copy the filename (via shared storage) */
128         copy = yasm__xstrdup(filename);
129         /*@-aliasunique@*/
130         mapping->filename = HAMT_insert(linemap->filenames, copy, copy,
131                                         &replace, filename_delete_one);
132         /*@=aliasunique@*/
133     }
134
135     mapping->line = virtual_line;
136     mapping->file_line = file_line;
137     mapping->line_inc = line_inc;
138 }
139
140 unsigned long
141 yasm_linemap_poke(yasm_linemap *linemap, const char *filename,
142                   unsigned long file_line)
143 {
144     unsigned long line;
145     line_mapping *mapping;
146
147     linemap->current++;
148     yasm_linemap_set(linemap, filename, 0, file_line, 0);
149
150     mapping = &linemap->map_vector[linemap->map_size-1];
151
152     line = linemap->current;
153
154     linemap->current++;
155     yasm_linemap_set(linemap, mapping->filename, 0,
156                      mapping->file_line +
157                      mapping->line_inc*(linemap->current-2-mapping->line),
158                      mapping->line_inc);
159
160     return line;
161 }
162
163 yasm_linemap *
164 yasm_linemap_create(void)
165 {
166     size_t i;
167     yasm_linemap *linemap = yasm_xmalloc(sizeof(yasm_linemap));
168
169     linemap->filenames = HAMT_create(0, yasm_internal_error_);
170
171     linemap->current = 1;
172
173     /* initialize mapping vector */
174     linemap->map_vector = yasm_xmalloc(8*sizeof(line_mapping));
175     linemap->map_size = 0;
176     linemap->map_allocated = 8;
177     
178     /* initialize source line information array */
179     linemap->source_info_size = 2;
180     linemap->source_info = yasm_xmalloc(linemap->source_info_size *
181                                         sizeof(line_source_info));
182     for (i=0; i<linemap->source_info_size; i++) {
183         linemap->source_info[i].bc = NULL;
184         linemap->source_info[i].source = NULL;
185     }
186
187     return linemap;
188 }
189
190 void
191 yasm_linemap_destroy(yasm_linemap *linemap)
192 {
193     size_t i;
194     for (i=0; i<linemap->source_info_size; i++) {
195         if (linemap->source_info[i].source)
196             yasm_xfree(linemap->source_info[i].source);
197     }
198     yasm_xfree(linemap->source_info);
199
200     yasm_xfree(linemap->map_vector);
201
202     if (linemap->filenames)
203         HAMT_destroy(linemap->filenames, filename_delete_one);
204
205     yasm_xfree(linemap);
206 }
207
208 unsigned long
209 yasm_linemap_get_current(yasm_linemap *linemap)
210 {
211     return linemap->current;
212 }
213
214 void
215 yasm_linemap_add_source(yasm_linemap *linemap, yasm_bytecode *bc,
216                         const char *source)
217 {
218     size_t i;
219
220     while (linemap->current > linemap->source_info_size) {
221         /* allocate another size bins when full for 2x space */
222         linemap->source_info = yasm_xrealloc(linemap->source_info,
223             2*linemap->source_info_size*sizeof(line_source_info));
224         for (i=linemap->source_info_size; i<linemap->source_info_size*2; i++) {
225             linemap->source_info[i].bc = NULL;
226             linemap->source_info[i].source = NULL;
227         }
228         linemap->source_info_size *= 2;
229     }
230
231     /* Delete existing info for that line (if any) */
232     if (linemap->source_info[linemap->current-1].source)
233         yasm_xfree(linemap->source_info[linemap->current-1].source);
234
235     linemap->source_info[linemap->current-1].bc = bc;
236     linemap->source_info[linemap->current-1].source = yasm__xstrdup(source);
237 }
238
239 unsigned long
240 yasm_linemap_goto_next(yasm_linemap *linemap)
241 {
242     return ++(linemap->current);
243 }
244
245 void
246 yasm_linemap_lookup(yasm_linemap *linemap, unsigned long line,
247                     const char **filename, unsigned long *file_line)
248 {
249     line_mapping *mapping;
250     unsigned long vindex, step;
251
252     assert(line <= linemap->current);
253
254     /* Binary search through map to find highest line_index <= index */
255     vindex = 0;
256     /* start step as the greatest power of 2 <= size */
257     step = 1;
258     while (step*2<=linemap->map_size)
259         step*=2;
260     while (step>0) {
261         if (vindex+step < linemap->map_size
262                 && linemap->map_vector[vindex+step].line <= line)
263             vindex += step;
264         step /= 2;
265     }
266     mapping = &linemap->map_vector[vindex];
267
268     *filename = mapping->filename;
269     *file_line = (line ? mapping->file_line + mapping->line_inc*(line-mapping->line) : 0);
270 }
271
272 int
273 yasm_linemap_traverse_filenames(yasm_linemap *linemap, /*@null@*/ void *d,
274                                 int (*func) (const char *filename, void *d))
275 {
276     return HAMT_traverse(linemap->filenames, d, (int (*) (void *, void *))func);
277 }
278
279 int
280 yasm_linemap_get_source(yasm_linemap *linemap, unsigned long line,
281                         yasm_bytecode **bcp, const char **sourcep)
282 {
283     if (line > linemap->source_info_size) {
284         *bcp = NULL;
285         *sourcep = NULL;
286         return 1;
287     }
288
289     *bcp = linemap->source_info[line-1].bc;
290     *sourcep = linemap->source_info[line-1].source;
291
292     return (!(*sourcep));
293 }