OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / java / verify-impl.c
index f487978..1ca2d9f 100644 (file)
@@ -1,4 +1,5 @@
-/* Copyright (C) 2001, 2002, 2003, 2004  Free Software Foundation
+/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2008, 2009, 2010
+   Free Software Foundation
 
    This file is part of libgcj.
 
@@ -18,37 +19,13 @@ details.  */
 /* Hack to work around namespace pollution from java-tree.h.  */
 #undef current_class
 
-#ifdef VERIFY_DEBUG
-#include <stdio.h>
-#endif /* VERIFY_DEBUG */
-
 /* This is used to mark states which are not scheduled for
    verification. */
 #define INVALID_STATE ((state *) -1)
 
-#ifdef VERIFY_DEBUG
-static void
-debug_print (const char *fmt, ...)
-{
-  va_list ap;
-  va_start (ap, fmt);
-  vfprintf (stderr, fmt, ap);
-  va_end (ap);
-}
-#else
-static void
+static void ATTRIBUTE_PRINTF_1
 debug_print (const char *fmt ATTRIBUTE_UNUSED, ...)
 {
-}    
-#endif /* VERIFY_DEBUG */
-
-#if 0
-static void debug_print (const char *fmt, ...)
-  __attribute__ ((format (printf, 1, 2)));
-
-static void
-debug_print (const char *fmt, ...)
-{
 #ifdef VERIFY_DEBUG
   va_list ap;
   va_start (ap, fmt);
@@ -56,7 +33,6 @@ debug_print (const char *fmt, ...)
   va_end (ap);
 #endif /* VERIFY_DEBUG */
 }
-#endif
 
 /* This started as a fairly ordinary verifier, and for the most part
    it remains so.  It works in the obvious way, by modeling the effect
@@ -224,22 +200,6 @@ static GTY(()) verifier_context *vfr;
 bool type_initialized (type *t);
 int ref_count_dimensions (ref_intersection *ref);
 
-#if 0
-  /* Create a new Utf-8 constant and return it.  We do this to avoid
-     having our Utf-8 constants prematurely collected.  */
-  static vfy_string
-  make_utf8_const (const char *s, int len)
-  {
-    vfy_string val = vfy_make_string (s, len);
-    vfy_string_list *lu = vfy_alloc (sizeof (vfy_string_list));
-    lu->val = val;
-    lu->next = vfr->utf8_list;
-    vfr->utf8_list = lu;
-
-    return val;
-  }
-#endif
-
 static void
 verify_fail_pc (const char *s, int pc)
 {
@@ -249,7 +209,7 @@ verify_fail_pc (const char *s, int pc)
 static void
 verify_fail (const char *s)
 {
-  verify_fail_pc (s, -1);
+  verify_fail_pc (s, vfr->PC);
 }
 
 /* This enum holds a list of tags for all the different types we
@@ -539,29 +499,21 @@ struct type
   
      First, when constructing a new object, it is the PC of the
      `new' instruction which created the object.  We use the special
-     value UNINIT to mean that this is uninitialized, and the
-     special value SELF for the case where the current method is
-     itself the <init> method.
-
+     value UNINIT to mean that this is uninitialized.  The special
+     value SELF is used for the case where the current method is
+     itself the <init> method.  the special value EITHER is used
+     when we may optionally allow either an uninitialized or
+     initialized reference to match.
+  
      Second, when the key is return_address_type, this holds the PC
      of the instruction following the `jsr'.  */
   int pc;
 
-  #define UNINIT -2
-  #define SELF -1
+#define UNINIT -2
+#define SELF -1
+#define EITHER -3
 };
 
-#if 0
-/* Basic constructor.  */
-static void
-init_type (type *t)
-{
-  t->key = unsuitable_type;
-  t->klass = NULL;
-  t->pc = UNINIT;
-}
-#endif
-
 /* Make a new instance given the type tag.  We assume a generic
    `reference_type' means Object.  */
 static void
@@ -623,26 +575,6 @@ make_type_from_string (vfy_string n)
   return t;
 }
 
-#if 0
-    /* Make a new instance given the name of a class.  */
-    type (vfy_string n)
-    {
-      key = reference_type;
-      klass = new ref_intersection (n, verifier);
-      pc = UNINIT;
-    }
-
-    /* Copy constructor.  */
-    static type copy_type (type *t)
-    {
-      type copy;
-      copy.key = t->key;
-      copy.klass = t->klass;
-      copy.pc = t->pc;
-      return copy;
-    }
-#endif
-
 /* Promote a numeric type.  */
 static void
 vfy_promote_type (type *t)
@@ -721,23 +653,52 @@ types_compatible (type *t, type *k)
   if (k->klass == NULL)
     verify_fail ("programmer error in type::compatible");
 
-  /* An initialized type and an uninitialized type are not
-     compatible.  */
-  if (type_initialized (t) != type_initialized (k))
-    return false;
-
-  /* Two uninitialized objects are compatible if either:
-     * The PCs are identical, or
-     * One PC is UNINIT.  */
-  if (type_initialized (t))
+  /* Handle the special 'EITHER' case, which is only used in a
+     special case of 'putfield'.  Note that we only need to handle
+     this on the LHS of a check.  */
+  if (! type_initialized (t) && t->pc == EITHER)
     {
-      if (t->pc != k->pc && t->pc != UNINIT && k->pc != UNINIT)
+      /* If the RHS is uninitialized, it must be an uninitialized
+        'this'.  */
+      if (! type_initialized (k) && k->pc != SELF)
        return false;
     }
+  else if (type_initialized (t) != type_initialized (k))
+    {
+      /* An initialized type and an uninitialized type are not
+        otherwise compatible.  */
+      return false;
+    }
+  else
+    {
+      /* Two uninitialized objects are compatible if either:
+       * The PCs are identical, or
+       * One PC is UNINIT.  */
+      if (type_initialized (t))
+       {
+         if (t->pc != k->pc && t->pc != UNINIT && k->pc != UNINIT)
+           return false;
+       }
+    }
 
   return ref_compatible (t->klass, k->klass);
 }
 
+/* Return true if two types are equal.  Only valid for reference
+   types.  */
+static bool
+types_equal (type *t1, type *t2)
+{
+  if ((t1->key != reference_type && t1->key != uninitialized_reference_type)
+      || (t2->key != reference_type
+         && t2->key != uninitialized_reference_type))
+    return false;
+  /* Only single-ref types are allowed.  */
+  if (t1->klass->ref_next || t2->klass->ref_next)
+    return false;
+  return refs_equal (t1->klass, t2->klass);
+}
+
 static bool
 type_isvoid (type *t)
 {
@@ -842,16 +803,6 @@ type_initialized (type *t)
   return t->key == reference_type || t->key == null_type;
 }
 
-#if 0
-static bool
-type_isresolved (type *t)
-{
-  return (t->key == reference_type
-         || t->key == null_type
-         || t->key == uninitialized_reference_type);
-}
-#endif
-
 static void
 type_verify_dimensions (type *t, int ndims)
 {
@@ -986,16 +937,6 @@ struct state
    acquired from the verification list.  */
 #define NO_NEXT -1
 
-#if 0
-static void
-init_state (state *s)
-{
-  s->stack = NULL;
-  s->locals = NULL;
-  s->next = INVALID_STATE;  
-}
-#endif
-
 static void
 init_state_with_stack (state *s, int max_stack, int max_locals)
 {
@@ -1039,7 +980,7 @@ copy_state_with_stack (state *s, state *orig, int max_stack, int max_locals)
 static state *
 make_state_copy (state *orig, int max_stack, int max_locals)
 {
-  state *s = vfy_alloc (sizeof (state));
+  state *s = (state *) vfy_alloc (sizeof (state));
   copy_state_with_stack (s, orig, max_stack, max_locals);
   return s;
 }
@@ -1047,12 +988,11 @@ make_state_copy (state *orig, int max_stack, int max_locals)
 static state *
 make_state (int max_stack, int max_locals)
 {
-  state *s = vfy_alloc (sizeof (state));
+  state *s = (state *) vfy_alloc (sizeof (state));
   init_state_with_stack (s, max_stack, max_locals);
   return s;
 }
 
-#if 0
 static void
 free_state (state *s)
 {
@@ -1061,29 +1001,6 @@ free_state (state *s)
   if (s->locals != NULL)
     vfy_free (s->locals);
 }
-#endif
-
-#if 0
-    void *operator new[] (size_t bytes)
-    {
-      return vfy_alloc (bytes);
-    }
-
-    void operator delete[] (void *mem)
-    {
-      vfy_free (mem);
-    }
-
-    void *operator new (size_t bytes)
-    {
-      return vfy_alloc (bytes);
-    }
-
-    void operator delete (void *mem)
-    {
-      vfy_free (mem);
-    }
-#endif
 
 /* Modify this state to reflect entry to an exception handler.  */
 static void
@@ -1097,20 +1014,6 @@ state_set_exception (state *s, type *t, int max_stack)
     init_type_from_tag (&s->stack[i], unsuitable_type);
 }
 
-static int
-state_get_pc (state *s)
-{
-  return s->pc;
-}
-
-#if 0
-static void
-set_pc (state *s, int npc)
-{
-  s->pc = npc;
-}
-#endif
-
 /* Merge STATE_OLD into this state.  Destructively modifies this
    state.  Returns true if the new state was in fact changed.
    Will throw an exception if the states are not mergeable.  */
@@ -1439,7 +1342,7 @@ get_ushort (void)
 static jint
 get_short (void)
 {
-  jint b1 = get_byte ();
+  signed char b1 = (signed char) get_byte ();
   jint b2 = get_byte ();
   jshort s = (b1 << 8) | b2;
   return (jint) s;
@@ -1452,7 +1355,10 @@ get_int (void)
   jint b2 = get_byte ();
   jint b3 = get_byte ();
   jint b4 = get_byte ();
-  return (b1 << 24) | (b2 << 16) | (b3 << 8) | b4;
+  jword result = (b1 << 24) | (b2 << 16) | (b3 << 8) | b4;
+  /* In the compiler, 'jint' might have more than 32 bits, so we must
+     sign extend.  */
+  return WORD_TO_INT (result);
 }
 
 static int
@@ -1476,7 +1382,7 @@ add_new_state (int npc, state *old_state)
   debug_print_state (new_state, "New", npc, current_method->max_stack,
                    current_method->max_locals);
 
-  nlink = vfy_alloc (sizeof (state_list));
+  nlink = (state_list *) vfy_alloc (sizeof (state_list));
   nlink->val = new_state;
   nlink->next = vfr->states[npc];
   vfr->states[npc] = nlink;
@@ -2037,7 +1943,7 @@ check_pool_index (int index)
 static type
 check_class_constant (int index)
 {
-  type t;
+  type t = { (type_val) 0, 0, 0 };
   vfy_constants *pool;
 
   check_pool_index (index);
@@ -2054,7 +1960,7 @@ check_class_constant (int index)
 static type
 check_constant (int index)
 {
-  type t;
+  type t = { (type_val) 0, 0, 0 };
   vfy_constants *pool;
 
   check_pool_index (index);
@@ -2066,6 +1972,10 @@ check_constant (int index)
     init_type_from_tag (&t, int_type);
   else if (vfy_tag (pool, index) == JV_CONSTANT_Float)
     init_type_from_tag (&t, float_type);
+  else if (vfy_tag (pool, index) == JV_CONSTANT_Class
+          || vfy_tag (pool, index) == JV_CONSTANT_ResolvedClass)
+    /* FIXME: should only allow this for 1.5 bytecode.  */
+    init_type_from_class (&t, vfy_class_type ());
   else
     verify_fail_pc ("String, int, or float constant expected", vfr->start_PC);
   return t;
@@ -2074,7 +1984,7 @@ check_constant (int index)
 static type
 check_wide_constant (int index)
 {
-  type t;
+  type t = { (type_val) 0, 0, 0 };
   vfy_constants *pool;
 
   check_pool_index (index);
@@ -2114,13 +2024,13 @@ handle_field_or_method (int index, int expected,
   return check_class_constant (class_index);
 }
 
-/* Return field's type, compute class' type if requested.  */
+/* Return field's type, compute class' type if requested.  If
+   PUTFIELD is true, use the special 'putfield' semantics.  */
 static type
-check_field_constant (int index, type *class_type)
+check_field_constant (int index, type *class_type, bool putfield)
 {
   vfy_string name, field_type;
   const char *typec;
-  int len;
   type t;
 
   type ct = handle_field_or_method (index,
@@ -2129,11 +2039,25 @@ check_field_constant (int index, type *class_type)
   if (class_type)
     *class_type = ct;
   typec = vfy_string_bytes (field_type);
-  len = vfy_string_length (field_type);
   if (typec[0] == '[' || typec[0] == 'L')
     init_type_from_string (&t, field_type);
   else
     init_type_from_tag (&t, get_type_val_for_signature (typec[0]));
+
+  /* We have an obscure special case here: we can use `putfield' on a
+     field declared in this class, even if `this' has not yet been
+     initialized.  */
+  if (putfield
+      && ! type_initialized (&vfr->current_state->this_type)
+      && vfr->current_state->this_type.pc == SELF
+      && types_equal (&vfr->current_state->this_type, &ct)
+      && vfy_class_has_field (vfr->current_class, name, field_type))
+    /* Note that we don't actually know whether we're going to match
+       against 'this' or some other object of the same type.  So,
+       here we set things up so that it doesn't matter.  This relies
+       on knowing what our caller is up to.  */
+    type_set_uninitialized (class_type, EITHER);
+
   return t;
 }
 
@@ -2149,8 +2073,8 @@ check_method_constant (int index, bool is_interface,
                                 method_name, method_signature);
 }
 
-static char *
-get_one_type (char *p, type *t)
+static const char *
+get_one_type (const char *p, type *t)
 {
   const char *start = p;
   vfy_jclass k;
@@ -2202,7 +2126,7 @@ static void
 compute_argument_types (vfy_string signature, type *types)
 {
   int i;
-  char *p = (char *) vfy_string_bytes (signature);
+  const char *p = vfy_string_bytes (signature);
 
   /* Skip `('.  */
   ++p;
@@ -2215,7 +2139,7 @@ compute_argument_types (vfy_string signature, type *types)
 static type
 compute_return_type (vfy_string signature)
 {
-  char *p = (char *) vfy_string_bytes (signature);
+  const char *p = vfy_string_bytes (signature);
   type t;
   while (*p != ')')
     ++p;
@@ -2317,7 +2241,7 @@ verify_instructions_0 (void)
          if (new_state == NULL)
            break;
 
-         vfr->PC = state_get_pc (new_state);
+         vfr->PC = new_state->pc;
          debug_print ("== State pop from pending list\n");
          /* Set up the current state.  */
          copy_state (vfr->current_state, new_state, 
@@ -2326,10 +2250,12 @@ verify_instructions_0 (void)
       else
        {
          /* We only have to do this checking in the situation where
-            control flow falls through from the previous
-            instruction.  Otherwise merging is done at the time we
-            push the branch.  */
-         if (vfr->states[vfr->PC] != NULL)
+            control flow falls through from the previous instruction.
+            Otherwise merging is done at the time we push the branch.
+            Note that we'll catch the off-the-end problem just
+            below.  */
+         if (vfr->PC < vfr->current_method->code_length
+             && vfr->states[vfr->PC] != NULL)
            {
              /* We've already visited this instruction.  So merge
                 the states together.  It is simplest, but not most
@@ -2960,23 +2886,25 @@ verify_instructions_0 (void)
          invalidate_pc ();
          break;
        case op_return:
-         /* We only need to check this when the return type is
-            void, because all instance initializers return void.  */
-         if (this_is_init)
+         /* We only need to check this when the return type is void,
+            because all instance initializers return void.  We also
+            need to special-case Object constructors, as they can't
+            call a superclass <init>.  */
+         if (this_is_init && vfr->current_class != vfy_object_type ())
            state_check_this_initialized (vfr->current_state);
          check_return_type (make_type (void_type));
          invalidate_pc ();
          break;
        case op_getstatic:
-         push_type_t (check_field_constant (get_ushort (), NULL));
+         push_type_t (check_field_constant (get_ushort (), NULL, false));
          break;
        case op_putstatic:
-         pop_type_t (check_field_constant (get_ushort (), NULL));
+         pop_type_t (check_field_constant (get_ushort (), NULL, false));
          break;
        case op_getfield:
          {
            type klass;
-           type field = check_field_constant (get_ushort (), &klass);
+           type field = check_field_constant (get_ushort (), &klass, false);
            pop_type_t (klass);
            push_type_t (field);
          }
@@ -2984,15 +2912,8 @@ verify_instructions_0 (void)
        case op_putfield:
          {
            type klass;
-           type field = check_field_constant (get_ushort (), &klass);
+           type field = check_field_constant (get_ushort (), &klass, true);
            pop_type_t (field);
-
-           /* We have an obscure special case here: we can use
-              `putfield' on a field declared in this class, even if
-              `this' has not yet been initialized.  */
-           if (! type_initialized (&vfr->current_state->this_type)
-               && vfr->current_state->this_type.pc == SELF)
-             type_set_uninitialized (&klass, SELF);
            pop_type_t (klass);
          }
          break;
@@ -3098,13 +3019,15 @@ verify_instructions_0 (void)
        case op_newarray:
          {
            int atype = get_byte ();
+           vfy_jclass k;
            type t;
            /* We intentionally have chosen constants to make this
               valid.  */
            if (atype < boolean_type || atype > long_type)
              verify_fail_pc ("type not primitive", vfr->start_PC);
            pop_type (int_type);
-           init_type_from_class (&t, construct_primitive_array_type (atype));
+           k = construct_primitive_array_type ((type_val) atype);
+           init_type_from_class (&t, k);
            push_type_t (t);
          }
          break;
@@ -3215,32 +3138,6 @@ verify_instructions_0 (void)
          handle_jsr_insn (get_int ());
          break;
 
-#if 0
-       /* These are unused here, but we call them out explicitly
-          so that -Wswitch-enum doesn't complain.  */
-       case op_putfield_1:
-       case op_putfield_2:
-       case op_putfield_4:
-       case op_putfield_8:
-       case op_putfield_a:
-       case op_putstatic_1:
-       case op_putstatic_2:
-       case op_putstatic_4:
-       case op_putstatic_8:
-       case op_putstatic_a:
-       case op_getfield_1:
-       case op_getfield_2s:
-       case op_getfield_2u:
-       case op_getfield_4:
-       case op_getfield_8:
-       case op_getfield_a:
-       case op_getstatic_1:
-       case op_getstatic_2s:
-       case op_getstatic_2u:
-       case op_getstatic_4:
-       case op_getstatic_8:
-       case op_getstatic_a:
-#endif
        default:
          /* Unrecognized opcode.  */
          verify_fail_pc ("unrecognized instruction in verify_instructions_0",
@@ -3284,7 +3181,7 @@ collapse_type (type *t)
       return vfy_object_type ();
     }
 
-  abort ();
+  gcc_unreachable ();
 }
 
 static void
@@ -3326,22 +3223,10 @@ verify_instructions (void)
                                   vfy_unsuitable_type ());
            }
        }
-      if (slot != curr->stackdepth)
-       abort ();
+      gcc_assert (slot == curr->stackdepth);
     }
 }
 
-#if 0
-_Jv_BytecodeVerifier (_Jv_InterpMethod *m)
-{
-  /* We just print the text as utf-8.  This is just for debugging
-     anyway.  */
-  debug_print ("--------------------------------\n");
-  debug_print ("-- Verifying method `%s'\n", m->self->name->chars());
-
-}
-#endif
-
 static void
 make_verifier_context (vfy_method *m)
 {
@@ -3392,6 +3277,7 @@ free_verifier_context (void)
          while (iter != NULL)
            {
              state_list *next = iter->next;
+             free_state (iter->val);
              vfy_free (iter->val);
              vfy_free (iter);
              iter = next;