1 /* src/vm/jit/linenumbertable.cpp - linenumber handling stuff
3 Copyright (C) 2007, 2008
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
33 #include "mm/memory.h"
35 #include "toolbox/list.hpp"
37 #if defined(ENABLE_STATISTICS)
38 # include "vm/options.h"
39 # include "vm/statistics.h"
42 #include "vm/jit/code.hpp"
43 #include "vm/jit/codegen-common.hpp"
44 #include "vm/jit/linenumbertable.hpp"
48 # define ADDR_MASK(type, x) ((type)((uintptr_t)(x) & 0x7FFFFFFF))
50 # define ADDR_MASK(type, x) (x)
55 * Resolve the linenumber.
57 * If the entry contains an mcode pointer (normal case), resolve it
58 * (see doc/inlining_stacktrace.txt for details).
60 * @param pv Procedure vector.
62 void Linenumber::resolve(codeinfo* code)
64 void* pv = ADDR_MASK(void*, code->entrypoint);
67 if (_linenumber >= -2)
68 _pc = (void*) ((uintptr_t) pv + (uintptr_t) _pc);
73 * Creates a linenumber table.
75 * We allocate an array and store the linenumber entry in
76 * reverse-order, so we can search the correct linenumber more easily.
80 //LinenumberTable::LinenumberTable(jitdata* jd) : _linenumbers(jd->cd->linenumbers->size())
81 LinenumberTable::LinenumberTable(jitdata* jd)
83 // Get required compiler data.
84 codeinfo* code = jd->code;
85 codegendata* cd = jd->cd;
87 #if defined(ENABLE_STATISTICS)
89 count_linenumbertable++;
91 size_linenumbertable +=
92 sizeof(LinenumberTable) +
93 sizeof(Linenumber) * cd->linenumbers->size();
97 // Fill the linenumber table entries in reverse order, so the
98 // search can be forward.
99 for (List<Linenumber>::iterator it = cd->linenumbers->begin(); it != cd->linenumbers->end(); it++) {
100 Linenumber& ln = *it;
102 // Resolve the linenumber.
105 // Store the linenumber in the vector.
106 _linenumbers.push_back(ln);
112 * Search the the line number table for the line corresponding to a
113 * given program counter.
115 * @param pc Program counter.
117 * @return Line number.
120 struct foo : public std::binary_function<Linenumber, void*, bool> {
121 bool operator() (const Linenumber& ln, const void* pc) const
123 return (pc >= ln.get_pc());
127 int32_t LinenumberTable::find(methodinfo **pm, void* pc)
129 void* maskpc = ADDR_MASK(void*, pc);
131 std::vector<Linenumber>::iterator it = find_if(_linenumbers.begin(), _linenumbers.end(), std::bind2nd(foo(), maskpc));
133 // No matching entry found.
134 if (it == _linenumbers.end())
137 Linenumber& ln = *it;
138 int32_t linenumber = ln.get_linenumber();
140 // Check for linenumber entry type.
141 if (linenumber < 0) {
142 VM::get_current()->abort("FIX ME!");
145 // We found a special inline entry (see
146 // doc/inlining_stacktrace.txt for details).
147 switch (linenumber) {
149 // Begin of an inlined method (ie. INLINE_END instruction.
150 lntinline = --lnte; /* get entry with methodinfo * */
151 lnte--; /* skip the special entry */
153 /* search inside the inlined method */
155 if (linenumbertable_linenumber_for_pc_intern(pm, lnte, lntsize, pc)) {
156 /* the inlined method contained the pc */
158 *pm = (methodinfo *) lntinline->pc;
160 assert(lntinline->linenumber <= -3);
162 return (-3) - lntinline->linenumber;
165 /* pc was not in inlined method, continue search.
166 Entries inside the inlined method will be skipped
167 because their lntentry->pc is higher than pc. */
171 /* end of inlined method */
175 /* default: is only reached for an -3-line entry after
176 a skipped -2 entry. We can safely ignore it and
177 continue searching. */
182 // Normal linenumber entry, return it.
187 /* linenumbertable_list_entry_add **********************************************
189 Add a line number reference.
192 cd.............current codegen data
193 linenumber.....number of line that starts with the given mcodeptr
195 *******************************************************************************/
197 void linenumbertable_list_entry_add(codegendata *cd, int32_t linenumber)
199 void* pc = (void*) (cd->mcodeptr - cd->mcodebase);
200 Linenumber ln(linenumber, pc);
202 cd->linenumbers->push_front(ln);
206 /* linenumbertable_list_entry_add_inline_start *********************************
208 Add a marker to the line number table indicating the start of an
209 inlined method body. (see doc/inlining_stacktrace.txt)
212 cd ..... current codegen data
213 iptr ... the ICMD_INLINE_BODY instruction
215 *******************************************************************************/
217 void linenumbertable_list_entry_add_inline_start(codegendata *cd, instruction *iptr)
219 void* pc = (void*) (cd->mcodeptr - cd->mcodebase);
221 Linenumber ln(-2 /* marks start of inlined method */, pc);
223 cd->linenumbers->push_front(ln);
225 insinfo_inline* insinfo = iptr->sx.s23.s3.inlineinfo;
226 insinfo->startmpc = (int32_t) (uintptr_t) pc; /* store for corresponding INLINE_END */
230 /* linenumbertable_list_entry_add_inline_end ***********************************
232 Add a marker to the line number table indicating the end of an
233 inlined method body. (see doc/inlining_stacktrace.txt)
236 cd ..... current codegen data
237 iptr ... the ICMD_INLINE_END instruction
240 iptr->method must point to the inlined callee.
242 *******************************************************************************/
244 void linenumbertable_list_entry_add_inline_end(codegendata *cd, instruction *iptr)
246 insinfo_inline* insinfo = iptr->sx.s23.s3.inlineinfo;
251 // Special entry containing the methodinfo.
252 Linenumber ln((-3) - iptr->line, insinfo->method);
254 cd->linenumbers->push_front(ln);
256 // End marker with PC of start of body.
257 Linenumber lne(-1, (void*) insinfo->startmpc);
259 cd->linenumbers->push_front(lne);
263 // Legacy C interface.
265 int32_t linenumbertable_linenumber_for_pc(methodinfo** m, codeinfo* code, void* pc) { return code->linenumbertable->find(m, pc); }
270 * These are local overrides for various environment variables in Emacs.
271 * Please do not remove this and leave it at the end of the file, where
272 * Emacs will automagically detect them.
273 * ---------------------------------------------------------------------
276 * indent-tabs-mode: t
280 * vim:noexpandtab:sw=4:ts=4: