OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [gcc/] [java/] [except.c] - Blame information for rev 744

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.