Line data Source code
1 : /* src/vm/jit/methodtree.cpp - AVL tree of methods
2 :
3 : Copyright (C) 1996-2013
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 "mm/memory.hpp"
29 :
30 : #include "toolbox/avl.hpp"
31 : #include "toolbox/logging.hpp"
32 :
33 : #include "vm/jit/asmpart.hpp"
34 : #include "vm/jit/methodtree.hpp"
35 : #include "vm/jit/stacktrace.hpp"
36 :
37 :
38 : /* methodtree_element *********************************************************/
39 :
40 : typedef struct methodtree_element_t methodtree_element_t;
41 :
42 : struct methodtree_element_t {
43 : void *startpc;
44 : void *endpc;
45 : };
46 :
47 :
48 : /* in this tree we store all method addresses *********************************/
49 :
50 : static avl_tree_t *methodtree = NULL;
51 :
52 :
53 : /* static functions ***********************************************************/
54 :
55 : static int methodtree_comparator(const void *treenode, const void *node);
56 :
57 :
58 : /* methodtree_init *************************************************************
59 :
60 : Initialize the global method tree.
61 :
62 : *******************************************************************************/
63 :
64 163 : void methodtree_init(void)
65 : {
66 : #if defined(ENABLE_JIT)
67 : methodtree_element_t *mte;
68 : #endif
69 :
70 163 : methodtree = avl_create(&methodtree_comparator);
71 :
72 : #if defined(ENABLE_JIT)
73 : /* Insert asm_vm_call_method. */
74 :
75 163 : mte = NEW(methodtree_element_t);
76 :
77 163 : mte->startpc = (u1 *) (ptrint) asm_vm_call_method;
78 163 : mte->endpc = (u1 *) (ptrint) asm_vm_call_method_end;
79 :
80 163 : avl_insert(methodtree, mte);
81 : #endif
82 163 : }
83 :
84 :
85 : /* methodtree_comparator *******************************************************
86 :
87 : Comparator function used for the AVL tree of methods.
88 :
89 : ARGUMENTS:
90 : treenode ... the node from the tree
91 : node ....... the node to compare to the tree-node
92 :
93 : RETURN VALUE:
94 : 0 .... found
95 : -1 ... go left
96 : 1 .... go right
97 :
98 : *******************************************************************************/
99 :
100 23542642 : static int methodtree_comparator(const void *treenode, const void *node)
101 : {
102 : methodtree_element_t *mte;
103 : methodtree_element_t *mtepc;
104 :
105 23542642 : mte = (methodtree_element_t *) treenode;
106 23542642 : mtepc = (methodtree_element_t *) node;
107 :
108 : /* compare both startpc and endpc of pc, even if they have the same value,
109 : otherwise the avl_probe sometimes thinks the element is already in the
110 : tree */
111 :
112 : #ifdef __S390__
113 : /* On S390 addresses are 31 bit. Compare only 31 bits of value.
114 : */
115 : # define ADDR_MASK(a) ((a) & 0x7FFFFFFF)
116 : #else
117 : # define ADDR_MASK(a) (a)
118 : #endif
119 :
120 23542642 : if (ADDR_MASK((long) mte->startpc) <= ADDR_MASK((long) mtepc->startpc) &&
121 : ADDR_MASK((long) mtepc->startpc) <= ADDR_MASK((long) mte->endpc) &&
122 : ADDR_MASK((long) mte->startpc) <= ADDR_MASK((long) mtepc->endpc) &&
123 : ADDR_MASK((long) mtepc->endpc) <= ADDR_MASK((long) mte->endpc)) {
124 2235495 : return 0;
125 :
126 21307147 : } else if (ADDR_MASK((long) mtepc->startpc) < ADDR_MASK((long) mte->startpc)) {
127 8773231 : return -1;
128 :
129 : } else {
130 12533916 : return 1;
131 : }
132 :
133 : # undef ADDR_MASK
134 : }
135 :
136 :
137 : /* methodtree_insert ***********************************************************
138 :
139 : Insert the machine code range of a method into the AVL tree of
140 : methods.
141 :
142 : ARGUMENTS:
143 : startpc ... start address of the method
144 : endpc ..... end address of the method
145 :
146 : *******************************************************************************/
147 :
148 99456 : void methodtree_insert(void *startpc, void *endpc)
149 : {
150 : methodtree_element_t *mte;
151 :
152 : /* Allocate new method entry. */
153 :
154 99456 : mte = NEW(methodtree_element_t);
155 :
156 99456 : mte->startpc = startpc;
157 99456 : mte->endpc = endpc;
158 :
159 : /* This function does not return an error, but asserts for
160 : duplicate entries. */
161 :
162 99456 : avl_insert(methodtree, mte);
163 99456 : }
164 :
165 :
166 : /* methodtree_find *************************************************************
167 :
168 : Find the PV for the given PC by searching in the AVL tree of
169 : methods.
170 :
171 : *******************************************************************************/
172 :
173 2235495 : void *methodtree_find(void *pc)
174 : {
175 : void *pv;
176 :
177 : // This flag indicates whether a methodtree lookup is failing. We need
178 : // to keep track of this to avoid endless loops during stacktrace creation.
179 : static bool methodtree_find_failing = false;
180 :
181 : /* Try to find a method. */
182 :
183 2235495 : pv = methodtree_find_nocheck(pc);
184 :
185 2235495 : if (pv == NULL) {
186 : /* No method was found. Let's dump a stacktrace. */
187 :
188 0 : log_println("We received a SIGSEGV and tried to handle it, but we were");
189 0 : log_println("unable to find a Java method at:");
190 0 : log_println("");
191 : #if SIZEOF_VOID_P == 8
192 0 : log_println("PC=0x%016lx", pc);
193 : #else
194 : log_println("PC=0x%08x", pc);
195 : #endif
196 0 : log_println("");
197 :
198 : // Detect and avoid endless loops.
199 0 : if (methodtree_find_failing)
200 0 : vm_abort("Exiting without stacktrace...");
201 : else
202 0 : methodtree_find_failing = true;
203 :
204 : // Actually try to dump a stacktrace.
205 0 : log_println("Dumping the current stacktrace:");
206 0 : stacktrace_print_current();
207 :
208 0 : vm_abort("Exiting...");
209 : }
210 :
211 2235495 : return pv;
212 : }
213 :
214 :
215 : /* methodtree_find_nocheck *****************************************************
216 :
217 : Find the PV for the given PC by searching in the AVL tree of
218 : methods. This method does not check the return value and is used
219 : by the profiler.
220 :
221 : *******************************************************************************/
222 :
223 2235495 : void *methodtree_find_nocheck(void *pc)
224 : {
225 : methodtree_element_t mtepc;
226 : methodtree_element_t *mte;
227 :
228 2235495 : mtepc.startpc = pc;
229 2235495 : mtepc.endpc = pc;
230 :
231 2235495 : mte = (methodtree_element_t*) avl_find(methodtree, &mtepc);
232 :
233 2235495 : if (mte == NULL)
234 0 : return NULL;
235 : else
236 2235495 : return mte->startpc;
237 : }
238 :
239 :
240 : /*
241 : * These are local overrides for various environment variables in Emacs.
242 : * Please do not remove this and leave it at the end of the file, where
243 : * Emacs will automagically detect them.
244 : * ---------------------------------------------------------------------
245 : * Local variables:
246 : * mode: c++
247 : * indent-tabs-mode: t
248 : * c-basic-offset: 4
249 : * tab-width: 4
250 : * End:
251 : * vim:noexpandtab:sw=4:ts=4:
252 : */
|