/* Handle verification of bytecoded methods for the GNU compiler for
the Java(TM) language.
- Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003
+ Free Software Foundation, Inc.
-This file is part of GNU CC.
+This file is part of GCC.
-GNU CC is free software; you can redistribute it and/or modify
+GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-GNU CC is distributed in the hope that it will be useful,
+GCC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING. If not, write to
+along with GCC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
#include "config.h"
#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
#include "tree.h"
#include "java-tree.h"
#include "javaop.h"
#include "java-except.h"
#include "toplev.h"
-static void push_pending_label PARAMS ((tree));
-static tree merge_types PARAMS ((tree, tree));
-static const char *check_pending_block PARAMS ((tree));
-static void type_stack_dup PARAMS ((int, int));
-static int start_pc_cmp PARAMS ((const PTR, const PTR));
-static char *pop_argument_types PARAMS ((tree));
+static void push_pending_label (tree);
+static tree merge_types (tree, tree);
+static const char *check_pending_block (tree);
+static void type_stack_dup (int, int);
+static int start_pc_cmp (const void *, const void *);
+static char *pop_argument_types (tree);
extern int stack_pointer;
/* Append TARGET_LABEL to the pending_block stack unless already in it. */
static void
-push_pending_label (target_label)
- tree target_label;
+push_pending_label (tree target_label)
{
if (! LABEL_CHANGED (target_label))
{
/* Note that TARGET_LABEL is a possible successor instruction.
Merge the type state etc.
- Return NULL on sucess, or an error message on failure. */
+ Return NULL on success, or an error message on failure. */
static const char *
-check_pending_block (target_label)
- tree target_label;
+check_pending_block (tree target_label)
{
int changed = merge_type_state (target_label);
return NULL;
}
+/* Count the number of nested jsr calls needed to reach LABEL. */
+
+static int
+subroutine_nesting (tree label)
+{
+ int nesting = 0;
+ while (label != NULL_TREE && LABEL_IN_SUBR (label))
+ {
+ if (! LABEL_IS_SUBR_START(label))
+ label = LABEL_SUBR_START (label);
+ label = LABEL_SUBR_CONTEXT (label);
+ nesting++;
+ }
+ return nesting;
+}
+
/* Return the "merged" types of TYPE1 and TYPE2.
If either is primitive, the other must match (after promotion to int).
For reference types, return the common super-class.
Return TYPE_UNKNOWN if the types cannot be merged. */
static tree
-merge_types (type1, type2)
- tree type1, type2;
+merge_types (tree type1, tree type2)
{
if (type1 == type2)
return type1;
if (type2 == ptr_type_node || type1 == object_ptr_type_node)
return type1;
- tt1 = HANDLE_TO_CLASS_TYPE (TREE_TYPE (type1));
- tt2 = HANDLE_TO_CLASS_TYPE (TREE_TYPE (type2));
+ tt1 = TREE_TYPE (type1);
+ tt2 = TREE_TYPE (type2);
/* If tt{1,2} haven't been properly loaded, now is a good time
to do it. */
0 if there was no change, and 1 if there was a change. */
int
-merge_type_state (label)
- tree label;
+merge_type_state (tree label)
{
int nlocals = DECL_MAX_LOCALS (current_function_decl);
int cur_length = stack_pointer + nlocals;
/* Handle dup-like operations. */
static void
-type_stack_dup (size, offset)
- int size, offset;
+type_stack_dup (int size, int offset)
{
tree type[4];
int index;
/* A helper that is used when sorting exception ranges. */
static int
-start_pc_cmp (xp, yp)
- const PTR xp;
- const PTR yp;
+start_pc_cmp (const void *xp, const void *yp)
{
const struct pc_index *x = (const struct pc_index *) xp;
const struct pc_index *y = (const struct pc_index *) yp;
#define VERIFICATION_ERROR_WITH_INDEX(MESSAGE) \
do { message = MESSAGE; goto error_with_index; } while (0)
-/* Recursive helper function to pop argument types during verifiation.
+/* Recursive helper function to pop argument types during verification.
ARG_TYPES is the list of formal parameter types.
Return NULL on success and a freshly malloc'd error message on failure. */
static char *
-pop_argument_types (arg_types)
- tree arg_types;
+pop_argument_types (tree arg_types)
{
if (arg_types == end_params_node)
return NULL;
#define BCODE byte_ops
/* Verify the bytecodes of the current method.
- Return 1 on sucess, 0 on failure. */
+ Return 1 on success, 0 on failure. */
int
-verify_jvm_instructions (jcf, byte_ops, length)
- JCF* jcf;
- const unsigned char *byte_ops;
- long length;
+verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
{
tree label;
int wide = 0;
/* We read the exception handlers in order of increasing start PC.
To do this we first read and sort the start PCs. */
- starts = (struct pc_index *) xmalloc (eh_count * sizeof (struct pc_index));
+ starts = xmalloc (eh_count * sizeof (struct pc_index));
for (i = 0; i < eh_count; ++i)
{
starts[i].start_pc = GET_u2 (jcf->read_ptr + 8 * i);
if (start_pc < 0 || start_pc >= length
|| end_pc < 0 || end_pc > length || start_pc >= end_pc
|| handler_pc < 0 || handler_pc >= length
- || (handler_pc >= start_pc && handler_pc < end_pc)
|| ! (instruction_bits [start_pc] & BCODE_INSTRUCTION_START)
|| (end_pc < length &&
! (instruction_bits [end_pc] & BCODE_INSTRUCTION_START))
if (current_subr
&& PC == INVALID_PC)
{
- tree caller = LABEL_SUBR_CONTEXT (current_subr);
-
if (pending_blocks == NULL_TREE
- || ! LABEL_IN_SUBR (pending_blocks)
- || LABEL_SUBR_START (pending_blocks) == caller)
+ || (subroutine_nesting (pending_blocks)
+ < subroutine_nesting (current_subr)))
{
int size = DECL_MAX_LOCALS(current_function_decl)+stack_pointer;
tree ret_map = LABEL_RETURN_TYPE_STATE (current_subr);
have returned to an earlier caller. Obviously a
"ret" can only return one level, but a throw may
return many levels.*/
- current_subr = caller;
+ current_subr = LABEL_SUBR_CONTEXT (current_subr);
if (RETURN_MAP_ADJUSTED (ret_map))
{
goto push_int;
push_int:
if (byte_ops[PC] == OPCODE_newarray
- || byte_ops[PC] == OPCODE_newarray)
+ || byte_ops[PC] == OPCODE_anewarray)
int_value = i;
PUSH_TYPE (int_type_node); break;
case OPCODE_lconst_0: case OPCODE_lconst_1:
prev_eh_ranges = NULL_EH_RANGE;
/* Allocate decl and rtx for this variable now, so if we're not
- optmizing, we get a temporary that survives the whole method. */
+ optimizing, we get a temporary that survives the whole method. */
find_local_variable (index, type, oldpc);
if (TYPE_IS_WIDE (type))
break;
case OPCODE_checkcast:
- pop_type (ptr_type_node);
+ POP_TYPE (object_ptr_type_node,
+ "checkcast operand is not a pointer");
type = get_class_constant (current_jcf, IMMEDIATE_u2);
PUSH_TYPE (type);
break;
case OPCODE_instanceof:
- pop_type (ptr_type_node);
+ POP_TYPE (object_ptr_type_node,
+ "instanceof operand is not a pointer");
get_class_constant (current_jcf, IMMEDIATE_u2);
PUSH_TYPE (int_type_node);
break;
type_map[len] = TREE_VEC_ELT (return_map, len);
}
current_subr = LABEL_SUBR_CONTEXT (target);
- PUSH_PENDING (return_label);
+ if (RETURN_MAP_ADJUSTED (return_map))
+ PUSH_PENDING (return_label);
}
INVALIDATE_PC;