2 * YASM assembler virtual line mapping handling (for parse stage)
4 * Copyright (C) 2002-2007 Peter Johnson
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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.
36 typedef struct line_mapping {
37 /* monotonically increasing virtual line */
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;
49 typedef struct line_source_info {
50 /* first bytecode on line; NULL if no bytecodes on line */
51 /*@null@*/ /*@dependent@*/ yasm_bytecode *bc;
53 /* source code line */
54 /*@owned@*/ char *source;
58 /* Shared storage for filenames */
59 /*@only@*/ /*@null@*/ HAMT *filenames;
61 /* Current virtual line number. */
62 unsigned long current;
64 /* Mappings from virtual to physical line numbers */
65 struct line_mapping *map_vector;
66 unsigned long map_size;
67 unsigned long map_allocated;
69 /* Bytecode and source line information */
70 /*@only@*/ line_source_info *source_info;
71 size_t source_info_size;
75 filename_delete_one(/*@only@*/ void *d)
81 yasm_linemap_set(yasm_linemap *linemap, const char *filename,
82 unsigned long virtual_line, unsigned long file_line,
83 unsigned long line_inc)
88 line_mapping *mapping = NULL;
90 if (virtual_line == 0) {
91 virtual_line = linemap->current;
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;
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;
113 mapping = &linemap->map_vector[linemap->map_size];
120 if (linemap->map_size >= 2)
122 linemap->map_vector[linemap->map_size-2].filename;
124 filename = "unknown";
127 /* Copy the filename (via shared storage) */
128 copy = yasm__xstrdup(filename);
130 mapping->filename = HAMT_insert(linemap->filenames, copy, copy,
131 &replace, filename_delete_one);
135 mapping->line = virtual_line;
136 mapping->file_line = file_line;
137 mapping->line_inc = line_inc;
141 yasm_linemap_poke(yasm_linemap *linemap, const char *filename,
142 unsigned long file_line)
145 line_mapping *mapping;
148 yasm_linemap_set(linemap, filename, 0, file_line, 0);
150 mapping = &linemap->map_vector[linemap->map_size-1];
152 line = linemap->current;
155 yasm_linemap_set(linemap, mapping->filename, 0,
157 mapping->line_inc*(linemap->current-2-mapping->line),
164 yasm_linemap_create(void)
167 yasm_linemap *linemap = yasm_xmalloc(sizeof(yasm_linemap));
169 linemap->filenames = HAMT_create(0, yasm_internal_error_);
171 linemap->current = 1;
173 /* initialize mapping vector */
174 linemap->map_vector = yasm_xmalloc(8*sizeof(line_mapping));
175 linemap->map_size = 0;
176 linemap->map_allocated = 8;
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;
191 yasm_linemap_destroy(yasm_linemap *linemap)
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);
198 yasm_xfree(linemap->source_info);
200 yasm_xfree(linemap->map_vector);
202 if (linemap->filenames)
203 HAMT_destroy(linemap->filenames, filename_delete_one);
209 yasm_linemap_get_current(yasm_linemap *linemap)
211 return linemap->current;
215 yasm_linemap_add_source(yasm_linemap *linemap, yasm_bytecode *bc,
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;
228 linemap->source_info_size *= 2;
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);
235 linemap->source_info[linemap->current-1].bc = bc;
236 linemap->source_info[linemap->current-1].source = yasm__xstrdup(source);
240 yasm_linemap_goto_next(yasm_linemap *linemap)
242 return ++(linemap->current);
246 yasm_linemap_lookup(yasm_linemap *linemap, unsigned long line,
247 const char **filename, unsigned long *file_line)
249 line_mapping *mapping;
250 unsigned long vindex, step;
252 assert(line <= linemap->current);
254 /* Binary search through map to find highest line_index <= index */
256 /* start step as the greatest power of 2 <= size */
258 while (step*2<=linemap->map_size)
261 if (vindex+step < linemap->map_size
262 && linemap->map_vector[vindex+step].line <= line)
266 mapping = &linemap->map_vector[vindex];
268 *filename = mapping->filename;
269 *file_line = (line ? mapping->file_line + mapping->line_inc*(line-mapping->line) : 0);
273 yasm_linemap_traverse_filenames(yasm_linemap *linemap, /*@null@*/ void *d,
274 int (*func) (const char *filename, void *d))
276 return HAMT_traverse(linemap->filenames, d, (int (*) (void *, void *))func);
280 yasm_linemap_get_source(yasm_linemap *linemap, unsigned long line,
281 yasm_bytecode **bcp, const char **sourcep)
283 if (line > linemap->source_info_size) {
289 *bcp = linemap->source_info[line-1].bc;
290 *sourcep = linemap->source_info[line-1].source;
292 return (!(*sourcep));