1/* Handle exceptions for GNU compiler for the Java(TM) language. 2 Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc. 3 4This file is part of GNU CC. 5 6GNU CC is free software; you can redistribute it and/or modify 7it under the terms of the GNU General Public License as published by 8the Free Software Foundation; either version 2, or (at your option) 9any later version. 10 11GNU CC is distributed in the hope that it will be useful, 12but WITHOUT ANY WARRANTY; without even the implied warranty of 13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14GNU General Public License for more details. 15 16You should have received a copy of the GNU General Public License 17along with GNU CC; see the file COPYING. If not, write to 18the Free Software Foundation, 59 Temple Place - Suite 330, 19Boston, MA 02111-1307, USA. 20 21Java and all Java-based marks are trademarks or registered trademarks 22of Sun Microsystems, Inc. in the United States and other countries. 23The Free Software Foundation is independent of Sun Microsystems, Inc. */ 24 25#include "config.h" 26#include "system.h" 27#include "tree.h" 28#include "real.h" 29#include "rtl.h" 30#include "java-tree.h" 31#include "javaop.h" 32#include "java-opcodes.h" 33#include "jcf.h" 34#include "except.h" 35#include "java-except.h" 36#include "eh-common.h" 37#include "toplev.h" 38 39static void expand_start_java_handler PROTO ((struct eh_range *)); 40static void expand_end_java_handler PROTO ((struct eh_range *)); 41 42extern struct obstack permanent_obstack; 43 44struct eh_range *current_method_handlers; 45 46struct eh_range *current_try_block = NULL; 47 48struct eh_range *eh_range_freelist = NULL; 49 50/* These variables are used to speed up find_handler. */ 51 52static int cache_range_start, cache_range_end; 53static struct eh_range *cache_range; 54static struct eh_range *cache_next_child; 55 56/* A dummy range that represents the entire method. */ 57 58struct eh_range whole_range; 59 60/* Search for the most specific eh_range containing PC. 61 Assume PC is within RANGE. 62 CHILD is a list of children of RANGE such that any 63 previous children have end_pc values that are too low. */ 64 65static struct eh_range * 66find_handler_in_range (pc, range, child) 67 int pc; 68 struct eh_range *range; 69 register struct eh_range *child; 70{ 71 for (; child != NULL; child = child->next_sibling) 72 { 73 if (pc < child->start_pc) 74 break; 75 if (pc < child->end_pc) 76 return find_handler_in_range (pc, child, child->first_child); 77 } 78 cache_range = range; 79 cache_range_start = pc; 80 cache_next_child = child; 81 cache_range_end = child == NULL ? range->end_pc : child->start_pc; 82 return range; 83} 84 85/* Find the inner-most handler that contains PC. */ 86 87struct eh_range * 88find_handler (pc) 89 int pc; 90{ 91 struct eh_range *h; 92 if (pc >= cache_range_start) 93 { 94 h = cache_range; 95 if (pc < cache_range_end) 96 return h; 97 while (pc >= h->end_pc) 98 { 99 cache_next_child = h->next_sibling; 100 h = h->outer; 101 } 102 } 103 else 104 { 105 h = &whole_range; 106 cache_next_child = h->first_child; 107 } 108 return find_handler_in_range (pc, h, cache_next_child); 109} 110 111/* Recursive helper routine for check_nested_ranges. */ 112 113static void 114link_handler (range, outer) 115 struct eh_range *range, *outer; 116{ 117 struct eh_range **ptr; 118 119 if (range->start_pc == outer->start_pc && range->end_pc == outer->end_pc) 120 { 121 outer->handlers = chainon (range->handlers, outer->handlers); 122 return; 123 } 124 125 /* If the new range completely encloses the `outer' range, then insert it 126 between the outer range and its parent. */ 127 if (range->start_pc <= outer->start_pc && range->end_pc >= outer->end_pc) 128 { 129 range->outer = outer->outer; 130 range->next_sibling = NULL; 131 range->first_child = outer; 132 { 133 struct eh_range **pr = &(outer->outer->first_child); 134 while (*pr != outer) 135 pr = &(*pr)->next_sibling; 136 *pr = range; 137 } 138 outer->outer = range; 139 return; 140 } 141 142 /* Handle overlapping ranges by splitting the new range. */ 143 if (range->start_pc < outer->start_pc || range->end_pc > outer->end_pc) 144 { 145 struct eh_range *h 146 = (struct eh_range *) oballoc (sizeof (struct eh_range)); 147 if (range->start_pc < outer->start_pc) 148 { 149 h->start_pc = range->start_pc; 150 h->end_pc = outer->start_pc; 151 range->start_pc = outer->start_pc; 152 } 153 else 154 { 155 h->start_pc = outer->end_pc; 156 h->end_pc = range->end_pc; 157 range->end_pc = outer->end_pc; 158 } 159 h->first_child = NULL; 160 h->outer = NULL; 161 h->handlers = build_tree_list (TREE_PURPOSE (range->handlers), 162 TREE_VALUE (range->handlers)); 163 h->next_sibling = NULL; 164 /* Restart both from the top to avoid having to make this 165 function smart about reentrancy. */ 166 link_handler (h, &whole_range); 167 link_handler (range, &whole_range); 168 return; 169 } 170 171 ptr = &outer->first_child; 172 for (;; ptr = &(*ptr)->next_sibling) 173 { 174 if (*ptr == NULL || range->end_pc <= (*ptr)->start_pc) 175 { 176 range->next_sibling = *ptr; 177 range->first_child = NULL; 178 range->outer = outer; 179 *ptr = range; 180 return; 181 } 182 else if (range->start_pc < (*ptr)->end_pc) 183 { 184 link_handler (range, *ptr); 185 return; 186 } 187 /* end_pc > (*ptr)->start_pc && start_pc >= (*ptr)->end_pc. */ 188 } 189} 190 191/* The first pass of exception range processing (calling add_handler) 192 constructs a linked list of exception ranges. We turn this into 193 the data structure expected by the rest of the code, and also 194 ensure that exception ranges are properly nested. */ 195 196void 197handle_nested_ranges () 198{ 199 struct eh_range *ptr, *next; 200 201 ptr = whole_range.first_child; 202 whole_range.first_child = NULL; 203 for (; ptr; ptr = next) 204 { 205 next = ptr->next_sibling; 206 ptr->next_sibling = NULL; 207 link_handler (ptr, &whole_range); 208 } 209} 210 211 212/* Called to re-initialize the exception machinery for a new method. */ 213 214void 215method_init_exceptions () 216{ 217 whole_range.start_pc = 0; 218 whole_range.end_pc = DECL_CODE_LENGTH (current_function_decl) + 1; 219 whole_range.outer = NULL; 220 whole_range.first_child = NULL; 221 whole_range.next_sibling = NULL; 222 cache_range_start = 0xFFFFFF; 223 java_set_exception_lang_code (); 224} 225 226void 227java_set_exception_lang_code () 228{ 229 set_exception_lang_code (EH_LANG_Java); 230 set_exception_version_code (1); 231} 232 233/* Add an exception range. If we already have an exception range 234 which has the same handler and label, and the new range overlaps 235 that one, then we simply extend the existing range. Some bytecode 236 obfuscators generate seemingly nonoverlapping exception ranges 237 which, when coalesced, do in fact nest correctly. 238 239 This constructs an ordinary linked list which check_nested_ranges() 240 later turns into the data structure we actually want. 241 242 We expect the input to come in order of increasing START_PC. This 243 function doesn't attempt to detect the case where two previously 244 added disjoint ranges could be coalesced by a new range; that is 245 what the sorting counteracts. */ 246 247void 248add_handler (start_pc, end_pc, handler, type) 249 int start_pc, end_pc; 250 tree handler; 251 tree type; 252{ 253 struct eh_range *ptr, *prev = NULL, *h; 254 255 for (ptr = whole_range.first_child; ptr; ptr = ptr->next_sibling) 256 { 257 if (start_pc >= ptr->start_pc 258 && start_pc <= ptr->end_pc 259 && TREE_PURPOSE (ptr->handlers) == type 260 && TREE_VALUE (ptr->handlers) == handler) 261 { 262 /* Already found an overlapping range, so coalesce. */ 263 ptr->end_pc = MAX (ptr->end_pc, end_pc); 264 return; 265 } 266 prev = ptr; 267 } 268 269 h = (struct eh_range *) oballoc (sizeof (struct eh_range)); 270 h->start_pc = start_pc; 271 h->end_pc = end_pc; 272 h->first_child = NULL; 273 h->outer = NULL; 274 h->handlers = build_tree_list (type, handler); 275 h->next_sibling = NULL; 276 277 if (prev == NULL) 278 whole_range.first_child = h; 279 else 280 prev->next_sibling = h; 281} 282 283 284/* if there are any handlers for this range, issue start of region */ 285static void 286expand_start_java_handler (range) 287 struct eh_range *range ATTRIBUTE_UNUSED; 288{ 289 expand_eh_region_start (); 290} 291 292tree 293prepare_eh_table_type (type) 294 tree type; 295{ 296 tree exp; 297 298 /* The "type" (metch_info) in a (Java) exception table is one: 299 * a) NULL - meaning match any type in a try-finally. 300 * b) a pointer to a (ccmpiled) class (low-order bit 0). 301 * c) a pointer to the Utf8Const name of the class, plus one 302 * (which yields a value with low-order bit 1). */ 303 304 push_obstacks (&permanent_obstack, &permanent_obstack); 305 if (type == NULL_TREE) 306 exp = null_pointer_node; 307 else if (is_compiled_class (type)) 308 exp = build_class_ref (type); 309 else 310 exp = fold (build 311 (PLUS_EXPR, ptr_type_node, 312 build_utf8_ref (build_internal_class_name (type)), 313 size_one_node)); 314 pop_obstacks (); 315 return exp; 316} 317 318/* if there are any handlers for this range, isssue end of range, 319 and then all handler blocks */ 320static void 321expand_end_java_handler (range) 322 struct eh_range *range; 323{ 324 tree handler = range->handlers; 325 expand_start_all_catch (); 326 for ( ; handler != NULL_TREE; handler = TREE_CHAIN (handler)) 327 { 328 start_catch_handler (prepare_eh_table_type (TREE_PURPOSE (handler))); 329 /* Push the thrown object on the top of the stack */ 330 expand_goto (TREE_VALUE (handler)); 331 } 332 expand_end_all_catch (); 333} 334 335/* Recursive helper routine for maybe_start_handlers. */ 336 337static void 338check_start_handlers (range, pc) 339 struct eh_range *range; 340 int pc; 341{ 342 if (range != NULL_EH_RANGE && range->start_pc == pc) 343 { 344 check_start_handlers (range->outer, pc); 345 expand_start_java_handler (range); 346 } 347} 348 349struct eh_range *current_range; 350 351/* Emit any start-of-try-range start at PC. */ 352 353void 354maybe_start_try (pc) 355 int pc; 356{ 357 if (! doing_eh (1)) 358 return; 359 360 current_range = find_handler (pc); 361 check_start_handlers (current_range, pc); 362} 363 364/* Emit any end-of-try-range end at PC. */ 365 366void 367maybe_end_try (pc) 368 int pc; 369{ 370 if (! doing_eh (1)) 371 return; 372 373 while (current_range != NULL_EH_RANGE && current_range->end_pc <= pc) 374 { 375 expand_end_java_handler (current_range); 376 current_range = current_range->outer; 377 } 378} 379 380/* Emit the handler labels and their code */ 381 382void 383emit_handlers () 384{ 385 if (catch_clauses) 386 { 387 rtx funcend = gen_label_rtx (); 388 emit_jump (funcend); 389 390 emit_insns (catch_clauses); 391 expand_leftover_cleanups (); 392 393 emit_label (funcend); 394 } 395} 396 397/* Resume executing at the statement immediately after the end of an 398 exception region. */ 399 400void 401expand_resume_after_catch () 402{ 403 expand_goto (top_label_entry (&caught_return_label_stack)); 404} 405