* src/vm/jit/codegen-common.hpp (exceptionref): Removed.
[cacao.git] / src / vm / jit / linenumbertable.cpp
1 /* src/vm/jit/linenumbertable.cpp - linenumber handling stuff
2
3    Copyright (C) 2007, 2008
4    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5
6    This file is part of CACAO.
7
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.
12
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.
17
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
21    02110-1301, USA.
22
23 */
24
25
26 #include "config.h"
27
28 #include <assert.h>
29 #include <stdint.h>
30
31 #include <algorithm>
32
33 #include "mm/memory.h"
34
35 #include "toolbox/list.hpp"
36
37 #if defined(ENABLE_STATISTICS)
38 # include "vm/options.h"
39 # include "vm/statistics.h"
40 #endif
41
42 #include "vm/jit/code.hpp"
43 #include "vm/jit/codegen-common.hpp"
44 #include "vm/jit/linenumbertable.hpp"
45
46
47 #if defined(__S390__)
48 #  define ADDR_MASK(type, x) ((type)((uintptr_t)(x) & 0x7FFFFFFF))
49 #else
50 #  define ADDR_MASK(type, x) (x)
51 #endif
52
53
54 /**
55  * Resolve the linenumber.
56  *
57  * If the entry contains an mcode pointer (normal case), resolve it
58  * (see doc/inlining_stacktrace.txt for details).
59  *
60  * @param pv Procedure vector.
61  */
62 void Linenumber::resolve(codeinfo* code)
63 {
64         void* pv = ADDR_MASK(void*, code->entrypoint);
65
66         // TODO Use constant.
67         if (_linenumber >= -2)
68                 _pc = (void*) ((uintptr_t) pv + (uintptr_t) _pc);
69 }
70
71
72 /**
73  * Creates a linenumber table.
74  *
75  * We allocate an array and store the linenumber entry in
76  * reverse-order, so we can search the correct linenumber more easily.
77  *
78  * @param jd JIT data.
79  */
80 //LinenumberTable::LinenumberTable(jitdata* jd) : _linenumbers(jd->cd->linenumbers->size())
81 LinenumberTable::LinenumberTable(jitdata* jd)
82 {
83         // Get required compiler data.
84         codeinfo*    code = jd->code;
85         codegendata* cd   = jd->cd;
86
87 #if defined(ENABLE_STATISTICS)
88         if (opt_stat) {
89                 count_linenumbertable++;
90
91                 size_linenumbertable +=
92                         sizeof(LinenumberTable) +
93                         sizeof(Linenumber) * cd->linenumbers->size();
94         }
95 #endif
96
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;
101
102                 // Resolve the linenumber.
103                 ln.resolve(code);
104
105                 // Store the linenumber in the vector.
106                 _linenumbers.push_back(ln);
107         }
108 }
109
110
111 /**
112  * Search the the line number table for the line corresponding to a
113  * given program counter.
114  *
115  * @param pc Program counter.
116  *
117  * @return Line number.
118  */
119
120 struct foo : public std::binary_function<Linenumber, void*, bool> {
121         bool operator() (const Linenumber& ln, const void* pc) const
122         {
123                 return (pc >= ln.get_pc());
124         }
125 };
126
127 int32_t LinenumberTable::find(methodinfo **pm, void* pc)
128 {
129         void* maskpc = ADDR_MASK(void*, pc);
130
131         std::vector<Linenumber>::iterator it = find_if(_linenumbers.begin(), _linenumbers.end(), std::bind2nd(foo(), maskpc));
132
133         // No matching entry found.
134         if (it == _linenumbers.end())
135                 return 0;
136
137         Linenumber& ln = *it;
138         int32_t linenumber = ln.get_linenumber();
139
140         // Check for linenumber entry type.
141         if (linenumber < 0) {
142                 VM::get_current()->abort("FIX ME!");
143
144 #if 0
145                 // We found a special inline entry (see
146                 // doc/inlining_stacktrace.txt for details).
147                 switch (linenumber) {
148                 case -1:
149                         // Begin of an inlined method (ie. INLINE_END instruction.
150                         lntinline = --lnte;            /* get entry with methodinfo * */
151                         lnte--;                        /* skip the special entry      */
152
153                         /* search inside the inlined method */
154
155                         if (linenumbertable_linenumber_for_pc_intern(pm, lnte, lntsize, pc)) {
156                                 /* the inlined method contained the pc */
157
158                                 *pm = (methodinfo *) lntinline->pc;
159
160                                 assert(lntinline->linenumber <= -3);
161
162                                 return (-3) - lntinline->linenumber;
163                         }
164
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.  */
168                         break;
169
170                 case -2: 
171                         /* end of inlined method */
172
173                         return 0;
174
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.  */
178                 }
179 #endif
180         }
181
182         // Normal linenumber entry, return it.
183         return linenumber;
184 }
185
186
187 /* linenumbertable_list_entry_add **********************************************
188
189    Add a line number reference.
190
191    IN:
192       cd.............current codegen data
193       linenumber.....number of line that starts with the given mcodeptr
194
195 *******************************************************************************/
196
197 void linenumbertable_list_entry_add(codegendata *cd, int32_t linenumber)
198 {
199         void* pc = (void*) (cd->mcodeptr - cd->mcodebase);
200         Linenumber ln(linenumber, pc);
201
202         cd->linenumbers->push_front(ln);
203 }
204
205
206 /* linenumbertable_list_entry_add_inline_start *********************************
207
208    Add a marker to the line number table indicating the start of an
209    inlined method body. (see doc/inlining_stacktrace.txt)
210
211    IN:
212       cd ..... current codegen data
213       iptr ... the ICMD_INLINE_BODY instruction
214
215 *******************************************************************************/
216
217 void linenumbertable_list_entry_add_inline_start(codegendata *cd, instruction *iptr)
218 {
219         void* pc = (void*) (cd->mcodeptr - cd->mcodebase);
220
221         Linenumber ln(-2 /* marks start of inlined method */, pc);
222
223         cd->linenumbers->push_front(ln);
224
225         insinfo_inline* insinfo = iptr->sx.s23.s3.inlineinfo;
226         insinfo->startmpc = (int32_t) (uintptr_t) pc; /* store for corresponding INLINE_END */
227 }
228
229
230 /* linenumbertable_list_entry_add_inline_end ***********************************
231
232    Add a marker to the line number table indicating the end of an
233    inlined method body. (see doc/inlining_stacktrace.txt)
234
235    IN:
236       cd ..... current codegen data
237       iptr ... the ICMD_INLINE_END instruction
238
239    Note:
240       iptr->method must point to the inlined callee.
241
242 *******************************************************************************/
243
244 void linenumbertable_list_entry_add_inline_end(codegendata *cd, instruction *iptr)
245 {
246         insinfo_inline* insinfo = iptr->sx.s23.s3.inlineinfo;
247
248         // Sanity check.
249         assert(insinfo);
250
251         // Special entry containing the methodinfo.
252         Linenumber ln((-3) - iptr->line, insinfo->method);
253
254         cd->linenumbers->push_front(ln);
255
256         // End marker with PC of start of body.
257         Linenumber lne(-1, (void*) insinfo->startmpc);
258
259         cd->linenumbers->push_front(lne);
260 }
261
262
263 // Legacy C interface.
264 extern "C" {
265         int32_t linenumbertable_linenumber_for_pc(methodinfo** m, codeinfo* code, void* pc) { return code->linenumbertable->find(m, pc); }
266 }
267
268
269 /*
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  * ---------------------------------------------------------------------
274  * Local variables:
275  * mode: c++
276  * indent-tabs-mode: t
277  * c-basic-offset: 4
278  * tab-width: 4
279  * End:
280  * vim:noexpandtab:sw=4:ts=4:
281  */