+2000-01-25 Andrew Haley <aph@cygnus.com>
+
+ * java-except.h (struct eh_range): Add `expanded' field.
+ (maybe_start_try): Add end_pc arg.
+ (maybe_end_try): Ditto.
+ * java-tree.h (force_poplevels): new function.
+ * expr.c (expand_byte_code): Don't call maybe_start_try or
+ maybe_end_try.
+ * except.c (add_handler): Reset expanded.
+ (expand_start_java_handler): Set expanded.
+ (check_start_handlers): Don't expand a start handler that's
+ already been expanded.
+ (maybe_start_try): Add end_pc arg. Only expand a handler which
+ ends after end_pc.
+ (expand_end_java_handler): call force_poplevels.
+ (force_poplevels): new function.
+ * decl.c (binding_level): Add start_pc of binding level.
+ (maybe_pushlevels): Call maybe_start_try when pushing binding
+ levels.
+ (maybe_poplevels): Call maybe_end_try when popping binding levels.
+ (LARGEST_PC): Define.
+ (clear_binding_level): Use LARGEST_PC.
+
+ * java-tree.h (DEBUG_JAVA_BINDING_LEVELS): new define.
+ * decl.c (DEBUG_JAVA_BINDING_LEVELS): new define.
+ (binding_depth, is_class_level, current_pc): new variables.
+ (struct binding_level): ditto.
+ (indent): new function.
+ (push_jvm_slot): add debugging info.
+ (maybe_pushlevels): ditto.
+ (maybe_poplevels): ditto.
+ (pushlevel): ditto.
+ (poplevel): ditto.
+ (start_java_method): ditto.
+ (give_name_to_locals): comment only.
+ * except.c (binding_depth, is_class_level, current_pc):
+ new variables.
+ (expand_start_java_handler): add debugging info.
+ (expand_end_java_handler): ditto.
+
2000-02-05 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
* gjavah.c (overloaded_jni_method_exists_p): Add prototype.
#include "config.h"
#include "system.h"
#include "tree.h"
+#include "toplev.h"
+#include "flags.h"
#include "java-tree.h"
#include "jcf.h"
#include "toplev.h"
#include "function.h"
#include "except.h"
#include "defaults.h"
+#include "java-except.h"
+
+#if defined (DEBUG_JAVA_BINDING_LEVELS)
+extern void indent PROTO((void));
+#endif
static tree push_jvm_slot PARAMS ((int, tree));
static tree lookup_name_current_level PARAMS ((tree));
/* Push a local variable or stack slot into the decl_map,
and assign it an rtl. */
+#if defined(DEBUG_JAVA_BINDING_LEVELS)
+int binding_depth = 0;
+int is_class_level = 0;
+int current_pc;
+
+void
+indent ()
+{
+ register unsigned i;
+
+ for (i = 0; i < binding_depth*2; i++)
+ putc (' ', stderr);
+}
+#endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
+
static tree
push_jvm_slot (index, decl)
int index;
/* The bytecode PC that marks the end of this level. */
int end_pc;
+ int start_pc;
+
+#if defined(DEBUG_JAVA_BINDING_LEVELS)
+ /* Binding depth at which this level began. */
+ unsigned binding_depth;
+#endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
};
#define NULL_BINDING_LEVEL (struct binding_level *) NULL
static struct binding_level *global_binding_level;
+/* A PC value bigger than any PC value we may ever may encounter. */
+
+#define LARGEST_PC (( (unsigned int)1 << (HOST_BITS_PER_INT - 1)) - 1)
+
/* Binding level structures are initialized by copying this one. */
static struct binding_level clear_binding_level
= {NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE,
- NULL_BINDING_LEVEL, 0, 0, 0, 0, 1000000000};
+ NULL_BINDING_LEVEL, 0, 0, 0, 0, LARGEST_PC, 0, 0};
#if 0
/* A list (chain of TREE_LIST nodes) of all LABEL_DECLs in the function
keep_next_level_flag = 0;
newlevel->keep_if_subblocks = keep_next_if_subblocks;
keep_next_if_subblocks = 0;
+#if defined(DEBUG_JAVA_BINDING_LEVELS)
+ newlevel->binding_depth = binding_depth;
+ indent ();
+ fprintf (stderr, "push %s level 0x%08x pc %d\n",
+ (is_class_level) ? "class" : "block", newlevel, current_pc);
+ is_class_level = 0;
+ binding_depth++;
+#endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
}
/* Exit a binding level.
tree decl;
int block_previously_created;
+#if defined(DEBUG_JAVA_BINDING_LEVELS)
+ binding_depth--;
+ indent ();
+ if (current_binding_level->end_pc != LARGEST_PC)
+ fprintf (stderr, "pop %s level 0x%08x pc %d (end pc %d)\n",
+ (is_class_level) ? "class" : "block", current_binding_level, current_pc,
+ current_binding_level->end_pc);
+ else
+ fprintf (stderr, "pop %s level 0x%08x pc %d\n",
+ (is_class_level) ? "class" : "block", current_binding_level, current_pc);
+#if 0
+ if (is_class_level != (current_binding_level == class_binding_level))
+ {
+ indent ();
+ fprintf (stderr, "XXX is_class_level != (current_binding_level == class_binding_level)\n");
+ }
+ is_class_level = 0;
+#endif
+#endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
+
keep |= current_binding_level->keep;
/* Get the decls in the order they were written.
maybe_pushlevels (pc)
int pc;
{
+#if defined(DEBUG_JAVA_BINDING_LEVELS)
+ current_pc = pc;
+#endif
+
while (pending_local_decls != NULL_TREE &&
DECL_LOCAL_START_PC (pending_local_decls) <= pc)
{
if (end_pc > current_binding_level->end_pc)
end_pc = current_binding_level->end_pc;
+ maybe_start_try (pc, end_pc);
+
pushlevel (1);
expand_start_bindings (0);
+
current_binding_level->end_pc = end_pc;
-
+ current_binding_level->start_pc = pc;
current_binding_level->names = decl;
for ( ; decl != NULL_TREE; decl = TREE_CHAIN (decl))
{
push_jvm_slot (DECL_LOCAL_SLOT_NUMBER (decl), decl);
}
- }
+ }
+
+ maybe_start_try (pc, 0);
}
void
maybe_poplevels (pc)
int pc;
{
+#if defined(DEBUG_JAVA_BINDING_LEVELS)
+ current_pc = pc;
+#endif
+
while (current_binding_level->end_pc <= pc)
{
+ tree decls = getdecls ();
+ expand_end_bindings (getdecls (), 1, 0);
+ maybe_end_try (current_binding_level->start_pc, pc);
+ poplevel (1, 0, 0);
+ }
+ maybe_end_try (0, pc);
+}
+
+/* Terminate any binding which began during the range beginning at
+ start_pc. This tidies up improperly nested local variable ranges
+ and exception handlers; a variable declared within an exception
+ range is forcibly terminated when that exception ends. */
+
+void
+force_poplevels (start_pc)
+ int start_pc;
+{
+ while (current_binding_level->start_pc > start_pc)
+ {
+ tree decls = getdecls ();
+ if (pedantic && current_binding_level->start_pc > start_pc)
+ warning_with_decl (current_function_decl,
+ "In %s: overlapped variable and exception ranges at %d",
+ current_binding_level->start_pc);
expand_end_bindings (getdecls (), 1, 0);
poplevel (1, 0, 0);
}
= (struct lang_decl *) permalloc (sizeof (struct lang_decl_var));
DECL_LOCAL_SLOT_NUMBER (decl) = slot;
DECL_LOCAL_START_PC (decl) = start_pc;
+#if 0
+ /* FIXME: The range used internally for exceptions and local
+ variable ranges, is a half-open interval:
+ start_pc <= pc < end_pc. However, the range used in the
+ Java VM spec is inclusive at both ends:
+ start_pc <= pc <= end_pc. */
+ end_pc++;
+#endif
DECL_LOCAL_END_PC (decl) = end_pc;
/* Now insert the new decl in the proper place in
decl_map = make_tree_vec (i);
type_map = (tree *) oballoc (i * sizeof (tree));
+#if defined(DEBUG_JAVA_BINDING_LEVELS)
+ fprintf (stderr, "%s:\n", (*decl_printable_name) (fndecl, 2));
+ current_pc = 0;
+#endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
pushlevel (1); /* Push parameters. */
ptr = &DECL_ARGUMENTS (fndecl);
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));
extern struct obstack permanent_obstack;
struct eh_range whole_range;
+#if defined(DEBUG_JAVA_BINDING_LEVELS)
+int binding_depth;
+int is_class_level;
+int current_pc;
+extern void indent ();
+
+#endif
+
/* Search for the most specific eh_range containing PC.
Assume PC is within RANGE.
CHILD is a list of children of RANGE such that any
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;
/* if there are any handlers for this range, issue start of region */
static void
expand_start_java_handler (range)
- struct eh_range *range ATTRIBUTE_UNUSED;
+ 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 /* defined(DEBUG_JAVA_BINDING_LEVELS) */
+ range->expanded = 1;
push_obstacks (&permanent_obstack, &permanent_obstack);
expand_eh_region_start ();
pop_obstacks ();
static void
expand_end_java_handler (range)
struct eh_range *range;
-{
+{
tree handler = range->handlers;
+ force_poplevels (range->start_pc);
push_obstacks (&permanent_obstack, &permanent_obstack);
expand_start_all_catch ();
pop_obstacks ();
end_catch_handler ();
}
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 /* defined(DEBUG_JAVA_BINDING_LEVELS) */
}
/* Recursive helper routine for maybe_start_handlers. */
if (range != NULL_EH_RANGE && range->start_pc == pc)
{
check_start_handlers (range->outer, pc);
- expand_start_java_handler (range);
+ if (!range->expanded)
+ expand_start_java_handler (range);
}
}
-struct eh_range *current_range;
-/* Emit any start-of-try-range start at PC. */
+static struct eh_range *current_range;
+
+/* Emit any start-of-try-range starting at start_pc and ending after
+ end_pc. */
void
-maybe_start_try (pc)
- int pc;
+maybe_start_try (start_pc, end_pc)
+ int start_pc;
+ int end_pc;
{
+ struct eh_range *range;
if (! doing_eh (1))
return;
- current_range = find_handler (pc);
- check_start_handlers (current_range, pc);
+ 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, end_pc);
}
-/* Emit any end-of-try-range end at PC. */
+/* Emit any end-of-try-range ending at end_pc and starting before
+ start_pc. */
void
-maybe_end_try (pc)
- int pc;
+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 <= pc)
+ 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;
}
}
}
- maybe_start_try (PC);
maybe_pushlevels (PC);
-
PC = process_jvm_instruction (PC, byte_ops, length);
-
maybe_poplevels (PC);
- maybe_end_try (PC);
} /* for */
if (dead_code_index != -1)
/* The next child of outer, in address order. */
struct eh_range *next_sibling;
+
+ /* True if this range has already been expanded. */
+ int expanded;
};
/* A dummy range that represents the entire method. */
extern void emit_handlers PARAMS ((void));
-extern void maybe_start_try PARAMS ((int));
+extern void maybe_start_try PARAMS ((int, int));
-extern void maybe_end_try PARAMS ((int));
+extern void maybe_end_try PARAMS ((int, int));
extern void add_handler PARAMS ((int, int, tree, tree));
extern int verify_jvm_instructions PARAMS ((struct JCF *, const unsigned char *, long));
extern void maybe_pushlevels PARAMS ((int));
extern void maybe_poplevels PARAMS ((int));
+extern void force_poplevels PARAMS ((int));
extern int process_jvm_instruction PARAMS ((int, const unsigned char *, long));
extern void set_local_type PARAMS ((int, tree));
extern int merge_type_state PARAMS ((tree));
if (java_error_count > save_error_count) \
return; \
}
+
+#undef DEBUG_JAVA_BINDING_LEVELS