#include "config.h"
#include "system.h"
#include "tree.h"
#include "real.h"
#include "rtl.h"
#include "java-tree.h"
#include "javaop.h"
#include "java-opcodes.h"
#include "jcf.h"
#include "function.h"
#include "except.h"
#include "java-except.h"
#include "toplev.h"
static void expand_start_java_handler PARAMS ((struct eh_range *));
static void expand_end_java_handler PARAMS ((struct eh_range *));
static struct eh_range *find_handler_in_range PARAMS ((int, struct eh_range *,
struct eh_range *));
static void link_handler PARAMS ((struct eh_range *, struct eh_range *));
static void check_start_handlers PARAMS ((struct eh_range *, int));
static void free_eh_ranges PARAMS ((struct eh_range *range));
struct eh_range *current_method_handlers;
struct eh_range *current_try_block = NULL;
struct eh_range *eh_range_freelist = NULL;
static int cache_range_start, cache_range_end;
static struct eh_range *cache_range;
static struct eh_range *cache_next_child;
struct eh_range whole_range;
#if defined(DEBUG_JAVA_BINDING_LEVELS)
extern int binding_depth;
extern int is_class_level;
extern int current_pc;
extern void indent ();
#endif
static struct eh_range *
find_handler_in_range (pc, range, child)
int pc;
struct eh_range *range;
register struct eh_range *child;
{
for (; child != NULL; child = child->next_sibling)
{
if (pc < child->start_pc)
break;
if (pc < child->end_pc)
return find_handler_in_range (pc, child, child->first_child);
}
cache_range = range;
cache_range_start = pc;
cache_next_child = child;
cache_range_end = child == NULL ? range->end_pc : child->start_pc;
return range;
}
struct eh_range *
find_handler (pc)
int pc;
{
struct eh_range *h;
if (pc >= cache_range_start)
{
h = cache_range;
if (pc < cache_range_end)
return h;
while (pc >= h->end_pc)
{
cache_next_child = h->next_sibling;
h = h->outer;
}
}
else
{
h = &whole_range;
cache_next_child = h->first_child;
}
return find_handler_in_range (pc, h, cache_next_child);
}
static void
link_handler (range, outer)
struct eh_range *range, *outer;
{
struct eh_range **ptr;
if (range->start_pc == outer->start_pc && range->end_pc == outer->end_pc)
{
outer->handlers = chainon (outer->handlers, range->handlers);
return;
}
if (range->start_pc <= outer->start_pc && range->end_pc >= outer->end_pc)
{
range->outer = outer->outer;
range->next_sibling = NULL;
range->first_child = outer;
{
struct eh_range **pr = &(outer->outer->first_child);
while (*pr != outer)
pr = &(*pr)->next_sibling;
*pr = range;
}
outer->outer = range;
return;
}
if (range->start_pc < outer->start_pc || range->end_pc > outer->end_pc)
{
struct eh_range *h = xmalloc (sizeof (struct eh_range));
if (range->start_pc < outer->start_pc)
{
h->start_pc = range->start_pc;
h->end_pc = outer->start_pc;
range->start_pc = outer->start_pc;
}
else
{
h->start_pc = outer->end_pc;
h->end_pc = range->end_pc;
range->end_pc = outer->end_pc;
}
h->first_child = NULL;
h->outer = NULL;
h->handlers = build_tree_list (TREE_PURPOSE (range->handlers),
TREE_VALUE (range->handlers));
h->next_sibling = NULL;
h->expanded = 0;
link_handler (h, &whole_range);
link_handler (range, &whole_range);
return;
}
ptr = &outer->first_child;
for (;; ptr = &(*ptr)->next_sibling)
{
if (*ptr == NULL || range->end_pc <= (*ptr)->start_pc)
{
range->next_sibling = *ptr;
range->first_child = NULL;
range->outer = outer;
*ptr = range;
return;
}
else if (range->start_pc < (*ptr)->end_pc)
{
link_handler (range, *ptr);
return;
}
}
}
void
handle_nested_ranges ()
{
struct eh_range *ptr, *next;
ptr = whole_range.first_child;
whole_range.first_child = NULL;
for (; ptr; ptr = next)
{
next = ptr->next_sibling;
ptr->next_sibling = NULL;
link_handler (ptr, &whole_range);
}
}
static void
free_eh_ranges (range)
struct eh_range *range;
{
while (range)
{
struct eh_range *next = range->next_sibling;
free_eh_ranges (range->first_child);
if (range != &whole_range)
free (range);
range = next;
}
}
void
method_init_exceptions ()
{
free_eh_ranges (&whole_range);
whole_range.start_pc = 0;
whole_range.end_pc = DECL_CODE_LENGTH (current_function_decl) + 1;
whole_range.outer = NULL;
whole_range.first_child = NULL;
whole_range.next_sibling = NULL;
cache_range_start = 0xFFFFFF;
}
void
add_handler (start_pc, end_pc, handler, type)
int start_pc, end_pc;
tree handler;
tree type;
{
struct eh_range *ptr, *prev = NULL, *h;
for (ptr = whole_range.first_child; ptr; ptr = ptr->next_sibling)
{
if (start_pc >= ptr->start_pc
&& start_pc <= ptr->end_pc
&& TREE_PURPOSE (ptr->handlers) == type
&& TREE_VALUE (ptr->handlers) == handler)
{
ptr->end_pc = MAX (ptr->end_pc, end_pc);
return;
}
prev = ptr;
}
h = xmalloc (sizeof (struct eh_range));
h->start_pc = start_pc;
h->end_pc = end_pc;
h->first_child = NULL;
h->outer = NULL;
h->handlers = build_tree_list (type, handler);
h->next_sibling = NULL;
h->expanded = 0;
if (prev == NULL)
whole_range.first_child = h;
else
prev->next_sibling = h;
}
static void
expand_start_java_handler (range)
struct eh_range *range;
{
#if defined(DEBUG_JAVA_BINDING_LEVELS)
indent ();
fprintf (stderr, "expand start handler pc %d --> %d\n",
current_pc, range->end_pc);
#endif
range->expanded = 1;
expand_eh_region_start ();
}
tree
prepare_eh_table_type (type)
tree type;
{
tree exp;
if (type == NULL_TREE)
exp = NULL_TREE;
else if (is_compiled_class (type))
exp = build_class_ref (type);
else
exp = fold (build
(PLUS_EXPR, ptr_type_node,
build_utf8_ref (build_internal_class_name (type)),
size_one_node));
return exp;
}
tree
build_exception_object_ref (type)
tree type;
{
tree obj;
obj = build (EXC_PTR_EXPR, build_pointer_type (type));
obj = build (MINUS_EXPR, TREE_TYPE (obj), obj,
TYPE_SIZE_UNIT (TREE_TYPE (obj)));
obj = build1 (INDIRECT_REF, type, obj);
return obj;
}
static void
expand_end_java_handler (range)
struct eh_range *range;
{
tree handler = range->handlers;
force_poplevels (range->start_pc);
expand_start_all_catch ();
for ( ; handler != NULL_TREE; handler = TREE_CHAIN (handler))
{
tree type = TREE_PURPOSE (handler);
if (type == NULL)
type = throwable_type_node;
expand_start_catch (type);
expand_goto (TREE_VALUE (handler));
expand_end_catch ();
}
expand_end_all_catch ();
#if defined(DEBUG_JAVA_BINDING_LEVELS)
indent ();
fprintf (stderr, "expand end handler pc %d <-- %d\n",
current_pc, range->start_pc);
#endif
}
static void
check_start_handlers (range, pc)
struct eh_range *range;
int pc;
{
if (range != NULL_EH_RANGE && range->start_pc == pc)
{
check_start_handlers (range->outer, pc);
if (!range->expanded)
expand_start_java_handler (range);
}
}
static struct eh_range *current_range;
void
maybe_start_try (start_pc, end_pc)
int start_pc;
int end_pc;
{
struct eh_range *range;
if (! doing_eh (1))
return;
range = find_handler (start_pc);
while (range != NULL_EH_RANGE && range->start_pc == start_pc
&& range->end_pc < end_pc)
range = range->outer;
current_range = range;
check_start_handlers (range, start_pc);
}
void
maybe_end_try (start_pc, end_pc)
int start_pc;
int end_pc;
{
if (! doing_eh (1))
return;
while (current_range != NULL_EH_RANGE && current_range->end_pc <= end_pc
&& current_range->start_pc >= start_pc)
{
expand_end_java_handler (current_range);
current_range = current_range->outer;
}
}