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

Subversion Repositories openrisc

[/] [openrisc/] [tags/] [gnu-src/] [gcc-4.5.1/] [gcc-4.5.1-or32-1.0rc3/] [gcc/] [java/] [except.c] - Blame information for rev 855

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

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

powered by: WebSVN 2.1.0

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