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