1/* Handle exceptions for GNU compiler for the Java(TM) language.
2   Copyright (C) 1997-2015 Free Software Foundation, Inc.
3
4This file is part of GCC.
5
6GCC 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 3, or (at your option)
9any later version.
10
11GCC 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 GCC; see the file COPYING3.  If not see
18<http://www.gnu.org/licenses/>.
19
20Java and all Java-based marks are trademarks or registered trademarks
21of Sun Microsystems, Inc. in the United States and other countries.
22The 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
51static void expand_start_java_handler (struct eh_range *);
52static struct eh_range *find_handler_in_range (int, struct eh_range *,
53					       struct eh_range *);
54static void check_start_handlers (struct eh_range *, int);
55static void free_eh_ranges (struct eh_range *range);
56
57struct eh_range *current_method_handlers;
58
59struct eh_range *current_try_block = NULL;
60
61/* These variables are used to speed up find_handler. */
62
63static int cache_range_start, cache_range_end;
64static struct eh_range *cache_range;
65static struct eh_range *cache_next_child;
66
67/* A dummy range that represents the entire method. */
68
69struct 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
75bool
76sanity_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)
93extern int is_class_level;
94extern int current_pc;
95extern int binding_depth;
96extern void indent (void);
97static void
98print_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
132static struct eh_range *
133find_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
151struct eh_range *
152find_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
174static void
175free_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
189void
190method_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
205static void
206split_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
275void
276add_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 */
362static void
363expand_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
375tree
376prepare_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
446int
447expand_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
461void
462java_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
471static tree
472build_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
491tree
492build_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 */
510void
511expand_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
565static void
566check_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
584static inline int
585doing_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
600static struct eh_range *current_range;
601
602/* Emit any start-of-try-range starting at start_pc and ending after
603   end_pc. */
604
605void
606maybe_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
621