1 /* src/vm/jit/linenumbertable.c - linenumber handling stuff
4 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
6 This file is part of CACAO.
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2, or (at
11 your option) any later version.
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
31 #include "mm/memory.h"
33 #include "vm/jit/code.h"
34 #include "vm/jit/codegen-common.h"
35 #include "vm/jit/linenumbertable.h"
37 #if defined(ENABLE_STATISTICS)
38 # include "vmcore/options.h"
39 # include "vmcore/statistics.h"
43 # define ADDR_MASK(type, x) ((type)((uintptr_t)(x) & 0x7FFFFFFF))
45 # define ADDR_MASK(type, x) (x)
48 /* linenumbertable_create ******************************************************
50 Creates the linenumber table. We allocate an array and store the
51 linenumber entry in reverse-order, so we can search the correct
52 linenumber more easily.
54 *******************************************************************************/
56 void linenumbertable_create(jitdata *jd)
60 linenumbertable_t *lnt;
61 linenumbertable_entry_t *lnte;
63 linenumbertable_list_entry_t *le;
67 /* Get required compiler data. */
72 /* Don't allocate a linenumber table if we don't need one. */
79 /* Allocate the linenumber table and the entries array. */
81 lnt = NEW(linenumbertable_t);
82 lnte = MNEW(linenumbertable_entry_t, l->size);
84 #if defined(ENABLE_STATISTICS)
86 count_linenumbertable++;
88 size_linenumbertable +=
89 sizeof(linenumbertable_t) +
90 sizeof(linenumbertable_entry_t) * l->size;
94 /* Fill the linenumber table. */
96 lnt->length = l->size;
99 /* Fill the linenumber table entries in reverse order, so the
100 search can be forward. */
102 /* FIXME I only made this change to prevent a problem when moving
103 to C++. This should be changed back when this file has
106 pv = ADDR_MASK(uint8_t *, code->entrypoint);
108 for (le = list_first(l); le != NULL; le = list_next(l, le), lnte++) {
109 /* If the entry contains an mcode pointer (normal case),
110 resolve it (see doc/inlining_stacktrace.txt for
113 if (le->linenumber >= -2)
116 pc = (void *) le->mpc;
118 /* Fill the linenumber table entry. */
120 lnte->linenumber = le->linenumber;
124 /* Store the linenumber table in the codeinfo. */
126 code->linenumbertable = lnt;
130 /* linenumbertable_list_entry_add **********************************************
132 Add a line number reference.
135 cd.............current codegen data
136 linenumber.....number of line that starts with the given mcodeptr
138 *******************************************************************************/
140 void linenumbertable_list_entry_add(codegendata *cd, int32_t linenumber)
142 linenumbertable_list_entry_t *le;
144 le = DNEW(linenumbertable_list_entry_t);
146 le->linenumber = linenumber;
147 le->mpc = cd->mcodeptr - cd->mcodebase;
149 list_add_first(cd->linenumbers, le);
153 /* linenumbertable_list_entry_add_inline_start *********************************
155 Add a marker to the line number table indicating the start of an
156 inlined method body. (see doc/inlining_stacktrace.txt)
159 cd ..... current codegen data
160 iptr ... the ICMD_INLINE_BODY instruction
162 *******************************************************************************/
164 void linenumbertable_list_entry_add_inline_start(codegendata *cd, instruction *iptr)
166 linenumbertable_list_entry_t *le;
167 insinfo_inline *insinfo;
170 le = DNEW(linenumbertable_list_entry_t);
172 le->linenumber = (-2); /* marks start of inlined method */
173 le->mpc = (mpc = cd->mcodeptr - cd->mcodebase);
175 list_add_first(cd->linenumbers, le);
177 insinfo = iptr->sx.s23.s3.inlineinfo;
179 insinfo->startmpc = mpc; /* store for corresponding INLINE_END */
183 /* linenumbertable_list_entry_add_inline_end ***********************************
185 Add a marker to the line number table indicating the end of an
186 inlined method body. (see doc/inlining_stacktrace.txt)
189 cd ..... current codegen data
190 iptr ... the ICMD_INLINE_END instruction
193 iptr->method must point to the inlined callee.
195 *******************************************************************************/
197 void linenumbertable_list_entry_add_inline_end(codegendata *cd, instruction *iptr)
199 linenumbertable_list_entry_t *le;
200 insinfo_inline *insinfo;
202 insinfo = iptr->sx.s23.s3.inlineinfo;
206 le = DNEW(linenumbertable_list_entry_t);
208 /* special entry containing the methodinfo * */
209 le->linenumber = (-3) - iptr->line;
210 le->mpc = (uintptr_t) insinfo->method;
212 list_add_first(cd->linenumbers, le);
214 le = DNEW(linenumbertable_list_entry_t);
216 /* end marker with PC of start of body */
217 le->linenumber = (-1);
218 le->mpc = insinfo->startmpc;
220 list_add_first(cd->linenumbers, le);
224 /* linenumbertable_linenumber_for_pc_intern ************************************
226 This function search the line number table for the line
227 corresponding to a given pc. The function recurses for inlined
230 *******************************************************************************/
232 static s4 linenumbertable_linenumber_for_pc_intern(methodinfo **pm, linenumbertable_entry_t *lnte, int32_t lntsize, void *pc)
234 linenumbertable_entry_t *lntinline; /* special entry for inlined method */
236 pc = ADDR_MASK(void *, pc);
238 for (; lntsize > 0; lntsize--, lnte++) {
239 /* Note: In case of inlining this may actually compare the pc
240 against a methodinfo *, yielding a non-sensical
241 result. This is no problem, however, as we ignore such
242 entries in the switch below. This way we optimize for the
243 common case (ie. a real pc in lntentry->pc). */
245 if (pc >= lnte->pc) {
246 /* did we reach the current line? */
248 if (lnte->linenumber >= 0)
249 return lnte->linenumber;
251 /* we found a special inline entry (see
252 doc/inlining_stacktrace.txt for details */
254 switch (lnte->linenumber) {
256 /* begin of inlined method (ie. INLINE_END
259 lntinline = --lnte; /* get entry with methodinfo * */
260 lnte--; /* skip the special entry */
263 /* search inside the inlined method */
265 if (linenumbertable_linenumber_for_pc_intern(pm, lnte, lntsize, pc)) {
266 /* the inlined method contained the pc */
268 *pm = (methodinfo *) lntinline->pc;
270 assert(lntinline->linenumber <= -3);
272 return (-3) - lntinline->linenumber;
275 /* pc was not in inlined method, continue search.
276 Entries inside the inlined method will be skipped
277 because their lntentry->pc is higher than pc. */
281 /* end of inlined method */
285 /* default: is only reached for an -3-line entry after
286 a skipped -2 entry. We can safely ignore it and
287 continue searching. */
298 /* linenumbertable_linenumber_for_pc *******************************************
300 A wrapper for linenumbertable_linenumber_for_pc_intern.
302 NOTE: We have a intern version because the function is called
303 recursively for inlined methods.
305 *******************************************************************************/
307 int32_t linenumbertable_linenumber_for_pc(methodinfo **pm, codeinfo *code, void *pc)
309 linenumbertable_t *lnt;
312 /* Get line number table. */
314 lnt = code->linenumbertable;
319 /* Get the line number. */
321 linenumber = linenumbertable_linenumber_for_pc_intern(pm, lnt->entries, lnt->length, pc);
328 * These are local overrides for various environment variables in Emacs.
329 * Please do not remove this and leave it at the end of the file, where
330 * Emacs will automagically detect them.
331 * ---------------------------------------------------------------------
334 * indent-tabs-mode: t
338 * vim:noexpandtab:sw=4:ts=4: