OSDN Git Service

* approved by aph
[pf3gnuchains/gcc-fork.git] / gcc / java / verify.c
index eadb4e6..fd09459 100644 (file)
@@ -1,21 +1,22 @@
 /* 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.
 
@@ -25,6 +26,8 @@ The Free Software Foundation is independent of Sun Microsystems, Inc.  */
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "tree.h"
 #include "java-tree.h"
 #include "javaop.h"
@@ -33,12 +36,12 @@ The Free Software Foundation is independent of Sun Microsystems, Inc.  */
 #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;
 
@@ -53,8 +56,7 @@ tree pending_blocks;
 /* 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))
     {
@@ -66,11 +68,10 @@ push_pending_label (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);
 
@@ -104,14 +105,29 @@ check_pending_block (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;
@@ -129,8 +145,8 @@ merge_types (type1, type2)
       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. */
@@ -226,8 +242,7 @@ merge_types (type1, type2)
    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;
@@ -289,8 +304,7 @@ merge_type_state (label)
 /* 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;
@@ -331,9 +345,7 @@ struct pc_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;
@@ -351,13 +363,12 @@ start_pc_cmp (xp, 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;
@@ -398,12 +409,9 @@ pop_argument_types (arg_types)
 #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;
@@ -433,7 +441,7 @@ verify_jvm_instructions (jcf, byte_ops, length)
 
   /* 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);
@@ -455,7 +463,6 @@ verify_jvm_instructions (jcf, byte_ops, length)
       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))
@@ -497,11 +504,9 @@ verify_jvm_instructions (jcf, byte_ops, length)
       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);
@@ -511,7 +516,7 @@ verify_jvm_instructions (jcf, byte_ops, length)
                 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))
                {
@@ -594,7 +599,7 @@ verify_jvm_instructions (jcf, byte_ops, length)
          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:
@@ -705,7 +710,7 @@ verify_jvm_instructions (jcf, byte_ops, length)
        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))
@@ -1174,12 +1179,14 @@ verify_jvm_instructions (jcf, byte_ops, length)
          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;
@@ -1308,7 +1315,8 @@ verify_jvm_instructions (jcf, byte_ops, length)
                      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;