CACAO
methodtree.cpp
Go to the documentation of this file.
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 
41 
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)
68 #endif
69 
70  methodtree = avl_create(&methodtree_comparator);
71 
72 #if defined(ENABLE_JIT)
73  /* Insert asm_vm_call_method. */
74 
76 
77  mte->startpc = (u1 *) (ptrint) asm_vm_call_method;
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 {
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 {
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  // 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  pv = methodtree_find_nocheck(pc);
184 
185  if (pv == NULL) {
186  /* No method was found. Let's dump a stacktrace. */
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 
198  // Detect and avoid endless loops.
199  if (methodtree_find_failing)
200  vm_abort("Exiting without stacktrace...");
201  else
202  methodtree_find_failing = true;
203 
204  // Actually try to dump a stacktrace.
205  log_println("Dumping the current stacktrace:");
207 
208  vm_abort("Exiting...");
209  }
210 
211  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 
224 {
225  methodtree_element_t mtepc;
227 
228  mtepc.startpc = pc;
229  mtepc.endpc = pc;
230 
231  mte = (methodtree_element_t*) avl_find(methodtree, &mtepc);
232 
233  if (mte == NULL)
234  return NULL;
235  else
236  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  */
#define methodtree_find
Definition: md-asm.hpp:101
#define pv
Definition: md-asm.hpp:65
void stacktrace_print_current(void)
java_object_t * asm_vm_call_method(void *pv, uint64_t *array, int32_t stackargs)
#define NEW(type)
Definition: memory.hpp:93
uint8_t u1
Definition: types.hpp:40
bool avl_insert(avl_tree_t *tree, void *data)
Definition: avl.cpp:317
void log_println(const char *text,...)
Definition: logging.cpp:193
void vm_abort(const char *text,...)
Definition: vm.cpp:2586
void methodtree_init(void)
Definition: methodtree.cpp:64
void * avl_find(avl_tree_t *tree, void *data)
Definition: avl.cpp:350
void asm_vm_call_method_end(void)
#define ADDR_MASK(a)
void * methodtree_find_nocheck(void *pc)
Definition: methodtree.cpp:223
static int methodtree_comparator(const void *treenode, const void *node)
Definition: methodtree.cpp:100
static avl_tree_t * methodtree
Definition: methodtree.cpp:50
#define pc
Definition: md-asm.hpp:56
void methodtree_insert(void *startpc, void *endpc)
Definition: methodtree.cpp:148
uintptr_t ptrint
Definition: types.hpp:54
avl_tree_t * avl_create(avl_comparator *comparator)
Definition: avl.cpp:65