2e586d173ee76eb73a53e0289fe9ca92adee8867
[cacao.git] / src / vm / jit / methodtree.c
1 /* src/vm/jit/methodtree.c - AVL tree of methods
2
3    Copyright (C) 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 <stdint.h>
29
30 #include "mm/memory.h"
31
32 #include "toolbox/avl.h"
33
34 #include "vm/jit/asmpart.h"
35 #include "vm/jit/methodtree.h"
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 void methodtree_init(void)
65 {
66 #if defined(ENABLE_JIT)
67         methodtree_element_t *mte;
68 #endif
69
70         methodtree = avl_create(&methodtree_comparator);
71
72 #if defined(ENABLE_JIT)
73         /* Insert asm_vm_call_method. */
74
75         mte = NEW(methodtree_element_t);
76
77         mte->startpc = (u1 *) (ptrint) asm_vm_call_method;
78         mte->endpc   = (u1 *) (ptrint) asm_vm_call_method_end;
79
80         avl_insert(methodtree, mte);
81 #endif
82 }
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 static int methodtree_comparator(const void *treenode, const void *node)
101 {
102         methodtree_element_t *mte;
103         methodtree_element_t *mtepc;
104
105         mte   = (methodtree_element_t *) treenode;
106         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         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                 return 0;
125
126         } else if (ADDR_MASK((long) mtepc->startpc) < ADDR_MASK((long) mte->startpc)) {
127                 return -1;
128
129         } else {
130                 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 void methodtree_insert(void *startpc, void *endpc)
149 {
150         methodtree_element_t *mte;
151
152         /* Allocate new method entry. */
153
154         mte = NEW(methodtree_element_t);
155
156         mte->startpc = startpc;
157         mte->endpc   = endpc;
158
159         /* This function does not return an error, but asserts for
160            duplicate entries. */
161
162         avl_insert(methodtree, mte);
163 }
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 void *methodtree_find(void *pc)
174 {
175         void *pv;
176
177         /* Try to find a method. */
178
179         pv = methodtree_find_nocheck(pc);
180
181         if (pv == NULL) {
182                 /* No method was found.  Let's dump a stacktrace. */
183
184 #if defined(ENABLE_VMLOG)
185                 vmlog_cacao_signl("SIGSEGV");
186 #endif
187
188                 log_println("We received a SIGSEGV and tried to handle it, but we were");
189                 log_println("unable to find a Java method at:");
190                 log_println("");
191 #if SIZEOF_VOID_P == 8
192                 log_println("PC=0x%016lx", pc);
193 #else
194                 log_println("PC=0x%08x", pc);
195 #endif
196                 log_println("");
197                 assert(0);
198                 log_println("Dumping the current stacktrace:");
199
200 #if defined(ENABLE_THREADS)
201                 /* XXX michi: This should be available even without threads! */
202                 threads_print_stacktrace();
203 #endif
204
205                 vm_abort("Exiting...");
206         }
207
208         return pv;
209 }
210
211
212 /* methodtree_find_nocheck *****************************************************
213
214    Find the PV for the given PC by searching in the AVL tree of
215    methods.  This method does not check the return value and is used
216    by the profiler.
217
218 *******************************************************************************/
219
220 void *methodtree_find_nocheck(void *pc)
221 {
222         methodtree_element_t  mtepc;
223         methodtree_element_t *mte;
224
225         mtepc.startpc = pc;
226         mtepc.endpc   = pc;
227
228         mte = avl_find(methodtree, &mtepc);
229
230         if (mte == NULL)
231                 return NULL;
232         else
233                 return mte->startpc;
234 }
235
236
237 /*
238  * These are local overrides for various environment variables in Emacs.
239  * Please do not remove this and leave it at the end of the file, where
240  * Emacs will automagically detect them.
241  * ---------------------------------------------------------------------
242  * Local variables:
243  * mode: c
244  * indent-tabs-mode: t
245  * c-basic-offset: 4
246  * tab-width: 4
247  * End:
248  * vim:noexpandtab:sw=4:ts=4:
249  */