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