]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/java/except.c
genattrtab.c (write_header): Include hash-set.h...
[thirdparty/gcc.git] / gcc / java / except.c
1 /* Handle exceptions for GNU compiler for the Java(TM) language.
2 Copyright (C) 1997-2015 Free Software Foundation, Inc.
3
4 This file is part of GCC.
5
6 GCC is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
10
11 GCC is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING3. If not see
18 <http://www.gnu.org/licenses/>.
19
20 Java and all Java-based marks are trademarks or registered trademarks
21 of Sun Microsystems, Inc. in the United States and other countries.
22 The Free Software Foundation is independent of Sun Microsystems, Inc. */
23
24 #include "config.h"
25 #include "system.h"
26 #include "coretypes.h"
27 #include "tm.h"
28 #include "hash-set.h"
29 #include "machmode.h"
30 #include "vec.h"
31 #include "double-int.h"
32 #include "input.h"
33 #include "alias.h"
34 #include "symtab.h"
35 #include "wide-int.h"
36 #include "inchash.h"
37 #include "tree.h"
38 #include "fold-const.h"
39 #include "stringpool.h"
40 #include "stor-layout.h"
41 #include "java-tree.h"
42 #include "javaop.h"
43 #include "java-opcodes.h"
44 #include "jcf.h"
45 #include "java-except.h"
46 #include "diagnostic-core.h"
47 #include "toplev.h"
48 #include "tree-iterator.h"
49
50
51 static void expand_start_java_handler (struct eh_range *);
52 static struct eh_range *find_handler_in_range (int, struct eh_range *,
53 struct eh_range *);
54 static void check_start_handlers (struct eh_range *, int);
55 static void free_eh_ranges (struct eh_range *range);
56
57 struct eh_range *current_method_handlers;
58
59 struct eh_range *current_try_block = NULL;
60
61 /* These variables are used to speed up find_handler. */
62
63 static int cache_range_start, cache_range_end;
64 static struct eh_range *cache_range;
65 static struct eh_range *cache_next_child;
66
67 /* A dummy range that represents the entire method. */
68
69 struct eh_range whole_range;
70
71 /* Check the invariants of the structure we're using to contain
72 exception regions. Either returns true or fails an assertion
73 check. */
74
75 bool
76 sanity_check_exception_range (struct eh_range *range)
77 {
78 struct eh_range *ptr = range->first_child;
79 for (; ptr; ptr = ptr->next_sibling)
80 {
81 gcc_assert (ptr->outer == range
82 && ptr->end_pc > ptr->start_pc);
83 if (ptr->next_sibling)
84 gcc_assert (ptr->next_sibling->start_pc >= ptr->end_pc);
85 gcc_assert (ptr->start_pc >= ptr->outer->start_pc
86 && ptr->end_pc <= ptr->outer->end_pc);
87 (void) sanity_check_exception_range (ptr);
88 }
89 return true;
90 }
91
92 #if defined(DEBUG_JAVA_BINDING_LEVELS)
93 extern int is_class_level;
94 extern int current_pc;
95 extern int binding_depth;
96 extern void indent (void);
97 static void
98 print_ranges (struct eh_range *range)
99 {
100 if (! range)
101 return;
102
103 struct eh_range *child = range->first_child;
104
105 indent ();
106 fprintf (stderr, "handler pc %d --> %d ", range->start_pc, range->end_pc);
107
108 tree handler = range->handlers;
109 for ( ; handler != NULL_TREE; handler = TREE_CHAIN (handler))
110 {
111 tree type = TREE_PURPOSE (handler);
112 if (type == NULL)
113 type = throwable_type_node;
114 fprintf (stderr, " type=%s ", IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))));
115 }
116 fprintf (stderr, "\n");
117
118 int saved = binding_depth;
119 binding_depth++;
120 print_ranges (child);
121 binding_depth = saved;
122
123 print_ranges (range->next_sibling);
124 }
125 #endif
126
127 /* Search for the most specific eh_range containing PC.
128 Assume PC is within RANGE.
129 CHILD is a list of children of RANGE such that any
130 previous children have end_pc values that are too low. */
131
132 static struct eh_range *
133 find_handler_in_range (int pc, struct eh_range *range, struct eh_range *child)
134 {
135 for (; child != NULL; child = child->next_sibling)
136 {
137 if (pc < child->start_pc)
138 break;
139 if (pc < child->end_pc)
140 return find_handler_in_range (pc, child, child->first_child);
141 }
142 cache_range = range;
143 cache_range_start = pc;
144 cache_next_child = child;
145 cache_range_end = child == NULL ? range->end_pc : child->start_pc;
146 return range;
147 }
148
149 /* Find the inner-most handler that contains PC. */
150
151 struct eh_range *
152 find_handler (int pc)
153 {
154 struct eh_range *h;
155 if (pc >= cache_range_start)
156 {
157 h = cache_range;
158 if (pc < cache_range_end)
159 return h;
160 while (pc >= h->end_pc)
161 {
162 cache_next_child = h->next_sibling;
163 h = h->outer;
164 }
165 }
166 else
167 {
168 h = &whole_range;
169 cache_next_child = h->first_child;
170 }
171 return find_handler_in_range (pc, h, cache_next_child);
172 }
173
174 static void
175 free_eh_ranges (struct eh_range *range)
176 {
177 while (range)
178 {
179 struct eh_range *next = range->next_sibling;
180 free_eh_ranges (range->first_child);
181 if (range != &whole_range)
182 free (range);
183 range = next;
184 }
185 }
186
187 /* Called to re-initialize the exception machinery for a new method. */
188
189 void
190 method_init_exceptions (void)
191 {
192 free_eh_ranges (&whole_range);
193 whole_range.start_pc = 0;
194 whole_range.end_pc = DECL_CODE_LENGTH (current_function_decl) + 1;
195 whole_range.outer = NULL;
196 whole_range.first_child = NULL;
197 whole_range.next_sibling = NULL;
198 cache_range_start = 0xFFFFFF;
199 }
200
201 /* Split an exception range into two at PC. The sub-ranges that
202 belong to the range are split and distributed between the two new
203 ranges. */
204
205 static void
206 split_range (struct eh_range *range, int pc)
207 {
208 struct eh_range *ptr;
209 struct eh_range **first_child, **second_child;
210 struct eh_range *h;
211
212 /* First, split all the sub-ranges. */
213 for (ptr = range->first_child; ptr; ptr = ptr->next_sibling)
214 {
215 if (pc > ptr->start_pc
216 && pc < ptr->end_pc)
217 {
218 split_range (ptr, pc);
219 }
220 }
221
222 /* Create a new range. */
223 h = XNEW (struct eh_range);
224
225 h->start_pc = pc;
226 h->end_pc = range->end_pc;
227 h->next_sibling = range->next_sibling;
228 range->next_sibling = h;
229 range->end_pc = pc;
230 h->handlers = build_tree_list (TREE_PURPOSE (range->handlers),
231 TREE_VALUE (range->handlers));
232 h->next_sibling = NULL;
233 h->expanded = 0;
234 h->stmt = NULL;
235 h->outer = range->outer;
236 h->first_child = NULL;
237
238 ptr = range->first_child;
239 first_child = &range->first_child;
240 second_child = &h->first_child;
241
242 /* Distribute the sub-ranges between the two new ranges. */
243 for (ptr = range->first_child; ptr; ptr = ptr->next_sibling)
244 {
245 if (ptr->start_pc < pc)
246 {
247 *first_child = ptr;
248 ptr->outer = range;
249 first_child = &ptr->next_sibling;
250 }
251 else
252 {
253 *second_child = ptr;
254 ptr->outer = h;
255 second_child = &ptr->next_sibling;
256 }
257 }
258 *first_child = NULL;
259 *second_child = NULL;
260 }
261
262
263 /* Add an exception range.
264
265 There are some missed optimization opportunities here. For
266 example, some bytecode obfuscators generate seemingly
267 nonoverlapping exception ranges which, when coalesced, do in fact
268 nest correctly. We could merge these, but we'd have to fix up all
269 the enclosed regions first and perhaps create a new range anyway if
270 it overlapped existing ranges.
271
272 Also, we don't attempt to detect the case where two previously
273 added disjoint ranges could be coalesced by a new range. */
274
275 void
276 add_handler (int start_pc, int end_pc, tree handler, tree type)
277 {
278 struct eh_range *ptr, *h;
279 struct eh_range **first_child, **prev;
280
281 /* First, split all the existing ranges that we need to enclose. */
282 for (ptr = whole_range.first_child; ptr; ptr = ptr->next_sibling)
283 {
284 if (start_pc > ptr->start_pc
285 && start_pc < ptr->end_pc)
286 {
287 split_range (ptr, start_pc);
288 }
289
290 if (end_pc > ptr->start_pc
291 && end_pc < ptr->end_pc)
292 {
293 split_range (ptr, end_pc);
294 }
295
296 if (ptr->start_pc >= end_pc)
297 break;
298 }
299
300 /* Create the new range. */
301 h = XNEW (struct eh_range);
302 first_child = &h->first_child;
303
304 h->start_pc = start_pc;
305 h->end_pc = end_pc;
306 h->first_child = NULL;
307 h->outer = NULL_EH_RANGE;
308 h->handlers = build_tree_list (type, handler);
309 h->next_sibling = NULL;
310 h->expanded = 0;
311 h->stmt = NULL;
312
313 /* Find every range at the top level that will be a sub-range of the
314 range we're inserting and make it so. */
315 {
316 struct eh_range **prev = &whole_range.first_child;
317 for (ptr = *prev; ptr;)
318 {
319 struct eh_range *next = ptr->next_sibling;
320
321 if (ptr->start_pc >= end_pc)
322 break;
323
324 if (ptr->start_pc < start_pc)
325 {
326 prev = &ptr->next_sibling;
327 }
328 else if (ptr->start_pc >= start_pc
329 && ptr->start_pc < end_pc)
330 {
331 *prev = next;
332 *first_child = ptr;
333 first_child = &ptr->next_sibling;
334 ptr->outer = h;
335 ptr->next_sibling = NULL;
336 }
337
338 ptr = next;
339 }
340 }
341
342 /* Find the right place to insert the new range. */
343 prev = &whole_range.first_child;
344 for (ptr = *prev; ptr; prev = &ptr->next_sibling, ptr = ptr->next_sibling)
345 {
346 gcc_assert (ptr->outer == NULL_EH_RANGE);
347 if (ptr->start_pc >= start_pc)
348 break;
349 }
350
351 /* And insert it there. */
352 *prev = h;
353 if (ptr)
354 {
355 h->next_sibling = ptr;
356 h->outer = ptr->outer;
357 }
358 }
359
360
361 /* if there are any handlers for this range, issue start of region */
362 static void
363 expand_start_java_handler (struct eh_range *range)
364 {
365 #if defined(DEBUG_JAVA_BINDING_LEVELS)
366 indent ();
367 fprintf (stderr, "expand start handler pc %d --> %d\n",
368 current_pc, range->end_pc);
369 #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
370 pushlevel (0);
371 register_exception_range (range, range->start_pc, range->end_pc);
372 range->expanded = 1;
373 }
374
375 tree
376 prepare_eh_table_type (tree type)
377 {
378 tree exp;
379 tree *slot;
380 const char *name;
381 char *buf;
382 tree decl;
383 tree utf8_ref;
384
385 /* The "type" (match_info) in a (Java) exception table is a pointer to:
386 * a) NULL - meaning match any type in a try-finally.
387 * b) a pointer to a pointer to a class.
388 * c) a pointer to a pointer to a utf8_ref. The pointer is
389 * rewritten to point to the appropriate class. */
390
391 if (type == NULL_TREE)
392 return NULL_TREE;
393
394 if (TYPE_TO_RUNTIME_MAP (output_class) == NULL)
395 TYPE_TO_RUNTIME_MAP (output_class) = java_treetreehash_create (10);
396
397 slot = java_treetreehash_new (TYPE_TO_RUNTIME_MAP (output_class), type);
398 if (*slot != NULL)
399 return TREE_VALUE (*slot);
400
401 if (is_compiled_class (type) && !flag_indirect_dispatch)
402 {
403 name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
404 buf = (char *) alloca (strlen (name) + 5);
405 sprintf (buf, "%s_ref", name);
406 decl = build_decl (input_location,
407 VAR_DECL, get_identifier (buf), ptr_type_node);
408 TREE_STATIC (decl) = 1;
409 DECL_ARTIFICIAL (decl) = 1;
410 DECL_IGNORED_P (decl) = 1;
411 TREE_READONLY (decl) = 1;
412 TREE_THIS_VOLATILE (decl) = 0;
413 DECL_INITIAL (decl) = build_class_ref (type);
414 layout_decl (decl, 0);
415 pushdecl (decl);
416 exp = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (decl)), decl);
417 }
418 else
419 {
420 utf8_ref = build_utf8_ref (DECL_NAME (TYPE_NAME (type)));
421 name = IDENTIFIER_POINTER (DECL_NAME (TREE_OPERAND (utf8_ref, 0)));
422 buf = (char *) alloca (strlen (name) + 5);
423 sprintf (buf, "%s_ref", name);
424 decl = build_decl (input_location,
425 VAR_DECL, get_identifier (buf), utf8const_ptr_type);
426 TREE_STATIC (decl) = 1;
427 DECL_ARTIFICIAL (decl) = 1;
428 DECL_IGNORED_P (decl) = 1;
429 TREE_READONLY (decl) = 1;
430 TREE_THIS_VOLATILE (decl) = 0;
431 layout_decl (decl, 0);
432 pushdecl (decl);
433 exp = build1 (ADDR_EXPR, build_pointer_type (utf8const_ptr_type), decl);
434 CONSTRUCTOR_APPEND_ELT (TYPE_CATCH_CLASSES (output_class),
435 NULL_TREE,
436 make_catch_class_record (exp, utf8_ref));
437 }
438
439 exp = convert (ptr_type_node, exp);
440
441 *slot = tree_cons (type, exp, NULL_TREE);
442
443 return exp;
444 }
445
446 int
447 expand_catch_class (treetreehash_entry **entry, int)
448 {
449 struct treetreehash_entry *ite = *entry;
450 tree addr = TREE_VALUE ((tree)ite->value);
451 tree decl;
452 STRIP_NOPS (addr);
453 decl = TREE_OPERAND (addr, 0);
454 rest_of_decl_compilation (decl, global_bindings_p (), 0);
455 return true;
456 }
457
458 /* For every class in the TYPE_TO_RUNTIME_MAP, expand the
459 corresponding object that is used by the runtime type matcher. */
460
461 void
462 java_expand_catch_classes (tree this_class)
463 {
464 if (TYPE_TO_RUNTIME_MAP (this_class))
465 TYPE_TO_RUNTIME_MAP (this_class)->traverse<int, expand_catch_class> (0);
466 }
467
468 /* Build and push the variable that will hold the exception object
469 within this function. */
470
471 static tree
472 build_exception_object_var (void)
473 {
474 tree decl = DECL_FUNCTION_EXC_OBJ (current_function_decl);
475 if (decl == NULL)
476 {
477 decl = build_decl (DECL_SOURCE_LOCATION (current_function_decl),
478 VAR_DECL, get_identifier ("#exc_obj"), ptr_type_node);
479 DECL_IGNORED_P (decl) = 1;
480 DECL_ARTIFICIAL (decl) = 1;
481
482 DECL_FUNCTION_EXC_OBJ (current_function_decl) = decl;
483 pushdecl_function_level (decl);
484 }
485 return decl;
486 }
487
488 /* Build a reference to the jthrowable object being carried in the
489 exception header. */
490
491 tree
492 build_exception_object_ref (tree type)
493 {
494 tree obj;
495
496 /* Java only passes object via pointer and doesn't require adjusting.
497 The java object is immediately before the generic exception header. */
498 obj = build_exception_object_var ();
499 obj = fold_convert (build_pointer_type (type), obj);
500 obj = fold_build_pointer_plus (obj,
501 fold_build1 (NEGATE_EXPR, sizetype,
502 TYPE_SIZE_UNIT (TREE_TYPE (obj))));
503 obj = build1 (INDIRECT_REF, type, obj);
504
505 return obj;
506 }
507
508 /* If there are any handlers for this range, issue end of range,
509 and then all handler blocks */
510 void
511 expand_end_java_handler (struct eh_range *range)
512 {
513 tree handler = range->handlers;
514 if (handler)
515 {
516 tree exc_obj = build_exception_object_var ();
517 tree catches = make_node (STATEMENT_LIST);
518 tree_stmt_iterator catches_i = tsi_last (catches);
519 tree *body;
520
521 for (; handler; handler = TREE_CHAIN (handler))
522 {
523 tree type, eh_type, x;
524 tree stmts = make_node (STATEMENT_LIST);
525 tree_stmt_iterator stmts_i = tsi_last (stmts);
526
527 type = TREE_PURPOSE (handler);
528 if (type == NULL)
529 type = throwable_type_node;
530 eh_type = prepare_eh_table_type (type);
531
532 x = build_call_expr (builtin_decl_explicit (BUILT_IN_EH_POINTER),
533 1, integer_zero_node);
534 x = build2 (MODIFY_EXPR, void_type_node, exc_obj, x);
535 tsi_link_after (&stmts_i, x, TSI_CONTINUE_LINKING);
536
537 x = build1 (GOTO_EXPR, void_type_node, TREE_VALUE (handler));
538 tsi_link_after (&stmts_i, x, TSI_CONTINUE_LINKING);
539
540 x = build2 (CATCH_EXPR, void_type_node, eh_type, stmts);
541 tsi_link_after (&catches_i, x, TSI_CONTINUE_LINKING);
542
543 /* Throwable can match anything in Java, and therefore
544 any subsequent handlers are unreachable. */
545 /* ??? If we're assured of no foreign language exceptions,
546 we'd be better off using NULL as the exception type
547 for the catch. */
548 if (type == throwable_type_node)
549 break;
550 }
551
552 body = get_stmts ();
553 *body = build2 (TRY_CATCH_EXPR, void_type_node, *body, catches);
554 }
555
556 #if defined(DEBUG_JAVA_BINDING_LEVELS)
557 indent ();
558 fprintf (stderr, "expand end handler pc %d <-- %d\n",
559 current_pc, range->start_pc);
560 #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
561 }
562
563 /* Recursive helper routine for maybe_start_handlers. */
564
565 static void
566 check_start_handlers (struct eh_range *range, int pc)
567 {
568 if (range != NULL_EH_RANGE && range->start_pc == pc)
569 {
570 check_start_handlers (range->outer, pc);
571 if (!range->expanded)
572 expand_start_java_handler (range);
573 }
574 }
575
576
577 /* Routine to see if exception handling is turned on.
578 DO_WARN is nonzero if we want to inform the user that exception
579 handling is turned off.
580
581 This is used to ensure that -fexceptions has been specified if the
582 compiler tries to use any exception-specific functions. */
583
584 static inline int
585 doing_eh (void)
586 {
587 if (! flag_exceptions)
588 {
589 static int warned = 0;
590 if (! warned)
591 {
592 error ("exception handling disabled, use -fexceptions to enable");
593 warned = 1;
594 }
595 return 0;
596 }
597 return 1;
598 }
599
600 static struct eh_range *current_range;
601
602 /* Emit any start-of-try-range starting at start_pc and ending after
603 end_pc. */
604
605 void
606 maybe_start_try (int start_pc, int end_pc)
607 {
608 struct eh_range *range;
609 if (! doing_eh ())
610 return;
611
612 range = find_handler (start_pc);
613 while (range != NULL_EH_RANGE && range->start_pc == start_pc
614 && range->end_pc < end_pc)
615 range = range->outer;
616
617 current_range = range;
618 check_start_handlers (range, start_pc);
619 }
620