* src/mm/memory.cpp,
[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.hpp"
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 code Code structure.
61  */
62 void Linenumber::resolve(const 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->begin(), jd->cd->linenumbers->end())
81 {
82         // Get required compiler data.
83         codeinfo* code = jd->code;
84
85 #if defined(ENABLE_STATISTICS)
86         if (opt_stat) {
87                 count_linenumbertable++;
88
89                 size_linenumbertable +=
90                         sizeof(LinenumberTable) +
91                         sizeof(Linenumber) * _linenumbers.size();
92         }
93 #endif
94
95         // Resolve all linenumbers in the vector.
96         (void) for_each(_linenumbers.begin(), _linenumbers.end(), std::bind2nd(LinenumberResolver(), code));
97 }
98
99
100 /**
101  * Search the the line number table for the line corresponding to a
102  * given program counter.
103  *
104  * @param pc Program counter.
105  *
106  * @return Line number.
107  */
108 int32_t LinenumberTable::find(methodinfo **pm, void* pc)
109 {
110         void* maskpc = ADDR_MASK(void*, pc);
111
112         std::vector<Linenumber>::iterator it = find_if(_linenumbers.begin(), _linenumbers.end(), std::bind2nd(comparator(), maskpc));
113
114         // No matching entry found.
115         if (it == _linenumbers.end())
116                 return 0;
117
118         Linenumber& ln = *it;
119         int32_t linenumber = ln.get_linenumber();
120
121         // Check for linenumber entry type.
122         if (linenumber < 0) {
123                 os::abort("FIX ME!");
124
125 #if 0
126                 // We found a special inline entry (see
127                 // doc/inlining_stacktrace.txt for details).
128                 switch (linenumber) {
129                 case -1:
130                         // Begin of an inlined method (ie. INLINE_END instruction.
131                         lntinline = --lnte;            /* get entry with methodinfo * */
132                         lnte--;                        /* skip the special entry      */
133
134                         /* search inside the inlined method */
135
136                         if (linenumbertable_linenumber_for_pc_intern(pm, lnte, lntsize, pc)) {
137                                 /* the inlined method contained the pc */
138
139                                 *pm = (methodinfo *) lntinline->pc;
140
141                                 assert(lntinline->linenumber <= -3);
142
143                                 return (-3) - lntinline->linenumber;
144                         }
145
146                         /* pc was not in inlined method, continue search.
147                            Entries inside the inlined method will be skipped
148                            because their lntentry->pc is higher than pc.  */
149                         break;
150
151                 case -2: 
152                         /* end of inlined method */
153
154                         return 0;
155
156                         /* default: is only reached for an -3-line entry after
157                            a skipped -2 entry. We can safely ignore it and
158                            continue searching.  */
159                 }
160 #endif
161         }
162
163         // Normal linenumber entry, return it.
164         return linenumber;
165 }
166
167
168 /* linenumbertable_list_entry_add **********************************************
169
170    Add a line number reference.
171
172    IN:
173       cd.............current codegen data
174       linenumber.....number of line that starts with the given mcodeptr
175
176 *******************************************************************************/
177
178 void linenumbertable_list_entry_add(codegendata *cd, int32_t linenumber)
179 {
180         void* pc = (void*) (cd->mcodeptr - cd->mcodebase);
181         Linenumber ln(linenumber, pc);
182
183         cd->linenumbers->push_front(ln);
184 }
185
186
187 /* linenumbertable_list_entry_add_inline_start *********************************
188
189    Add a marker to the line number table indicating the start of an
190    inlined method body. (see doc/inlining_stacktrace.txt)
191
192    IN:
193       cd ..... current codegen data
194       iptr ... the ICMD_INLINE_BODY instruction
195
196 *******************************************************************************/
197
198 void linenumbertable_list_entry_add_inline_start(codegendata *cd, instruction *iptr)
199 {
200         void* pc = (void*) (cd->mcodeptr - cd->mcodebase);
201
202         Linenumber ln(-2 /* marks start of inlined method */, pc);
203
204         cd->linenumbers->push_front(ln);
205
206         insinfo_inline* insinfo = iptr->sx.s23.s3.inlineinfo;
207         insinfo->startmpc = (int32_t) (uintptr_t) pc; /* store for corresponding INLINE_END */
208 }
209
210
211 /* linenumbertable_list_entry_add_inline_end ***********************************
212
213    Add a marker to the line number table indicating the end of an
214    inlined method body. (see doc/inlining_stacktrace.txt)
215
216    IN:
217       cd ..... current codegen data
218       iptr ... the ICMD_INLINE_END instruction
219
220    Note:
221       iptr->method must point to the inlined callee.
222
223 *******************************************************************************/
224
225 void linenumbertable_list_entry_add_inline_end(codegendata *cd, instruction *iptr)
226 {
227         insinfo_inline* insinfo = iptr->sx.s23.s3.inlineinfo;
228
229         // Sanity check.
230         assert(insinfo);
231
232         // Special entry containing the methodinfo.
233         Linenumber ln((-3) - iptr->line, insinfo->method);
234
235         cd->linenumbers->push_front(ln);
236
237         // End marker with PC of start of body.
238         Linenumber lne(-1, (void*) insinfo->startmpc);
239
240         cd->linenumbers->push_front(lne);
241 }
242
243
244 /*
245  * These are local overrides for various environment variables in Emacs.
246  * Please do not remove this and leave it at the end of the file, where
247  * Emacs will automagically detect them.
248  * ---------------------------------------------------------------------
249  * Local variables:
250  * mode: c++
251  * indent-tabs-mode: t
252  * c-basic-offset: 4
253  * tab-width: 4
254  * End:
255  * vim:noexpandtab:sw=4:ts=4:
256  */