OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-stable/] [gcc-4.5.1/] [gcc/] [java/] [verify-impl.c] - Diff between revs 816 and 826

Only display areas with differences | Details | Blame | View Log

Rev 816 Rev 826
/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2008, 2009
/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2008, 2009
   Free Software Foundation
   Free Software Foundation
 
 
   This file is part of libgcj.
   This file is part of libgcj.
 
 
This software is copyrighted work licensed under the terms of the
This software is copyrighted work licensed under the terms of the
Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
details.  */
details.  */
 
 
/* Written by Tom Tromey <tromey@redhat.com>  */
/* Written by Tom Tromey <tromey@redhat.com>  */
 
 
/* Uncomment this to enable debugging output.  */
/* Uncomment this to enable debugging output.  */
/* #define VERIFY_DEBUG */
/* #define VERIFY_DEBUG */
 
 
#include "config.h"
#include "config.h"
 
 
#include "verify.h"
#include "verify.h"
 
 
/* Hack to work around namespace pollution from java-tree.h.  */
/* Hack to work around namespace pollution from java-tree.h.  */
#undef current_class
#undef current_class
 
 
#ifdef VERIFY_DEBUG
#ifdef VERIFY_DEBUG
#include <stdio.h>
#include <stdio.h>
#endif /* VERIFY_DEBUG */
#endif /* VERIFY_DEBUG */
 
 
/* This is used to mark states which are not scheduled for
/* This is used to mark states which are not scheduled for
   verification. */
   verification. */
#define INVALID_STATE ((state *) -1)
#define INVALID_STATE ((state *) -1)
 
 
static void ATTRIBUTE_PRINTF_1
static void ATTRIBUTE_PRINTF_1
debug_print (const char *fmt ATTRIBUTE_UNUSED, ...)
debug_print (const char *fmt ATTRIBUTE_UNUSED, ...)
{
{
#ifdef VERIFY_DEBUG
#ifdef VERIFY_DEBUG
  va_list ap;
  va_list ap;
  va_start (ap, fmt);
  va_start (ap, fmt);
  vfprintf (stderr, fmt, ap);
  vfprintf (stderr, fmt, ap);
  va_end (ap);
  va_end (ap);
#endif /* VERIFY_DEBUG */
#endif /* VERIFY_DEBUG */
}
}
 
 
/* This started as a fairly ordinary verifier, and for the most part
/* 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
   it remains so.  It works in the obvious way, by modeling the effect
   of each opcode as it is encountered.  For most opcodes, this is a
   of each opcode as it is encountered.  For most opcodes, this is a
   straightforward operation.
   straightforward operation.
 
 
   This verifier does not do type merging.  It used to, but this
   This verifier does not do type merging.  It used to, but this
   results in difficulty verifying some relatively simple code
   results in difficulty verifying some relatively simple code
   involving interfaces, and it pushed some verification work into the
   involving interfaces, and it pushed some verification work into the
   interpreter.
   interpreter.
 
 
   Instead of merging reference types, when we reach a point where two
   Instead of merging reference types, when we reach a point where two
   flows of control merge, we simply keep the union of reference types
   flows of control merge, we simply keep the union of reference types
   from each branch.  Then, when we need to verify a fact about a
   from each branch.  Then, when we need to verify a fact about a
   reference on the stack (e.g., that it is compatible with the
   reference on the stack (e.g., that it is compatible with the
   argument type of a method), we check to ensure that all possible
   argument type of a method), we check to ensure that all possible
   types satisfy the requirement.
   types satisfy the requirement.
 
 
   Another area this verifier differs from the norm is in its handling
   Another area this verifier differs from the norm is in its handling
   of subroutines.  The JVM specification has some confusing things to
   of subroutines.  The JVM specification has some confusing things to
   say about subroutines.  For instance, it makes claims about not
   say about subroutines.  For instance, it makes claims about not
   allowing subroutines to merge and it rejects recursive subroutines.
   allowing subroutines to merge and it rejects recursive subroutines.
   For the most part these are red herrings; we used to try to follow
   For the most part these are red herrings; we used to try to follow
   these things but they lead to problems.  For example, the notion of
   these things but they lead to problems.  For example, the notion of
   "being in a subroutine" is not well-defined: is an exception
   "being in a subroutine" is not well-defined: is an exception
   handler in a subroutine?  If you never execute the `ret' but
   handler in a subroutine?  If you never execute the `ret' but
   instead `goto 1' do you remain in the subroutine?
   instead `goto 1' do you remain in the subroutine?
 
 
   For clarity on what is really required for type safety, read
   For clarity on what is really required for type safety, read
   "Simple Verification Technique for Complex Java Bytecode
   "Simple Verification Technique for Complex Java Bytecode
   Subroutines" by Alessandro Coglio.  Among other things this paper
   Subroutines" by Alessandro Coglio.  Among other things this paper
   shows that recursive subroutines are not harmful to type safety.
   shows that recursive subroutines are not harmful to type safety.
   We implement something similar to what he proposes.  Note that this
   We implement something similar to what he proposes.  Note that this
   means that this verifier will accept code that is rejected by some
   means that this verifier will accept code that is rejected by some
   other verifiers.
   other verifiers.
 
 
   For those not wanting to read the paper, the basic observation is
   For those not wanting to read the paper, the basic observation is
   that we can maintain split states in subroutines.  We maintain one
   that we can maintain split states in subroutines.  We maintain one
   state for each calling `jsr'.  In other words, we re-verify a
   state for each calling `jsr'.  In other words, we re-verify a
   subroutine once for each caller, using the exact types held by the
   subroutine once for each caller, using the exact types held by the
   callers (as opposed to the old approach of merging types and
   callers (as opposed to the old approach of merging types and
   keeping a bitmap registering what did or did not change).  This
   keeping a bitmap registering what did or did not change).  This
   approach lets us continue to verify correctly even when a
   approach lets us continue to verify correctly even when a
   subroutine is exited via `goto' or `athrow' and not `ret'.
   subroutine is exited via `goto' or `athrow' and not `ret'.
 
 
   In some other areas the JVM specification is (mildly) incorrect,
   In some other areas the JVM specification is (mildly) incorrect,
   so we diverge.  For instance, you cannot
   so we diverge.  For instance, you cannot
   violate type safety by allocating an object with `new' and then
   violate type safety by allocating an object with `new' and then
   failing to initialize it, no matter how one branches or where one
   failing to initialize it, no matter how one branches or where one
   stores the uninitialized reference.  See "Improving the official
   stores the uninitialized reference.  See "Improving the official
   specification of Java bytecode verification" by Alessandro Coglio.
   specification of Java bytecode verification" by Alessandro Coglio.
 
 
   Note that there's no real point in enforcing that padding bytes or
   Note that there's no real point in enforcing that padding bytes or
   the mystery byte of invokeinterface must be 0, but we do that
   the mystery byte of invokeinterface must be 0, but we do that
   regardless.
   regardless.
 
 
   The verifier is currently neither completely lazy nor eager when it
   The verifier is currently neither completely lazy nor eager when it
   comes to loading classes.  It tries to represent types by name when
   comes to loading classes.  It tries to represent types by name when
   possible, and then loads them when it needs to verify a fact about
   possible, and then loads them when it needs to verify a fact about
   the type.  Checking types by name is valid because we only use
   the type.  Checking types by name is valid because we only use
   names which come from the current class' constant pool.  Since all
   names which come from the current class' constant pool.  Since all
   such names are looked up using the same class loader, there is no
   such names are looked up using the same class loader, there is no
   danger that we might be fooled into comparing different types with
   danger that we might be fooled into comparing different types with
   the same name.
   the same name.
 
 
   In the future we plan to allow for a completely lazy mode of
   In the future we plan to allow for a completely lazy mode of
   operation, where the verifier will construct a list of type
   operation, where the verifier will construct a list of type
   assertions to be checked later.
   assertions to be checked later.
 
 
   Some test cases for the verifier live in the "verify" module of the
   Some test cases for the verifier live in the "verify" module of the
   Mauve test suite.  However, some of these are presently
   Mauve test suite.  However, some of these are presently
   (2004-01-20) believed to be incorrect.  (More precisely the notion
   (2004-01-20) believed to be incorrect.  (More precisely the notion
   of "correct" is not well-defined, and this verifier differs from
   of "correct" is not well-defined, and this verifier differs from
   others while remaining type-safe.)  Some other tests live in the
   others while remaining type-safe.)  Some other tests live in the
   libgcj test suite.
   libgcj test suite.
 
 
   This verifier is also written to be pluggable.  This means that it
   This verifier is also written to be pluggable.  This means that it
   is intended for use in a variety of environments, not just libgcj.
   is intended for use in a variety of environments, not just libgcj.
   As a result the verifier expects a number of type and method
   As a result the verifier expects a number of type and method
   declarations to be declared in "verify.h".  The intent is that you
   declarations to be declared in "verify.h".  The intent is that you
   recompile the verifier for your particular environment.  This
   recompile the verifier for your particular environment.  This
   approach was chosen so that operations could be inlined in verify.h
   approach was chosen so that operations could be inlined in verify.h
   as much as possible.
   as much as possible.
 
 
   See the verify.h that accompanies this copy of the verifier to see
   See the verify.h that accompanies this copy of the verifier to see
   what types, preprocessor defines, and functions must be declared.
   what types, preprocessor defines, and functions must be declared.
   The interface is ad hoc, but was defined so that it could be
   The interface is ad hoc, but was defined so that it could be
   implemented to connect to a pure C program.
   implemented to connect to a pure C program.
*/
*/
 
 
#define FLAG_INSN_START 1
#define FLAG_INSN_START 1
#define FLAG_BRANCH_TARGET 2
#define FLAG_BRANCH_TARGET 2
#define FLAG_INSN_SEEN 4
#define FLAG_INSN_SEEN 4
 
 
struct state;
struct state;
struct type;
struct type;
struct ref_intersection;
struct ref_intersection;
 
 
typedef struct state state;
typedef struct state state;
typedef struct type type;
typedef struct type type;
typedef struct ref_intersection ref_intersection;
typedef struct ref_intersection ref_intersection;
 
 
/*typedef struct state_list state_list;*/
/*typedef struct state_list state_list;*/
 
 
typedef struct state_list
typedef struct state_list
{
{
  state *val;
  state *val;
  struct state_list *next;
  struct state_list *next;
} state_list;
} state_list;
 
 
typedef struct vfy_string_list
typedef struct vfy_string_list
{
{
  vfy_string val;
  vfy_string val;
  struct vfy_string_list *next;
  struct vfy_string_list *next;
} vfy_string_list;
} vfy_string_list;
 
 
typedef struct verifier_context
typedef struct verifier_context
{
{
  /* The current PC.  */
  /* The current PC.  */
  int PC;
  int PC;
  /* The PC corresponding to the start of the current instruction.  */
  /* The PC corresponding to the start of the current instruction.  */
  int start_PC;
  int start_PC;
 
 
  /* The current state of the stack, locals, etc.  */
  /* The current state of the stack, locals, etc.  */
  state *current_state;
  state *current_state;
 
 
  /* At each branch target we keep a linked list of all the states we
  /* At each branch target we keep a linked list of all the states we
     can process at that point.  We'll only have multiple states at a
     can process at that point.  We'll only have multiple states at a
     given PC if they both have different return-address types in the
     given PC if they both have different return-address types in the
     same stack or local slot.  This array is indexed by PC and holds
     same stack or local slot.  This array is indexed by PC and holds
     the list of all such states.  */
     the list of all such states.  */
  state_list **states;
  state_list **states;
 
 
  /* We keep a linked list of all the states which we must reverify.
  /* We keep a linked list of all the states which we must reverify.
     This is the head of the list.  */
     This is the head of the list.  */
  state *next_verify_state;
  state *next_verify_state;
 
 
  /* We keep some flags for each instruction.  The values are the
  /* We keep some flags for each instruction.  The values are the
     FLAG_* constants defined above.  This is an array indexed by PC.  */
     FLAG_* constants defined above.  This is an array indexed by PC.  */
  char *flags;
  char *flags;
 
 
  /* The bytecode itself.  */
  /* The bytecode itself.  */
  const unsigned char *bytecode;
  const unsigned char *bytecode;
  /* The exceptions.  */
  /* The exceptions.  */
  vfy_exception *exception;
  vfy_exception *exception;
 
 
  /* Defining class.  */
  /* Defining class.  */
  vfy_jclass current_class;
  vfy_jclass current_class;
  /* This method.  */
  /* This method.  */
  vfy_method *current_method;
  vfy_method *current_method;
 
 
  /* A linked list of utf8 objects we allocate.  */
  /* A linked list of utf8 objects we allocate.  */
  vfy_string_list *utf8_list;
  vfy_string_list *utf8_list;
 
 
  /* A linked list of all ref_intersection objects we allocate.  */
  /* A linked list of all ref_intersection objects we allocate.  */
  ref_intersection *isect_list;
  ref_intersection *isect_list;
} verifier_context;
} verifier_context;
 
 
/* The current verifier's state data. This is maintained by
/* The current verifier's state data. This is maintained by
   {push/pop}_verifier_context to provide a shorthand form to access
   {push/pop}_verifier_context to provide a shorthand form to access
   the verification state. */
   the verification state. */
static GTY(()) verifier_context *vfr;
static GTY(()) verifier_context *vfr;
 
 
/* Local function declarations.  */
/* Local function declarations.  */
bool type_initialized (type *t);
bool type_initialized (type *t);
int ref_count_dimensions (ref_intersection *ref);
int ref_count_dimensions (ref_intersection *ref);
 
 
static void
static void
verify_fail_pc (const char *s, int pc)
verify_fail_pc (const char *s, int pc)
{
{
  vfy_fail (s, pc, vfr->current_class, vfr->current_method);
  vfy_fail (s, pc, vfr->current_class, vfr->current_method);
}
}
 
 
static void
static void
verify_fail (const char *s)
verify_fail (const char *s)
{
{
  verify_fail_pc (s, vfr->PC);
  verify_fail_pc (s, vfr->PC);
}
}
 
 
/* This enum holds a list of tags for all the different types we
/* This enum holds a list of tags for all the different types we
   need to handle.  Reference types are treated specially by the
   need to handle.  Reference types are treated specially by the
   type class.  */
   type class.  */
typedef enum type_val
typedef enum type_val
{
{
  void_type,
  void_type,
 
 
  /* The values for primitive types are chosen to correspond to values
  /* The values for primitive types are chosen to correspond to values
     specified to newarray. */
     specified to newarray. */
  boolean_type = 4,
  boolean_type = 4,
  char_type = 5,
  char_type = 5,
  float_type = 6,
  float_type = 6,
  double_type = 7,
  double_type = 7,
  byte_type = 8,
  byte_type = 8,
  short_type = 9,
  short_type = 9,
  int_type = 10,
  int_type = 10,
  long_type = 11,
  long_type = 11,
 
 
  /* Used when overwriting second word of a double or long in the
  /* Used when overwriting second word of a double or long in the
     local variables.  Also used after merging local variable states
     local variables.  Also used after merging local variable states
     to indicate an unusable value.  */
     to indicate an unusable value.  */
  unsuitable_type,
  unsuitable_type,
  return_address_type,
  return_address_type,
  /* This is the second word of a two-word value, i.e., a double or
  /* This is the second word of a two-word value, i.e., a double or
     a long.  */
     a long.  */
  continuation_type,
  continuation_type,
 
 
  /* Everything after `reference_type' must be a reference type.  */
  /* Everything after `reference_type' must be a reference type.  */
  reference_type,
  reference_type,
  null_type,
  null_type,
  uninitialized_reference_type
  uninitialized_reference_type
} type_val;
} type_val;
 
 
/* This represents a merged class type.  Some verifiers (including
/* This represents a merged class type.  Some verifiers (including
   earlier versions of this one) will compute the intersection of
   earlier versions of this one) will compute the intersection of
   two class types when merging states.  However, this loses
   two class types when merging states.  However, this loses
   critical information about interfaces implemented by the various
   critical information about interfaces implemented by the various
   classes.  So instead we keep track of all the actual classes that
   classes.  So instead we keep track of all the actual classes that
   have been merged.  */
   have been merged.  */
struct ref_intersection
struct ref_intersection
{
{
  /* Whether or not this type has been resolved.  */
  /* Whether or not this type has been resolved.  */
  bool is_resolved;
  bool is_resolved;
 
 
  /* Actual type data.  */
  /* Actual type data.  */
  union
  union
  {
  {
    /* For a resolved reference type, this is a pointer to the class.  */
    /* For a resolved reference type, this is a pointer to the class.  */
    vfy_jclass klass;
    vfy_jclass klass;
    /* For other reference types, this it the name of the class.  */
    /* For other reference types, this it the name of the class.  */
    vfy_string name;
    vfy_string name;
  } data;
  } data;
 
 
  /* Link to the next reference in the intersection.  */
  /* Link to the next reference in the intersection.  */
  ref_intersection *ref_next;
  ref_intersection *ref_next;
 
 
  /* This is used to keep track of all the allocated
  /* This is used to keep track of all the allocated
     ref_intersection objects, so we can free them.
     ref_intersection objects, so we can free them.
     FIXME: we should allocate these in chunks.  */
     FIXME: we should allocate these in chunks.  */
  ref_intersection *alloc_next;
  ref_intersection *alloc_next;
};
};
 
 
static ref_intersection *
static ref_intersection *
make_ref (void)
make_ref (void)
{
{
  ref_intersection *new_ref =
  ref_intersection *new_ref =
    (ref_intersection *) vfy_alloc (sizeof (ref_intersection));
    (ref_intersection *) vfy_alloc (sizeof (ref_intersection));
 
 
  new_ref->alloc_next = vfr->isect_list;
  new_ref->alloc_next = vfr->isect_list;
  vfr->isect_list = new_ref;
  vfr->isect_list = new_ref;
  return new_ref;
  return new_ref;
}
}
 
 
static ref_intersection *
static ref_intersection *
clone_ref (ref_intersection *dup)
clone_ref (ref_intersection *dup)
{
{
  ref_intersection *new_ref = make_ref ();
  ref_intersection *new_ref = make_ref ();
 
 
  new_ref->is_resolved = dup->is_resolved;
  new_ref->is_resolved = dup->is_resolved;
  new_ref->data = dup->data;
  new_ref->data = dup->data;
  return new_ref;
  return new_ref;
}
}
 
 
static void
static void
resolve_ref (ref_intersection *ref)
resolve_ref (ref_intersection *ref)
{
{
  if (ref->is_resolved)
  if (ref->is_resolved)
    return;
    return;
  ref->data.klass = vfy_find_class (vfr->current_class, ref->data.name);
  ref->data.klass = vfy_find_class (vfr->current_class, ref->data.name);
  ref->is_resolved = true;
  ref->is_resolved = true;
}
}
 
 
static bool
static bool
refs_equal (ref_intersection *ref1, ref_intersection *ref2)
refs_equal (ref_intersection *ref1, ref_intersection *ref2)
{
{
  if (! ref1->is_resolved && ! ref2->is_resolved
  if (! ref1->is_resolved && ! ref2->is_resolved
      && vfy_strings_equal (ref1->data.name, ref2->data.name))
      && vfy_strings_equal (ref1->data.name, ref2->data.name))
    return true;
    return true;
  if (! ref1->is_resolved)
  if (! ref1->is_resolved)
    resolve_ref (ref1);
    resolve_ref (ref1);
  if (! ref2->is_resolved)
  if (! ref2->is_resolved)
    resolve_ref (ref2);
    resolve_ref (ref2);
  return ref1->data.klass == ref2->data.klass;
  return ref1->data.klass == ref2->data.klass;
}
}
 
 
/* Merge REF1 type into REF2, returning the result.  This will
/* Merge REF1 type into REF2, returning the result.  This will
   return REF2 if all the classes in THIS already appear in
   return REF2 if all the classes in THIS already appear in
   REF2.  */
   REF2.  */
static ref_intersection *
static ref_intersection *
merge_refs (ref_intersection *ref1, ref_intersection *ref2)
merge_refs (ref_intersection *ref1, ref_intersection *ref2)
{
{
  ref_intersection *tail = ref2;
  ref_intersection *tail = ref2;
  for (; ref1 != NULL; ref1 = ref1->ref_next)
  for (; ref1 != NULL; ref1 = ref1->ref_next)
    {
    {
      bool add = true;
      bool add = true;
      ref_intersection *iter;
      ref_intersection *iter;
      for (iter = ref2; iter != NULL; iter = iter->ref_next)
      for (iter = ref2; iter != NULL; iter = iter->ref_next)
        {
        {
          if (refs_equal (ref1, iter))
          if (refs_equal (ref1, iter))
            {
            {
              add = false;
              add = false;
              break;
              break;
            }
            }
        }
        }
 
 
      if (add)
      if (add)
        {
        {
          ref_intersection *new_tail = clone_ref (ref1);
          ref_intersection *new_tail = clone_ref (ref1);
          new_tail->ref_next = tail;
          new_tail->ref_next = tail;
          tail = new_tail;
          tail = new_tail;
        }
        }
    }
    }
  return tail;
  return tail;
}
}
 
 
/* See if an object of type SOURCE can be assigned to an object of
/* See if an object of type SOURCE can be assigned to an object of
   type TARGET.  This might resolve classes in one chain or the other.  */
   type TARGET.  This might resolve classes in one chain or the other.  */
static bool
static bool
ref_compatible (ref_intersection *target, ref_intersection *source)
ref_compatible (ref_intersection *target, ref_intersection *source)
{
{
  for (; target != NULL; target = target->ref_next)
  for (; target != NULL; target = target->ref_next)
    {
    {
      ref_intersection *source_iter = source;
      ref_intersection *source_iter = source;
 
 
      for (; source_iter != NULL; source_iter = source_iter->ref_next)
      for (; source_iter != NULL; source_iter = source_iter->ref_next)
        {
        {
          /* Avoid resolving if possible.  */
          /* Avoid resolving if possible.  */
          if (! target->is_resolved
          if (! target->is_resolved
              && ! source_iter->is_resolved
              && ! source_iter->is_resolved
              && vfy_strings_equal (target->data.name,
              && vfy_strings_equal (target->data.name,
                                    source_iter->data.name))
                                    source_iter->data.name))
            continue;
            continue;
 
 
          if (! target->is_resolved)
          if (! target->is_resolved)
            resolve_ref (target);
            resolve_ref (target);
          if (! source_iter->is_resolved)
          if (! source_iter->is_resolved)
            resolve_ref (source_iter);
            resolve_ref (source_iter);
 
 
          if (! vfy_is_assignable_from (target->data.klass,
          if (! vfy_is_assignable_from (target->data.klass,
                                        source_iter->data.klass))
                                        source_iter->data.klass))
            return false;
            return false;
        }
        }
    }
    }
 
 
  return true;
  return true;
}
}
 
 
static bool
static bool
ref_isarray (ref_intersection *ref)
ref_isarray (ref_intersection *ref)
{
{
  /* assert (ref_next == NULL);  */
  /* assert (ref_next == NULL);  */
  if (ref->is_resolved)
  if (ref->is_resolved)
    return vfy_is_array (ref->data.klass);
    return vfy_is_array (ref->data.klass);
  else
  else
    return vfy_string_bytes (ref->data.name)[0] == '[';
    return vfy_string_bytes (ref->data.name)[0] == '[';
}
}
 
 
static bool
static bool
ref_isinterface (ref_intersection *ref)
ref_isinterface (ref_intersection *ref)
{
{
  /* assert (ref_next == NULL);  */
  /* assert (ref_next == NULL);  */
  if (! ref->is_resolved)
  if (! ref->is_resolved)
    resolve_ref (ref);
    resolve_ref (ref);
  return vfy_is_interface (ref->data.klass);
  return vfy_is_interface (ref->data.klass);
}
}
 
 
static bool
static bool
ref_isabstract (ref_intersection *ref)
ref_isabstract (ref_intersection *ref)
{
{
  /* assert (ref_next == NULL); */
  /* assert (ref_next == NULL); */
  if (! ref->is_resolved)
  if (! ref->is_resolved)
    resolve_ref (ref);
    resolve_ref (ref);
  return vfy_is_abstract (ref->data.klass);
  return vfy_is_abstract (ref->data.klass);
}
}
 
 
static vfy_jclass
static vfy_jclass
ref_getclass (ref_intersection *ref)
ref_getclass (ref_intersection *ref)
{
{
  if (! ref->is_resolved)
  if (! ref->is_resolved)
    resolve_ref (ref);
    resolve_ref (ref);
  return ref->data.klass;
  return ref->data.klass;
}
}
 
 
int
int
ref_count_dimensions (ref_intersection *ref)
ref_count_dimensions (ref_intersection *ref)
{
{
  int ndims = 0;
  int ndims = 0;
  if (ref->is_resolved)
  if (ref->is_resolved)
    {
    {
      vfy_jclass k = ref->data.klass;
      vfy_jclass k = ref->data.klass;
      while (vfy_is_array (k))
      while (vfy_is_array (k))
        {
        {
          k = vfy_get_component_type (k);
          k = vfy_get_component_type (k);
          ++ndims;
          ++ndims;
        }
        }
    }
    }
  else
  else
    {
    {
      const char *p = vfy_string_bytes (ref->data.name);
      const char *p = vfy_string_bytes (ref->data.name);
      while (*p++ == '[')
      while (*p++ == '[')
        ++ndims;
        ++ndims;
    }
    }
  return ndims;
  return ndims;
}
}
 
 
/* Return the type_val corresponding to a primitive signature
/* Return the type_val corresponding to a primitive signature
   character.  For instance `I' returns `int.class'.  */
   character.  For instance `I' returns `int.class'.  */
static type_val
static type_val
get_type_val_for_signature (char sig)
get_type_val_for_signature (char sig)
{
{
  type_val rt;
  type_val rt;
  switch (sig)
  switch (sig)
    {
    {
    case 'Z':
    case 'Z':
      rt = boolean_type;
      rt = boolean_type;
      break;
      break;
    case 'B':
    case 'B':
      rt = byte_type;
      rt = byte_type;
      break;
      break;
    case 'C':
    case 'C':
      rt = char_type;
      rt = char_type;
      break;
      break;
    case 'S':
    case 'S':
      rt = short_type;
      rt = short_type;
      break;
      break;
    case 'I':
    case 'I':
      rt = int_type;
      rt = int_type;
      break;
      break;
    case 'J':
    case 'J':
      rt = long_type;
      rt = long_type;
      break;
      break;
    case 'F':
    case 'F':
      rt = float_type;
      rt = float_type;
      break;
      break;
    case 'D':
    case 'D':
      rt = double_type;
      rt = double_type;
      break;
      break;
    case 'V':
    case 'V':
      rt = void_type;
      rt = void_type;
      break;
      break;
    default:
    default:
      verify_fail ("invalid signature");
      verify_fail ("invalid signature");
      return null_type;
      return null_type;
    }
    }
  return rt;
  return rt;
}
}
 
 
/* Return the type_val corresponding to a primitive class.  */
/* Return the type_val corresponding to a primitive class.  */
static type_val
static type_val
get_type_val_for_primtype (vfy_jclass k)
get_type_val_for_primtype (vfy_jclass k)
{
{
  return get_type_val_for_signature (vfy_get_primitive_char (k));
  return get_type_val_for_signature (vfy_get_primitive_char (k));
}
}
 
 
/* The `type' class is used to represent a single type in the verifier.  */
/* The `type' class is used to represent a single type in the verifier.  */
struct type
struct type
{
{
  /* The type key.  */
  /* The type key.  */
  type_val key;
  type_val key;
 
 
  /* For reference types, the representation of the type.  */
  /* For reference types, the representation of the type.  */
  ref_intersection *klass;
  ref_intersection *klass;
 
 
  /* This is used in two situations.
  /* This is used in two situations.
 
 
     First, when constructing a new object, it is the PC of the
     First, when constructing a new object, it is the PC of the
     `new' instruction which created the object.  We use the special
     `new' instruction which created the object.  We use the special
     value UNINIT to mean that this is uninitialized.  The special
     value UNINIT to mean that this is uninitialized.  The special
     value SELF is used for the case where the current method is
     value SELF is used for the case where the current method is
     itself the <init> method.  the special value EITHER is used
     itself the <init> method.  the special value EITHER is used
     when we may optionally allow either an uninitialized or
     when we may optionally allow either an uninitialized or
     initialized reference to match.
     initialized reference to match.
 
 
     Second, when the key is return_address_type, this holds the PC
     Second, when the key is return_address_type, this holds the PC
     of the instruction following the `jsr'.  */
     of the instruction following the `jsr'.  */
  int pc;
  int pc;
 
 
#define UNINIT -2
#define UNINIT -2
#define SELF -1
#define SELF -1
#define EITHER -3
#define EITHER -3
};
};
 
 
/* Make a new instance given the type tag.  We assume a generic
/* Make a new instance given the type tag.  We assume a generic
   `reference_type' means Object.  */
   `reference_type' means Object.  */
static void
static void
init_type_from_tag (type *t, type_val k)
init_type_from_tag (type *t, type_val k)
{
{
  t->key = k;
  t->key = k;
  /* For reference_type, if KLASS==NULL then that means we are
  /* For reference_type, if KLASS==NULL then that means we are
     looking for a generic object of any kind, including an
     looking for a generic object of any kind, including an
     uninitialized reference.  */
     uninitialized reference.  */
  t->klass = NULL;
  t->klass = NULL;
  t->pc = UNINIT;
  t->pc = UNINIT;
}
}
 
 
/* Make a type for the given type_val tag K.  */
/* Make a type for the given type_val tag K.  */
static type
static type
make_type (type_val k)
make_type (type_val k)
{
{
  type t;
  type t;
  init_type_from_tag (&t, k);
  init_type_from_tag (&t, k);
  return t;
  return t;
}
}
 
 
/* Make a new instance given a class.  */
/* Make a new instance given a class.  */
static void
static void
init_type_from_class (type *t, vfy_jclass k)
init_type_from_class (type *t, vfy_jclass k)
{
{
  t->key = reference_type;
  t->key = reference_type;
  t->klass = make_ref ();
  t->klass = make_ref ();
  t->klass->is_resolved = true;
  t->klass->is_resolved = true;
  t->klass->data.klass = k;
  t->klass->data.klass = k;
  t->klass->ref_next = NULL;
  t->klass->ref_next = NULL;
  t->pc = UNINIT;
  t->pc = UNINIT;
}
}
 
 
static type
static type
make_type_from_class (vfy_jclass k)
make_type_from_class (vfy_jclass k)
{
{
  type t;
  type t;
  init_type_from_class (&t, k);
  init_type_from_class (&t, k);
  return t;
  return t;
}
}
 
 
static void
static void
init_type_from_string (type *t, vfy_string n)
init_type_from_string (type *t, vfy_string n)
{
{
  t->key = reference_type;
  t->key = reference_type;
  t->klass = make_ref ();
  t->klass = make_ref ();
  t->klass->is_resolved = false;
  t->klass->is_resolved = false;
  t->klass->data.name = n;
  t->klass->data.name = n;
  t->klass->ref_next = NULL;
  t->klass->ref_next = NULL;
  t->pc = UNINIT;
  t->pc = UNINIT;
}
}
 
 
static type
static type
make_type_from_string (vfy_string n)
make_type_from_string (vfy_string n)
{
{
  type t;
  type t;
  init_type_from_string (&t, n);
  init_type_from_string (&t, n);
  return t;
  return t;
}
}
 
 
/* Promote a numeric type.  */
/* Promote a numeric type.  */
static void
static void
vfy_promote_type (type *t)
vfy_promote_type (type *t)
{
{
  if (t->key == boolean_type || t->key == char_type
  if (t->key == boolean_type || t->key == char_type
      || t->key == byte_type || t->key == short_type)
      || t->key == byte_type || t->key == short_type)
    t->key = int_type;
    t->key = int_type;
}
}
#define promote_type vfy_promote_type
#define promote_type vfy_promote_type
 
 
/* Mark this type as the uninitialized result of `new'.  */
/* Mark this type as the uninitialized result of `new'.  */
static void
static void
type_set_uninitialized (type *t, int npc)
type_set_uninitialized (type *t, int npc)
{
{
  if (t->key == reference_type)
  if (t->key == reference_type)
    t->key = uninitialized_reference_type;
    t->key = uninitialized_reference_type;
  else
  else
    verify_fail ("internal error in type::uninitialized");
    verify_fail ("internal error in type::uninitialized");
  t->pc = npc;
  t->pc = npc;
}
}
 
 
/* Mark this type as now initialized.  */
/* Mark this type as now initialized.  */
static void
static void
type_set_initialized (type *t, int npc)
type_set_initialized (type *t, int npc)
{
{
  if (npc != UNINIT && t->pc == npc && t->key == uninitialized_reference_type)
  if (npc != UNINIT && t->pc == npc && t->key == uninitialized_reference_type)
    {
    {
      t->key = reference_type;
      t->key = reference_type;
      t->pc = UNINIT;
      t->pc = UNINIT;
    }
    }
}
}
 
 
/* Mark this type as a particular return address.  */
/* Mark this type as a particular return address.  */
static void type_set_return_address (type *t, int npc)
static void type_set_return_address (type *t, int npc)
{
{
  t->pc = npc;
  t->pc = npc;
}
}
 
 
/* Return true if this type and type OTHER are considered
/* Return true if this type and type OTHER are considered
   mergeable for the purposes of state merging.  This is related
   mergeable for the purposes of state merging.  This is related
   to subroutine handling.  For this purpose two types are
   to subroutine handling.  For this purpose two types are
   considered unmergeable if they are both return-addresses but
   considered unmergeable if they are both return-addresses but
   have different PCs.  */
   have different PCs.  */
static bool
static bool
type_state_mergeable_p (type *t1, type *t2)
type_state_mergeable_p (type *t1, type *t2)
{
{
  return (t1->key != return_address_type
  return (t1->key != return_address_type
          || t2->key != return_address_type
          || t2->key != return_address_type
          || t1->pc == t2->pc);
          || t1->pc == t2->pc);
}
}
 
 
/* Return true if an object of type K can be assigned to a variable
/* Return true if an object of type K can be assigned to a variable
   of type T.  Handle various special cases too.  Might modify
   of type T.  Handle various special cases too.  Might modify
   T or K.  Note however that this does not perform numeric
   T or K.  Note however that this does not perform numeric
   promotion.  */
   promotion.  */
static bool
static bool
types_compatible (type *t, type *k)
types_compatible (type *t, type *k)
{
{
  /* Any type is compatible with the unsuitable type.  */
  /* Any type is compatible with the unsuitable type.  */
  if (k->key == unsuitable_type)
  if (k->key == unsuitable_type)
    return true;
    return true;
 
 
  if (t->key < reference_type || k->key < reference_type)
  if (t->key < reference_type || k->key < reference_type)
    return t->key == k->key;
    return t->key == k->key;
 
 
  /* The `null' type is convertible to any initialized reference
  /* The `null' type is convertible to any initialized reference
     type.  */
     type.  */
  if (t->key == null_type)
  if (t->key == null_type)
    return k->key != uninitialized_reference_type;
    return k->key != uninitialized_reference_type;
  if (k->key == null_type)
  if (k->key == null_type)
    return t->key != uninitialized_reference_type;
    return t->key != uninitialized_reference_type;
 
 
  /* A special case for a generic reference.  */
  /* A special case for a generic reference.  */
  if (t->klass == NULL)
  if (t->klass == NULL)
    return true;
    return true;
  if (k->klass == NULL)
  if (k->klass == NULL)
    verify_fail ("programmer error in type::compatible");
    verify_fail ("programmer error in type::compatible");
 
 
  /* Handle the special 'EITHER' case, which is only used in a
  /* Handle the special 'EITHER' case, which is only used in a
     special case of 'putfield'.  Note that we only need to handle
     special case of 'putfield'.  Note that we only need to handle
     this on the LHS of a check.  */
     this on the LHS of a check.  */
  if (! type_initialized (t) && t->pc == EITHER)
  if (! type_initialized (t) && t->pc == EITHER)
    {
    {
      /* If the RHS is uninitialized, it must be an uninitialized
      /* If the RHS is uninitialized, it must be an uninitialized
         'this'.  */
         'this'.  */
      if (! type_initialized (k) && k->pc != SELF)
      if (! type_initialized (k) && k->pc != SELF)
        return false;
        return false;
    }
    }
  else if (type_initialized (t) != type_initialized (k))
  else if (type_initialized (t) != type_initialized (k))
    {
    {
      /* An initialized type and an uninitialized type are not
      /* An initialized type and an uninitialized type are not
         otherwise compatible.  */
         otherwise compatible.  */
      return false;
      return false;
    }
    }
  else
  else
    {
    {
      /* Two uninitialized objects are compatible if either:
      /* Two uninitialized objects are compatible if either:
       * The PCs are identical, or
       * The PCs are identical, or
       * One PC is UNINIT.  */
       * One PC is UNINIT.  */
      if (type_initialized (t))
      if (type_initialized (t))
        {
        {
          if (t->pc != k->pc && t->pc != UNINIT && k->pc != UNINIT)
          if (t->pc != k->pc && t->pc != UNINIT && k->pc != UNINIT)
            return false;
            return false;
        }
        }
    }
    }
 
 
  return ref_compatible (t->klass, k->klass);
  return ref_compatible (t->klass, k->klass);
}
}
 
 
/* Return true if two types are equal.  Only valid for reference
/* Return true if two types are equal.  Only valid for reference
   types.  */
   types.  */
static bool
static bool
types_equal (type *t1, type *t2)
types_equal (type *t1, type *t2)
{
{
  if ((t1->key != reference_type && t1->key != uninitialized_reference_type)
  if ((t1->key != reference_type && t1->key != uninitialized_reference_type)
      || (t2->key != reference_type
      || (t2->key != reference_type
          && t2->key != uninitialized_reference_type))
          && t2->key != uninitialized_reference_type))
    return false;
    return false;
  /* Only single-ref types are allowed.  */
  /* Only single-ref types are allowed.  */
  if (t1->klass->ref_next || t2->klass->ref_next)
  if (t1->klass->ref_next || t2->klass->ref_next)
    return false;
    return false;
  return refs_equal (t1->klass, t2->klass);
  return refs_equal (t1->klass, t2->klass);
}
}
 
 
static bool
static bool
type_isvoid (type *t)
type_isvoid (type *t)
{
{
  return t->key == void_type;
  return t->key == void_type;
}
}
 
 
static bool
static bool
type_iswide (type *t)
type_iswide (type *t)
{
{
  return t->key == long_type || t->key == double_type;
  return t->key == long_type || t->key == double_type;
}
}
 
 
/* Return number of stack or local variable slots taken by this type.  */
/* Return number of stack or local variable slots taken by this type.  */
static int
static int
type_depth (type *t)
type_depth (type *t)
{
{
  return type_iswide (t) ? 2 : 1;
  return type_iswide (t) ? 2 : 1;
}
}
 
 
static bool
static bool
type_isarray (type *t)
type_isarray (type *t)
{
{
  /* We treat null_type as not an array.  This is ok based on the
  /* We treat null_type as not an array.  This is ok based on the
     current uses of this method.  */
     current uses of this method.  */
  if (t->key == reference_type)
  if (t->key == reference_type)
    return ref_isarray (t->klass);
    return ref_isarray (t->klass);
  return false;
  return false;
}
}
 
 
static bool
static bool
type_isnull (type *t)
type_isnull (type *t)
{
{
  return t->key == null_type;
  return t->key == null_type;
}
}
 
 
static bool
static bool
type_isinterface (type *t)
type_isinterface (type *t)
{
{
  if (t->key != reference_type)
  if (t->key != reference_type)
    return false;
    return false;
  return ref_isinterface (t->klass);
  return ref_isinterface (t->klass);
}
}
 
 
static bool
static bool
type_isabstract (type *t)
type_isabstract (type *t)
{
{
  if (t->key != reference_type)
  if (t->key != reference_type)
    return false;
    return false;
  return ref_isabstract (t->klass);
  return ref_isabstract (t->klass);
}
}
 
 
/* Return the element type of an array.  */
/* Return the element type of an array.  */
static type
static type
type_array_element (type *t)
type_array_element (type *t)
{
{
  type et;
  type et;
  vfy_jclass k;
  vfy_jclass k;
 
 
  if (t->key != reference_type)
  if (t->key != reference_type)
    verify_fail ("programmer error in type::element_type()");
    verify_fail ("programmer error in type::element_type()");
 
 
  k = vfy_get_component_type (ref_getclass (t->klass));
  k = vfy_get_component_type (ref_getclass (t->klass));
  if (vfy_is_primitive (k))
  if (vfy_is_primitive (k))
    init_type_from_tag (&et, get_type_val_for_primtype (k));
    init_type_from_tag (&et, get_type_val_for_primtype (k));
  else
  else
    init_type_from_class (&et, k);
    init_type_from_class (&et, k);
  return et;
  return et;
}
}
 
 
/* Return the array type corresponding to an initialized
/* Return the array type corresponding to an initialized
   reference.  We could expand this to work for other kinds of
   reference.  We could expand this to work for other kinds of
   types, but currently we don't need to.  */
   types, but currently we don't need to.  */
static type
static type
type_to_array (type *t)
type_to_array (type *t)
{
{
  type at;
  type at;
  vfy_jclass k;
  vfy_jclass k;
 
 
  if (t->key != reference_type)
  if (t->key != reference_type)
    verify_fail ("internal error in type::to_array()");
    verify_fail ("internal error in type::to_array()");
 
 
  k = ref_getclass (t->klass);
  k = ref_getclass (t->klass);
  init_type_from_class (&at, vfy_get_array_class (k));
  init_type_from_class (&at, vfy_get_array_class (k));
  return at;
  return at;
}
}
 
 
static bool
static bool
type_isreference (type *t)
type_isreference (type *t)
{
{
  return t->key >= reference_type;
  return t->key >= reference_type;
}
}
 
 
static int
static int
type_get_pc (type *t)
type_get_pc (type *t)
{
{
  return t->pc;
  return t->pc;
}
}
 
 
bool
bool
type_initialized (type *t)
type_initialized (type *t)
{
{
  return t->key == reference_type || t->key == null_type;
  return t->key == reference_type || t->key == null_type;
}
}
 
 
static void
static void
type_verify_dimensions (type *t, int ndims)
type_verify_dimensions (type *t, int ndims)
{
{
  /* The way this is written, we don't need to check isarray().  */
  /* The way this is written, we don't need to check isarray().  */
  if (t->key != reference_type)
  if (t->key != reference_type)
    verify_fail ("internal error in verify_dimensions:"
    verify_fail ("internal error in verify_dimensions:"
                           " not a reference type");
                           " not a reference type");
 
 
  if (ref_count_dimensions (t->klass) < ndims)
  if (ref_count_dimensions (t->klass) < ndims)
    verify_fail ("array type has fewer dimensions"
    verify_fail ("array type has fewer dimensions"
                           " than required");
                           " than required");
}
}
 
 
/* Merge OLD_TYPE into this.  On error throw exception.  Return
/* Merge OLD_TYPE into this.  On error throw exception.  Return
   true if the merge caused a type change.  */
   true if the merge caused a type change.  */
static bool
static bool
merge_types (type *t, type *old_type, bool local_semantics)
merge_types (type *t, type *old_type, bool local_semantics)
{
{
  bool changed = false;
  bool changed = false;
  bool refo = type_isreference (old_type);
  bool refo = type_isreference (old_type);
  bool refn = type_isreference (t);
  bool refn = type_isreference (t);
  if (refo && refn)
  if (refo && refn)
    {
    {
      if (old_type->key == null_type)
      if (old_type->key == null_type)
        ;
        ;
      else if (t->key == null_type)
      else if (t->key == null_type)
        {
        {
          *t = *old_type;
          *t = *old_type;
          changed = true;
          changed = true;
        }
        }
      else if (type_initialized (t) != type_initialized (old_type))
      else if (type_initialized (t) != type_initialized (old_type))
        verify_fail ("merging initialized and uninitialized types");
        verify_fail ("merging initialized and uninitialized types");
      else
      else
        {
        {
          ref_intersection *merged;
          ref_intersection *merged;
          if (! type_initialized (t))
          if (! type_initialized (t))
            {
            {
              if (t->pc == UNINIT)
              if (t->pc == UNINIT)
                t->pc = old_type->pc;
                t->pc = old_type->pc;
              else if (old_type->pc == UNINIT)
              else if (old_type->pc == UNINIT)
                ;
                ;
              else if (t->pc != old_type->pc)
              else if (t->pc != old_type->pc)
                verify_fail ("merging different uninitialized types");
                verify_fail ("merging different uninitialized types");
            }
            }
 
 
          merged = merge_refs (old_type->klass, t->klass);
          merged = merge_refs (old_type->klass, t->klass);
          if (merged != t->klass)
          if (merged != t->klass)
            {
            {
              t->klass = merged;
              t->klass = merged;
              changed = true;
              changed = true;
            }
            }
        }
        }
    }
    }
  else if (refo || refn || t->key != old_type->key)
  else if (refo || refn || t->key != old_type->key)
    {
    {
      if (local_semantics)
      if (local_semantics)
        {
        {
          /* If we already have an `unsuitable' type, then we
          /* If we already have an `unsuitable' type, then we
             don't need to change again.  */
             don't need to change again.  */
          if (t->key != unsuitable_type)
          if (t->key != unsuitable_type)
            {
            {
              t->key = unsuitable_type;
              t->key = unsuitable_type;
              changed = true;
              changed = true;
            }
            }
        }
        }
      else
      else
        verify_fail ("unmergeable type");
        verify_fail ("unmergeable type");
    }
    }
  return changed;
  return changed;
}
}
 
 
#ifdef VERIFY_DEBUG
#ifdef VERIFY_DEBUG
static void
static void
type_print (type *t)
type_print (type *t)
{
{
  char c = '?';
  char c = '?';
  switch (t->key)
  switch (t->key)
    {
    {
    case boolean_type: c = 'Z'; break;
    case boolean_type: c = 'Z'; break;
    case byte_type: c = 'B'; break;
    case byte_type: c = 'B'; break;
    case char_type: c = 'C'; break;
    case char_type: c = 'C'; break;
    case short_type: c = 'S'; break;
    case short_type: c = 'S'; break;
    case int_type: c = 'I'; break;
    case int_type: c = 'I'; break;
    case long_type: c = 'J'; break;
    case long_type: c = 'J'; break;
    case float_type: c = 'F'; break;
    case float_type: c = 'F'; break;
    case double_type: c = 'D'; break;
    case double_type: c = 'D'; break;
    case void_type: c = 'V'; break;
    case void_type: c = 'V'; break;
    case unsuitable_type: c = '-'; break;
    case unsuitable_type: c = '-'; break;
    case return_address_type: c = 'r'; break;
    case return_address_type: c = 'r'; break;
    case continuation_type: c = '+'; break;
    case continuation_type: c = '+'; break;
    case reference_type: c = 'L'; break;
    case reference_type: c = 'L'; break;
    case null_type: c = '@'; break;
    case null_type: c = '@'; break;
    case uninitialized_reference_type: c = 'U'; break;
    case uninitialized_reference_type: c = 'U'; break;
    }
    }
  debug_print ("%c", c);
  debug_print ("%c", c);
}
}
#endif /* VERIFY_DEBUG */
#endif /* VERIFY_DEBUG */
 
 
/* This class holds all the state information we need for a given
/* This class holds all the state information we need for a given
   location. */
   location. */
struct state
struct state
{
{
  /* The current top of the stack, in terms of slots.  */
  /* The current top of the stack, in terms of slots.  */
  int stacktop;
  int stacktop;
  /* The current depth of the stack.  This will be larger than
  /* The current depth of the stack.  This will be larger than
     STACKTOP when wide types are on the stack.  */
     STACKTOP when wide types are on the stack.  */
  int stackdepth;
  int stackdepth;
  /* The stack.  */
  /* The stack.  */
  type *stack;
  type *stack;
  /* The local variables.  */
  /* The local variables.  */
  type *locals;
  type *locals;
  /* We keep track of the type of `this' specially.  This is used to
  /* We keep track of the type of `this' specially.  This is used to
     ensure that an instance initializer invokes another initializer
     ensure that an instance initializer invokes another initializer
     on `this' before returning.  We must keep track of this
     on `this' before returning.  We must keep track of this
     specially because otherwise we might be confused by code which
     specially because otherwise we might be confused by code which
     assigns to locals[0] (overwriting `this') and then returns
     assigns to locals[0] (overwriting `this') and then returns
     without really initializing.  */
     without really initializing.  */
  type this_type;
  type this_type;
 
 
  /* The PC for this state.  This is only valid on states which are
  /* The PC for this state.  This is only valid on states which are
     permanently attached to a given PC.  For an object like
     permanently attached to a given PC.  For an object like
     `current_state', which is used transiently, this has no
     `current_state', which is used transiently, this has no
     meaning.  */
     meaning.  */
  int pc;
  int pc;
  /* We keep a linked list of all states requiring reverification.
  /* We keep a linked list of all states requiring reverification.
     If this is the special value INVALID_STATE then this state is
     If this is the special value INVALID_STATE then this state is
     not on the list.  NULL marks the end of the linked list.  */
     not on the list.  NULL marks the end of the linked list.  */
  state *next;
  state *next;
};
};
 
 
/* NO_NEXT is the PC value meaning that a new state must be
/* NO_NEXT is the PC value meaning that a new state must be
   acquired from the verification list.  */
   acquired from the verification list.  */
#define NO_NEXT -1
#define NO_NEXT -1
 
 
static void
static void
init_state_with_stack (state *s, int max_stack, int max_locals)
init_state_with_stack (state *s, int max_stack, int max_locals)
{
{
  int i;
  int i;
  s->stacktop = 0;
  s->stacktop = 0;
  s->stackdepth = 0;
  s->stackdepth = 0;
  s->stack = (type *) vfy_alloc (max_stack * sizeof (type));
  s->stack = (type *) vfy_alloc (max_stack * sizeof (type));
  for (i = 0; i < max_stack; ++i)
  for (i = 0; i < max_stack; ++i)
    init_type_from_tag (&s->stack[i], unsuitable_type);
    init_type_from_tag (&s->stack[i], unsuitable_type);
  s->locals = (type *) vfy_alloc (max_locals * sizeof (type));
  s->locals = (type *) vfy_alloc (max_locals * sizeof (type));
  for (i = 0; i < max_locals; ++i)
  for (i = 0; i < max_locals; ++i)
    init_type_from_tag (&s->locals[i], unsuitable_type);
    init_type_from_tag (&s->locals[i], unsuitable_type);
  init_type_from_tag (&s->this_type, unsuitable_type);
  init_type_from_tag (&s->this_type, unsuitable_type);
  s->pc = NO_NEXT;
  s->pc = NO_NEXT;
  s->next = INVALID_STATE;
  s->next = INVALID_STATE;
}
}
 
 
static void
static void
copy_state (state *s, state *copy, int max_stack, int max_locals)
copy_state (state *s, state *copy, int max_stack, int max_locals)
{
{
  int i;
  int i;
  s->stacktop = copy->stacktop;
  s->stacktop = copy->stacktop;
  s->stackdepth = copy->stackdepth;
  s->stackdepth = copy->stackdepth;
  for (i = 0; i < max_stack; ++i)
  for (i = 0; i < max_stack; ++i)
    s->stack[i] = copy->stack[i];
    s->stack[i] = copy->stack[i];
  for (i = 0; i < max_locals; ++i)
  for (i = 0; i < max_locals; ++i)
    s->locals[i] = copy->locals[i];
    s->locals[i] = copy->locals[i];
 
 
  s->this_type = copy->this_type;
  s->this_type = copy->this_type;
  /* Don't modify `next' or `pc'. */
  /* Don't modify `next' or `pc'. */
}
}
 
 
static void
static void
copy_state_with_stack (state *s, state *orig, int max_stack, int max_locals)
copy_state_with_stack (state *s, state *orig, int max_stack, int max_locals)
{
{
  init_state_with_stack (s, max_stack, max_locals);
  init_state_with_stack (s, max_stack, max_locals);
  copy_state (s, orig, max_stack, max_locals);
  copy_state (s, orig, max_stack, max_locals);
}
}
 
 
/* Allocate a new state, copying ORIG. */
/* Allocate a new state, copying ORIG. */
static state *
static state *
make_state_copy (state *orig, int max_stack, int max_locals)
make_state_copy (state *orig, int max_stack, int max_locals)
{
{
  state *s = (state *) vfy_alloc (sizeof (state));
  state *s = (state *) vfy_alloc (sizeof (state));
  copy_state_with_stack (s, orig, max_stack, max_locals);
  copy_state_with_stack (s, orig, max_stack, max_locals);
  return s;
  return s;
}
}
 
 
static state *
static state *
make_state (int max_stack, int max_locals)
make_state (int max_stack, int max_locals)
{
{
  state *s = (state *) vfy_alloc (sizeof (state));
  state *s = (state *) vfy_alloc (sizeof (state));
  init_state_with_stack (s, max_stack, max_locals);
  init_state_with_stack (s, max_stack, max_locals);
  return s;
  return s;
}
}
 
 
static void
static void
free_state (state *s)
free_state (state *s)
{
{
  if (s->stack != NULL)
  if (s->stack != NULL)
    vfy_free (s->stack);
    vfy_free (s->stack);
  if (s->locals != NULL)
  if (s->locals != NULL)
    vfy_free (s->locals);
    vfy_free (s->locals);
}
}
 
 
/* Modify this state to reflect entry to an exception handler.  */
/* Modify this state to reflect entry to an exception handler.  */
static void
static void
state_set_exception (state *s, type *t, int max_stack)
state_set_exception (state *s, type *t, int max_stack)
{
{
  int i;
  int i;
  s->stackdepth = 1;
  s->stackdepth = 1;
  s->stacktop = 1;
  s->stacktop = 1;
  s->stack[0] = *t;
  s->stack[0] = *t;
  for (i = s->stacktop; i < max_stack; ++i)
  for (i = s->stacktop; i < max_stack; ++i)
    init_type_from_tag (&s->stack[i], unsuitable_type);
    init_type_from_tag (&s->stack[i], unsuitable_type);
}
}
 
 
/* Merge STATE_OLD into this state.  Destructively modifies this
/* Merge STATE_OLD into this state.  Destructively modifies this
   state.  Returns true if the new state was in fact changed.
   state.  Returns true if the new state was in fact changed.
   Will throw an exception if the states are not mergeable.  */
   Will throw an exception if the states are not mergeable.  */
static bool
static bool
merge_states (state *s, state *state_old, int max_locals)
merge_states (state *s, state *state_old, int max_locals)
{
{
  int i;
  int i;
  bool changed = false;
  bool changed = false;
 
 
  /* Special handling for `this'.  If one or the other is
  /* Special handling for `this'.  If one or the other is
     uninitialized, then the merge is uninitialized.  */
     uninitialized, then the merge is uninitialized.  */
  if (type_initialized (&s->this_type))
  if (type_initialized (&s->this_type))
    s->this_type = state_old->this_type;
    s->this_type = state_old->this_type;
 
 
  /* Merge stacks.  */
  /* Merge stacks.  */
  if (state_old->stacktop != s->stacktop)  /* FIXME stackdepth instead?  */
  if (state_old->stacktop != s->stacktop)  /* FIXME stackdepth instead?  */
    verify_fail ("stack sizes differ");
    verify_fail ("stack sizes differ");
  for (i = 0; i < state_old->stacktop; ++i)
  for (i = 0; i < state_old->stacktop; ++i)
    {
    {
      if (merge_types (&s->stack[i], &state_old->stack[i], false))
      if (merge_types (&s->stack[i], &state_old->stack[i], false))
        changed = true;
        changed = true;
    }
    }
 
 
  /* Merge local variables.  */
  /* Merge local variables.  */
  for (i = 0; i < max_locals; ++i)
  for (i = 0; i < max_locals; ++i)
    {
    {
      if (merge_types (&s->locals[i], &state_old->locals[i], true))
      if (merge_types (&s->locals[i], &state_old->locals[i], true))
        changed = true;
        changed = true;
    }
    }
 
 
  return changed;
  return changed;
}
}
 
 
/* Ensure that `this' has been initialized.  */
/* Ensure that `this' has been initialized.  */
static void
static void
state_check_this_initialized (state *s)
state_check_this_initialized (state *s)
{
{
  if (type_isreference (&s->this_type) && ! type_initialized (&s->this_type))
  if (type_isreference (&s->this_type) && ! type_initialized (&s->this_type))
    verify_fail ("`this' is uninitialized");
    verify_fail ("`this' is uninitialized");
}
}
 
 
/* Set type of `this'.  */
/* Set type of `this'.  */
static void
static void
state_set_this_type (state *s, type *k)
state_set_this_type (state *s, type *k)
{
{
  s->this_type = *k;
  s->this_type = *k;
}
}
 
 
/* Mark each `new'd object we know of that was allocated at PC as
/* Mark each `new'd object we know of that was allocated at PC as
   initialized.  */
   initialized.  */
static void
static void
state_set_initialized (state *s, int pc, int max_locals)
state_set_initialized (state *s, int pc, int max_locals)
{
{
  int i;
  int i;
  for (i = 0; i < s->stacktop; ++i)
  for (i = 0; i < s->stacktop; ++i)
    type_set_initialized (&s->stack[i], pc);
    type_set_initialized (&s->stack[i], pc);
  for (i = 0; i < max_locals; ++i)
  for (i = 0; i < max_locals; ++i)
    type_set_initialized (&s->locals[i], pc);
    type_set_initialized (&s->locals[i], pc);
  type_set_initialized (&s->this_type, pc);
  type_set_initialized (&s->this_type, pc);
}
}
 
 
/* This tests to see whether two states can be considered "merge
/* This tests to see whether two states can be considered "merge
   compatible".  If both states have a return-address in the same
   compatible".  If both states have a return-address in the same
   slot, and the return addresses are different, then they are not
   slot, and the return addresses are different, then they are not
   compatible and we must not try to merge them.  */
   compatible and we must not try to merge them.  */
static bool
static bool
state_mergeable_p (state *s, state *other, int max_locals)
state_mergeable_p (state *s, state *other, int max_locals)
 
 
{
{
  int i;
  int i;
 
 
  /* This is tricky: if the stack sizes differ, then not only are
  /* This is tricky: if the stack sizes differ, then not only are
     these not mergeable, but in fact we should give an error, as
     these not mergeable, but in fact we should give an error, as
     we've found two execution paths that reach a branch target
     we've found two execution paths that reach a branch target
     with different stack depths.  FIXME stackdepth instead?  */
     with different stack depths.  FIXME stackdepth instead?  */
  if (s->stacktop != other->stacktop)
  if (s->stacktop != other->stacktop)
    verify_fail ("stack sizes differ");
    verify_fail ("stack sizes differ");
 
 
  for (i = 0; i < s->stacktop; ++i)
  for (i = 0; i < s->stacktop; ++i)
    if (! type_state_mergeable_p (&s->stack[i], &other->stack[i]))
    if (! type_state_mergeable_p (&s->stack[i], &other->stack[i]))
      return false;
      return false;
  for (i = 0; i < max_locals; ++i)
  for (i = 0; i < max_locals; ++i)
    if (! type_state_mergeable_p (&s->locals[i], &other->locals[i]))
    if (! type_state_mergeable_p (&s->locals[i], &other->locals[i]))
      return false;
      return false;
  return true;
  return true;
}
}
 
 
static void
static void
state_reverify (state *s)
state_reverify (state *s)
{
{
  if (s->next == INVALID_STATE)
  if (s->next == INVALID_STATE)
    {
    {
      s->next = vfr->next_verify_state;
      s->next = vfr->next_verify_state;
      vfr->next_verify_state = s;
      vfr->next_verify_state = s;
    }
    }
}
}
 
 
#ifdef VERIFY_DEBUG
#ifdef VERIFY_DEBUG
static void
static void
debug_print_state (state *s, const char *leader, int pc, int max_stack,
debug_print_state (state *s, const char *leader, int pc, int max_stack,
                   int max_locals)
                   int max_locals)
{
{
  int i;
  int i;
  debug_print ("%s [%4d]:   [stack] ", leader, pc);
  debug_print ("%s [%4d]:   [stack] ", leader, pc);
  for (i = 0; i < s->stacktop; ++i)
  for (i = 0; i < s->stacktop; ++i)
    type_print (&s->stack[i]);
    type_print (&s->stack[i]);
  for (; i < max_stack; ++i)
  for (; i < max_stack; ++i)
    debug_print (".");
    debug_print (".");
  debug_print ("    [local] ");
  debug_print ("    [local] ");
  for (i = 0; i < max_locals; ++i)
  for (i = 0; i < max_locals; ++i)
    type_print (&s->locals[i]);
    type_print (&s->locals[i]);
  debug_print (" | %p\n", s);
  debug_print (" | %p\n", s);
}
}
#else
#else
static void
static void
debug_print_state (state *s ATTRIBUTE_UNUSED,
debug_print_state (state *s ATTRIBUTE_UNUSED,
                   const char *leader ATTRIBUTE_UNUSED,
                   const char *leader ATTRIBUTE_UNUSED,
                   int pc ATTRIBUTE_UNUSED, int max_stack ATTRIBUTE_UNUSED,
                   int pc ATTRIBUTE_UNUSED, int max_stack ATTRIBUTE_UNUSED,
                   int max_locals ATTRIBUTE_UNUSED)
                   int max_locals ATTRIBUTE_UNUSED)
{
{
}
}
#endif /* VERIFY_DEBUG */
#endif /* VERIFY_DEBUG */
 
 
static type
static type
pop_raw (void)
pop_raw (void)
{
{
  type r;
  type r;
  state *s = vfr->current_state;
  state *s = vfr->current_state;
  if (s->stacktop <= 0)
  if (s->stacktop <= 0)
    verify_fail ("stack empty");
    verify_fail ("stack empty");
  r = s->stack[--s->stacktop];
  r = s->stack[--s->stacktop];
  s->stackdepth -= type_depth (&r);
  s->stackdepth -= type_depth (&r);
  if (s->stackdepth < 0)
  if (s->stackdepth < 0)
    verify_fail_pc ("stack empty", vfr->start_PC);
    verify_fail_pc ("stack empty", vfr->start_PC);
  return r;
  return r;
}
}
 
 
static type
static type
pop32 (void)
pop32 (void)
{
{
  type r = pop_raw ();
  type r = pop_raw ();
  if (type_iswide (&r))
  if (type_iswide (&r))
    verify_fail ("narrow pop of wide type");
    verify_fail ("narrow pop of wide type");
  return r;
  return r;
}
}
 
 
static type
static type
vfy_pop_type_t (type match)
vfy_pop_type_t (type match)
{
{
  type t;
  type t;
  vfy_promote_type (&match);
  vfy_promote_type (&match);
  t = pop_raw ();
  t = pop_raw ();
  if (! types_compatible (&match, &t))
  if (! types_compatible (&match, &t))
    verify_fail ("incompatible type on stack");
    verify_fail ("incompatible type on stack");
  return t;
  return t;
}
}
 
 
static type
static type
vfy_pop_type (type_val match)
vfy_pop_type (type_val match)
{
{
  type t = make_type (match);
  type t = make_type (match);
  return vfy_pop_type_t (t);
  return vfy_pop_type_t (t);
}
}
 
 
#define pop_type vfy_pop_type
#define pop_type vfy_pop_type
#define pop_type_t vfy_pop_type_t
#define pop_type_t vfy_pop_type_t
 
 
/* Pop a reference which is guaranteed to be initialized.  MATCH
/* Pop a reference which is guaranteed to be initialized.  MATCH
   doesn't have to be a reference type; in this case this acts like
   doesn't have to be a reference type; in this case this acts like
   pop_type.  */
   pop_type.  */
static type
static type
pop_init_ref_t (type match)
pop_init_ref_t (type match)
{
{
  type t = pop_raw ();
  type t = pop_raw ();
  if (type_isreference (&t) && ! type_initialized (&t))
  if (type_isreference (&t) && ! type_initialized (&t))
    verify_fail ("initialized reference required");
    verify_fail ("initialized reference required");
  else if (! types_compatible (&match, &t))
  else if (! types_compatible (&match, &t))
    verify_fail ("incompatible type on stack");
    verify_fail ("incompatible type on stack");
  return t;
  return t;
}
}
 
 
static type
static type
pop_init_ref (type_val match)
pop_init_ref (type_val match)
{
{
  type t = make_type (match);
  type t = make_type (match);
  return pop_init_ref_t (t);
  return pop_init_ref_t (t);
}
}
 
 
/* Pop a reference type or a return address.  */
/* Pop a reference type or a return address.  */
static type
static type
pop_ref_or_return (void)
pop_ref_or_return (void)
{
{
  type t = pop_raw ();
  type t = pop_raw ();
  if (! type_isreference (&t) && t.key != return_address_type)
  if (! type_isreference (&t) && t.key != return_address_type)
    verify_fail ("expected reference or return address on stack");
    verify_fail ("expected reference or return address on stack");
  return t;
  return t;
}
}
 
 
static void
static void
vfy_push_type_t (type t)
vfy_push_type_t (type t)
{
{
  int depth;
  int depth;
  state *s = vfr->current_state;
  state *s = vfr->current_state;
  /* If T is a numeric type like short, promote it to int.  */
  /* If T is a numeric type like short, promote it to int.  */
  promote_type (&t);
  promote_type (&t);
 
 
  depth = type_depth (&t);
  depth = type_depth (&t);
 
 
  if (s->stackdepth + depth > vfr->current_method->max_stack)
  if (s->stackdepth + depth > vfr->current_method->max_stack)
    verify_fail ("stack overflow");
    verify_fail ("stack overflow");
  s->stack[s->stacktop++] = t;
  s->stack[s->stacktop++] = t;
  s->stackdepth += depth;
  s->stackdepth += depth;
}
}
 
 
static void
static void
vfy_push_type (type_val tval)
vfy_push_type (type_val tval)
{
{
  type t = make_type (tval);
  type t = make_type (tval);
  vfy_push_type_t (t);
  vfy_push_type_t (t);
}
}
 
 
#define push_type vfy_push_type
#define push_type vfy_push_type
#define push_type_t vfy_push_type_t
#define push_type_t vfy_push_type_t
 
 
static void
static void
set_variable (int index, type t)
set_variable (int index, type t)
{
{
  int depth;
  int depth;
  state *s = vfr->current_state;
  state *s = vfr->current_state;
  /* If T is a numeric type like short, promote it to int.  */
  /* If T is a numeric type like short, promote it to int.  */
  promote_type (&t);
  promote_type (&t);
 
 
  depth = type_depth (&t);
  depth = type_depth (&t);
  if (index > vfr->current_method->max_locals - depth)
  if (index > vfr->current_method->max_locals - depth)
    verify_fail ("invalid local variable");
    verify_fail ("invalid local variable");
  s->locals[index] = t;
  s->locals[index] = t;
 
 
  if (depth == 2)
  if (depth == 2)
    init_type_from_tag (&s->locals[index + 1], continuation_type);
    init_type_from_tag (&s->locals[index + 1], continuation_type);
  if (index > 0 && type_iswide (&s->locals[index - 1]))
  if (index > 0 && type_iswide (&s->locals[index - 1]))
    init_type_from_tag (&s->locals[index - 1], unsuitable_type);
    init_type_from_tag (&s->locals[index - 1], unsuitable_type);
}
}
 
 
static type
static type
get_variable_t (int index, type *t)
get_variable_t (int index, type *t)
{
{
  state *s = vfr->current_state;
  state *s = vfr->current_state;
  int depth = type_depth (t);
  int depth = type_depth (t);
  if (index > vfr->current_method->max_locals - depth)
  if (index > vfr->current_method->max_locals - depth)
    verify_fail ("invalid local variable");
    verify_fail ("invalid local variable");
  if (! types_compatible (t, &s->locals[index]))
  if (! types_compatible (t, &s->locals[index]))
    verify_fail ("incompatible type in local variable");
    verify_fail ("incompatible type in local variable");
  if (depth == 2)
  if (depth == 2)
    {
    {
      type cont = make_type (continuation_type);
      type cont = make_type (continuation_type);
      if (! types_compatible (&s->locals[index + 1], &cont))
      if (! types_compatible (&s->locals[index + 1], &cont))
        verify_fail ("invalid local variable");
        verify_fail ("invalid local variable");
    }
    }
  return s->locals[index];
  return s->locals[index];
}
}
 
 
static type
static type
get_variable (int index, type_val v)
get_variable (int index, type_val v)
{
{
  type t = make_type (v);
  type t = make_type (v);
  return get_variable_t (index, &t);
  return get_variable_t (index, &t);
}
}
 
 
/* Make sure ARRAY is an array type and that its elements are
/* Make sure ARRAY is an array type and that its elements are
   compatible with type ELEMENT.  Returns the actual element type.  */
   compatible with type ELEMENT.  Returns the actual element type.  */
static type
static type
require_array_type_t (type array, type element)
require_array_type_t (type array, type element)
{
{
  type t;
  type t;
  /* An odd case.  Here we just pretend that everything went ok.  If
  /* An odd case.  Here we just pretend that everything went ok.  If
     the requested element type is some kind of reference, return
     the requested element type is some kind of reference, return
     the null type instead.  */
     the null type instead.  */
  if (type_isnull (&array))
  if (type_isnull (&array))
    return type_isreference (&element) ? make_type (null_type) : element;
    return type_isreference (&element) ? make_type (null_type) : element;
 
 
  if (! type_isarray (&array))
  if (! type_isarray (&array))
    verify_fail ("array required");
    verify_fail ("array required");
 
 
  t = type_array_element (&array);
  t = type_array_element (&array);
  if (! types_compatible (&element, &t))
  if (! types_compatible (&element, &t))
    {
    {
      /* Special case for byte arrays, which must also be boolean
      /* Special case for byte arrays, which must also be boolean
         arrays.  */
         arrays.  */
      bool ok = true;
      bool ok = true;
      if (element.key == byte_type)
      if (element.key == byte_type)
        {
        {
          type e2 = make_type (boolean_type);
          type e2 = make_type (boolean_type);
          ok = types_compatible (&e2, &t);
          ok = types_compatible (&e2, &t);
        }
        }
      if (! ok)
      if (! ok)
        verify_fail ("incompatible array element type");
        verify_fail ("incompatible array element type");
    }
    }
 
 
  /* Return T and not ELEMENT, because T might be specialized.  */
  /* Return T and not ELEMENT, because T might be specialized.  */
  return t;
  return t;
}
}
 
 
static type
static type
require_array_type (type array, type_val element)
require_array_type (type array, type_val element)
{
{
  type t = make_type (element);
  type t = make_type (element);
  return require_array_type_t (array, t);
  return require_array_type_t (array, t);
}
}
 
 
static jint
static jint
get_byte (void)
get_byte (void)
{
{
  if (vfr->PC >= vfr->current_method->code_length)
  if (vfr->PC >= vfr->current_method->code_length)
    verify_fail ("premature end of bytecode");
    verify_fail ("premature end of bytecode");
  return (jint) vfr->bytecode[vfr->PC++] & 0xff;
  return (jint) vfr->bytecode[vfr->PC++] & 0xff;
}
}
 
 
static jint
static jint
get_ushort (void)
get_ushort (void)
{
{
  jint b1 = get_byte ();
  jint b1 = get_byte ();
  jint b2 = get_byte ();
  jint b2 = get_byte ();
  return (jint) ((b1 << 8) | b2) & 0xffff;
  return (jint) ((b1 << 8) | b2) & 0xffff;
}
}
 
 
static jint
static jint
get_short (void)
get_short (void)
{
{
  signed char b1 = (signed char) get_byte ();
  signed char b1 = (signed char) get_byte ();
  jint b2 = get_byte ();
  jint b2 = get_byte ();
  jshort s = (b1 << 8) | b2;
  jshort s = (b1 << 8) | b2;
  return (jint) s;
  return (jint) s;
}
}
 
 
static jint
static jint
get_int (void)
get_int (void)
{
{
  jint b1 = get_byte ();
  jint b1 = get_byte ();
  jint b2 = get_byte ();
  jint b2 = get_byte ();
  jint b3 = get_byte ();
  jint b3 = get_byte ();
  jint b4 = get_byte ();
  jint b4 = get_byte ();
  jword result = (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
  /* In the compiler, 'jint' might have more than 32 bits, so we must
     sign extend.  */
     sign extend.  */
  return WORD_TO_INT (result);
  return WORD_TO_INT (result);
}
}
 
 
static int
static int
compute_jump (int offset)
compute_jump (int offset)
{
{
  int npc = vfr->start_PC + offset;
  int npc = vfr->start_PC + offset;
  if (npc < 0 || npc >= vfr->current_method->code_length)
  if (npc < 0 || npc >= vfr->current_method->code_length)
    verify_fail_pc ("branch out of range", vfr->start_PC);
    verify_fail_pc ("branch out of range", vfr->start_PC);
  return npc;
  return npc;
}
}
 
 
/* Add a new state to the state list at NPC.  */
/* Add a new state to the state list at NPC.  */
static state *
static state *
add_new_state (int npc, state *old_state)
add_new_state (int npc, state *old_state)
{
{
  state_list *nlink;
  state_list *nlink;
  vfy_method *current_method = vfr->current_method;
  vfy_method *current_method = vfr->current_method;
  state *new_state = make_state_copy (old_state, current_method->max_stack,
  state *new_state = make_state_copy (old_state, current_method->max_stack,
                                      current_method->max_locals);
                                      current_method->max_locals);
  debug_print ("== New state in add_new_state\n");
  debug_print ("== New state in add_new_state\n");
  debug_print_state (new_state, "New", npc, current_method->max_stack,
  debug_print_state (new_state, "New", npc, current_method->max_stack,
                    current_method->max_locals);
                    current_method->max_locals);
 
 
  nlink = (state_list *) vfy_alloc (sizeof (state_list));
  nlink = (state_list *) vfy_alloc (sizeof (state_list));
  nlink->val = new_state;
  nlink->val = new_state;
  nlink->next = vfr->states[npc];
  nlink->next = vfr->states[npc];
  vfr->states[npc] = nlink;
  vfr->states[npc] = nlink;
  new_state->pc = npc;
  new_state->pc = npc;
  return new_state;
  return new_state;
}
}
 
 
/* Merge the indicated state into the state at the branch target and
/* Merge the indicated state into the state at the branch target and
   schedule a new PC if there is a change.  NPC is the PC of the
   schedule a new PC if there is a change.  NPC is the PC of the
   branch target, and FROM_STATE is the state at the source of the
   branch target, and FROM_STATE is the state at the source of the
   branch.  This method returns true if the destination state
   branch.  This method returns true if the destination state
   changed and requires reverification, false otherwise.  */
   changed and requires reverification, false otherwise.  */
static void
static void
merge_into (int npc, state *from_state)
merge_into (int npc, state *from_state)
{
{
  /* Iterate over all target states and merge our state into each,
  /* Iterate over all target states and merge our state into each,
     if applicable.  FIXME one improvement we could make here is
     if applicable.  FIXME one improvement we could make here is
     "state destruction".  Merging a new state into an existing one
     "state destruction".  Merging a new state into an existing one
     might cause a return_address_type to be merged to
     might cause a return_address_type to be merged to
     unsuitable_type.  In this case the resulting state may now be
     unsuitable_type.  In this case the resulting state may now be
     mergeable with other states currently held in parallel at this
     mergeable with other states currently held in parallel at this
     location.  So in this situation we could pairwise compare and
     location.  So in this situation we could pairwise compare and
     reduce the number of parallel states.  */
     reduce the number of parallel states.  */
  state_list *iter;
  state_list *iter;
  bool applicable = false;
  bool applicable = false;
  for (iter = vfr->states[npc]; iter != NULL; iter = iter->next)
  for (iter = vfr->states[npc]; iter != NULL; iter = iter->next)
    {
    {
      state *new_state = iter->val;
      state *new_state = iter->val;
      vfy_method *current_method = vfr->current_method;
      vfy_method *current_method = vfr->current_method;
 
 
      if (state_mergeable_p (new_state, from_state,
      if (state_mergeable_p (new_state, from_state,
                                        current_method->max_locals))
                                        current_method->max_locals))
        {
        {
          bool changed;
          bool changed;
          applicable = true;
          applicable = true;
 
 
          debug_print ("== Merge states in merge_into\n");
          debug_print ("== Merge states in merge_into\n");
          debug_print_state (from_state, "Frm", vfr->start_PC, current_method->max_stack,
          debug_print_state (from_state, "Frm", vfr->start_PC, current_method->max_stack,
                             current_method->max_locals);
                             current_method->max_locals);
          debug_print_state (new_state, " To", npc, current_method->max_stack,
          debug_print_state (new_state, " To", npc, current_method->max_stack,
                            current_method->max_locals);
                            current_method->max_locals);
          changed = merge_states (new_state, from_state,
          changed = merge_states (new_state, from_state,
                                  current_method->max_locals);
                                  current_method->max_locals);
          debug_print_state (new_state, "New", npc, current_method->max_stack,
          debug_print_state (new_state, "New", npc, current_method->max_stack,
                            current_method->max_locals);
                            current_method->max_locals);
 
 
          if (changed)
          if (changed)
            state_reverify (new_state);
            state_reverify (new_state);
        }
        }
    }
    }
 
 
  if (! applicable)
  if (! applicable)
    {
    {
      /* Either we don't yet have a state at NPC, or we have a
      /* Either we don't yet have a state at NPC, or we have a
         return-address type that is in conflict with all existing
         return-address type that is in conflict with all existing
         state.  So, we need to create a new entry.  */
         state.  So, we need to create a new entry.  */
      state *new_state = add_new_state (npc, from_state);
      state *new_state = add_new_state (npc, from_state);
      /* A new state added in this way must always be reverified.  */
      /* A new state added in this way must always be reverified.  */
      state_reverify (new_state);
      state_reverify (new_state);
    }
    }
}
}
 
 
static void
static void
push_jump (int offset)
push_jump (int offset)
{
{
  int npc = compute_jump (offset);
  int npc = compute_jump (offset);
  /* According to the JVM Spec, we need to check for uninitialized
  /* According to the JVM Spec, we need to check for uninitialized
     objects here.  However, this does not actually affect type
     objects here.  However, this does not actually affect type
     safety, and the Eclipse java compiler generates code that
     safety, and the Eclipse java compiler generates code that
     violates this constraint.  */
     violates this constraint.  */
  merge_into (npc, vfr->current_state);
  merge_into (npc, vfr->current_state);
}
}
 
 
static void
static void
push_exception_jump (type t, int pc)
push_exception_jump (type t, int pc)
{
{
  state s;
  state s;
  /* According to the JVM Spec, we need to check for uninitialized
  /* According to the JVM Spec, we need to check for uninitialized
     objects here.  However, this does not actually affect type
     objects here.  However, this does not actually affect type
     safety, and the Eclipse java compiler generates code that
     safety, and the Eclipse java compiler generates code that
     violates this constraint.  */
     violates this constraint.  */
  copy_state_with_stack (&s, vfr->current_state,
  copy_state_with_stack (&s, vfr->current_state,
                         vfr->current_method->max_stack,
                         vfr->current_method->max_stack,
                         vfr->current_method->max_locals);
                         vfr->current_method->max_locals);
  if (vfr->current_method->max_stack < 1)
  if (vfr->current_method->max_stack < 1)
    verify_fail ("stack overflow at exception handler");
    verify_fail ("stack overflow at exception handler");
  state_set_exception (&s, &t, vfr->current_method->max_stack);
  state_set_exception (&s, &t, vfr->current_method->max_stack);
  merge_into (pc, &s);
  merge_into (pc, &s);
  /* FIXME: leak.. need free_state or GC */
  /* FIXME: leak.. need free_state or GC */
}
}
 
 
static state *
static state *
pop_jump (void)
pop_jump (void)
{
{
  state *new_state = vfr->next_verify_state;
  state *new_state = vfr->next_verify_state;
  if (new_state == INVALID_STATE)
  if (new_state == INVALID_STATE)
    verify_fail ("programmer error in pop_jump");
    verify_fail ("programmer error in pop_jump");
  if (new_state != NULL)
  if (new_state != NULL)
    {
    {
      vfr->next_verify_state = new_state->next;
      vfr->next_verify_state = new_state->next;
      new_state->next = INVALID_STATE;
      new_state->next = INVALID_STATE;
    }
    }
  return new_state;
  return new_state;
}
}
 
 
static void
static void
invalidate_pc (void)
invalidate_pc (void)
{
{
  vfr->PC = NO_NEXT;
  vfr->PC = NO_NEXT;
}
}
 
 
static void
static void
note_branch_target (int pc)
note_branch_target (int pc)
{
{
  /* Don't check `pc <= PC', because we've advanced PC after
  /* Don't check `pc <= PC', because we've advanced PC after
     fetching the target and we haven't yet checked the next
     fetching the target and we haven't yet checked the next
     instruction.  */
     instruction.  */
  if (pc < vfr->PC && ! (vfr->flags[pc] & FLAG_INSN_START))
  if (pc < vfr->PC && ! (vfr->flags[pc] & FLAG_INSN_START))
    verify_fail_pc ("branch not to instruction start", vfr->start_PC);
    verify_fail_pc ("branch not to instruction start", vfr->start_PC);
  vfr->flags[pc] |= FLAG_BRANCH_TARGET;
  vfr->flags[pc] |= FLAG_BRANCH_TARGET;
}
}
 
 
static void
static void
skip_padding (void)
skip_padding (void)
{
{
  while ((vfr->PC % 4) > 0)
  while ((vfr->PC % 4) > 0)
    if (get_byte () != 0)
    if (get_byte () != 0)
      verify_fail ("found nonzero padding byte");
      verify_fail ("found nonzero padding byte");
}
}
 
 
/* Do the work for a `ret' instruction.  INDEX is the index into the
/* Do the work for a `ret' instruction.  INDEX is the index into the
   local variables.  */
   local variables.  */
static void
static void
handle_ret_insn (int index)
handle_ret_insn (int index)
{
{
  type ret = make_type (return_address_type);
  type ret = make_type (return_address_type);
  type ret_addr = get_variable_t (index, &ret);
  type ret_addr = get_variable_t (index, &ret);
  /* It would be nice if we could do this.  However, the JVM Spec
  /* It would be nice if we could do this.  However, the JVM Spec
     doesn't say that this is what happens.  It is implied that
     doesn't say that this is what happens.  It is implied that
     reusing a return address is invalid, but there's no actual
     reusing a return address is invalid, but there's no actual
     prohibition against it.  */
     prohibition against it.  */
  /* set_variable (index, unsuitable_type); */
  /* set_variable (index, unsuitable_type); */
 
 
  int npc = type_get_pc (&ret_addr);
  int npc = type_get_pc (&ret_addr);
  /* We might be returning to a `jsr' that is at the end of the
  /* We might be returning to a `jsr' that is at the end of the
     bytecode.  This is ok if we never return from the called
     bytecode.  This is ok if we never return from the called
     subroutine, but if we see this here it is an error.  */
     subroutine, but if we see this here it is an error.  */
  if (npc >= vfr->current_method->code_length)
  if (npc >= vfr->current_method->code_length)
    verify_fail ("fell off end");
    verify_fail ("fell off end");
 
 
  /* According to the JVM Spec, we need to check for uninitialized
  /* According to the JVM Spec, we need to check for uninitialized
     objects here.  However, this does not actually affect type
     objects here.  However, this does not actually affect type
     safety, and the Eclipse java compiler generates code that
     safety, and the Eclipse java compiler generates code that
     violates this constraint.  */
     violates this constraint.  */
  merge_into (npc, vfr->current_state);
  merge_into (npc, vfr->current_state);
  invalidate_pc ();
  invalidate_pc ();
}
}
 
 
static void handle_jsr_insn (int offset)
static void handle_jsr_insn (int offset)
{
{
  type ret_addr;
  type ret_addr;
  int npc = compute_jump (offset);
  int npc = compute_jump (offset);
 
 
  /* According to the JVM Spec, we need to check for uninitialized
  /* According to the JVM Spec, we need to check for uninitialized
     objects here.  However, this does not actually affect type
     objects here.  However, this does not actually affect type
     safety, and the Eclipse java compiler generates code that
     safety, and the Eclipse java compiler generates code that
     violates this constraint.  */
     violates this constraint.  */
 
 
  /* Modify our state as appropriate for entry into a subroutine.  */
  /* Modify our state as appropriate for entry into a subroutine.  */
  ret_addr = make_type (return_address_type);
  ret_addr = make_type (return_address_type);
  type_set_return_address (&ret_addr, vfr->PC);
  type_set_return_address (&ret_addr, vfr->PC);
  vfy_push_type_t (ret_addr);
  vfy_push_type_t (ret_addr);
  merge_into (npc, vfr->current_state);
  merge_into (npc, vfr->current_state);
  invalidate_pc ();
  invalidate_pc ();
}
}
 
 
static vfy_jclass
static vfy_jclass
construct_primitive_array_type (type_val prim)
construct_primitive_array_type (type_val prim)
{
{
  vfy_jclass k = NULL;
  vfy_jclass k = NULL;
  switch (prim)
  switch (prim)
    {
    {
    case boolean_type:
    case boolean_type:
    case char_type:
    case char_type:
    case float_type:
    case float_type:
    case double_type:
    case double_type:
    case byte_type:
    case byte_type:
    case short_type:
    case short_type:
    case int_type:
    case int_type:
    case long_type:
    case long_type:
      k = vfy_get_primitive_type ((int) prim);
      k = vfy_get_primitive_type ((int) prim);
      break;
      break;
 
 
    /* These aren't used here but we call them out to avoid
    /* These aren't used here but we call them out to avoid
       warnings.  */
       warnings.  */
    case void_type:
    case void_type:
    case unsuitable_type:
    case unsuitable_type:
    case return_address_type:
    case return_address_type:
    case continuation_type:
    case continuation_type:
    case reference_type:
    case reference_type:
    case null_type:
    case null_type:
    case uninitialized_reference_type:
    case uninitialized_reference_type:
    default:
    default:
      verify_fail ("unknown type in construct_primitive_array_type");
      verify_fail ("unknown type in construct_primitive_array_type");
    }
    }
  k = vfy_get_array_class (k);
  k = vfy_get_array_class (k);
  return k;
  return k;
}
}
 
 
/* This pass computes the location of branch targets and also
/* This pass computes the location of branch targets and also
   instruction starts.  */
   instruction starts.  */
static void
static void
branch_prepass (void)
branch_prepass (void)
{
{
  int i, pc;
  int i, pc;
  vfr->flags = (char *) vfy_alloc (vfr->current_method->code_length);
  vfr->flags = (char *) vfy_alloc (vfr->current_method->code_length);
 
 
  for (i = 0; i < vfr->current_method->code_length; ++i)
  for (i = 0; i < vfr->current_method->code_length; ++i)
    vfr->flags[i] = 0;
    vfr->flags[i] = 0;
 
 
  vfr->PC = 0;
  vfr->PC = 0;
  while (vfr->PC < vfr->current_method->code_length)
  while (vfr->PC < vfr->current_method->code_length)
    {
    {
      java_opcode opcode;
      java_opcode opcode;
      /* Set `start_PC' early so that error checking can have the
      /* Set `start_PC' early so that error checking can have the
         correct value.  */
         correct value.  */
      vfr->start_PC = vfr->PC;
      vfr->start_PC = vfr->PC;
      vfr->flags[vfr->PC] |= FLAG_INSN_START;
      vfr->flags[vfr->PC] |= FLAG_INSN_START;
 
 
      opcode = (java_opcode) vfr->bytecode[vfr->PC++];
      opcode = (java_opcode) vfr->bytecode[vfr->PC++];
      switch (opcode)
      switch (opcode)
        {
        {
        case op_nop:
        case op_nop:
        case op_aconst_null:
        case op_aconst_null:
        case op_iconst_m1:
        case op_iconst_m1:
        case op_iconst_0:
        case op_iconst_0:
        case op_iconst_1:
        case op_iconst_1:
        case op_iconst_2:
        case op_iconst_2:
        case op_iconst_3:
        case op_iconst_3:
        case op_iconst_4:
        case op_iconst_4:
        case op_iconst_5:
        case op_iconst_5:
        case op_lconst_0:
        case op_lconst_0:
        case op_lconst_1:
        case op_lconst_1:
        case op_fconst_0:
        case op_fconst_0:
        case op_fconst_1:
        case op_fconst_1:
        case op_fconst_2:
        case op_fconst_2:
        case op_dconst_0:
        case op_dconst_0:
        case op_dconst_1:
        case op_dconst_1:
        case op_iload_0:
        case op_iload_0:
        case op_iload_1:
        case op_iload_1:
        case op_iload_2:
        case op_iload_2:
        case op_iload_3:
        case op_iload_3:
        case op_lload_0:
        case op_lload_0:
        case op_lload_1:
        case op_lload_1:
        case op_lload_2:
        case op_lload_2:
        case op_lload_3:
        case op_lload_3:
        case op_fload_0:
        case op_fload_0:
        case op_fload_1:
        case op_fload_1:
        case op_fload_2:
        case op_fload_2:
        case op_fload_3:
        case op_fload_3:
        case op_dload_0:
        case op_dload_0:
        case op_dload_1:
        case op_dload_1:
        case op_dload_2:
        case op_dload_2:
        case op_dload_3:
        case op_dload_3:
        case op_aload_0:
        case op_aload_0:
        case op_aload_1:
        case op_aload_1:
        case op_aload_2:
        case op_aload_2:
        case op_aload_3:
        case op_aload_3:
        case op_iaload:
        case op_iaload:
        case op_laload:
        case op_laload:
        case op_faload:
        case op_faload:
        case op_daload:
        case op_daload:
        case op_aaload:
        case op_aaload:
        case op_baload:
        case op_baload:
        case op_caload:
        case op_caload:
        case op_saload:
        case op_saload:
        case op_istore_0:
        case op_istore_0:
        case op_istore_1:
        case op_istore_1:
        case op_istore_2:
        case op_istore_2:
        case op_istore_3:
        case op_istore_3:
        case op_lstore_0:
        case op_lstore_0:
        case op_lstore_1:
        case op_lstore_1:
        case op_lstore_2:
        case op_lstore_2:
        case op_lstore_3:
        case op_lstore_3:
        case op_fstore_0:
        case op_fstore_0:
        case op_fstore_1:
        case op_fstore_1:
        case op_fstore_2:
        case op_fstore_2:
        case op_fstore_3:
        case op_fstore_3:
        case op_dstore_0:
        case op_dstore_0:
        case op_dstore_1:
        case op_dstore_1:
        case op_dstore_2:
        case op_dstore_2:
        case op_dstore_3:
        case op_dstore_3:
        case op_astore_0:
        case op_astore_0:
        case op_astore_1:
        case op_astore_1:
        case op_astore_2:
        case op_astore_2:
        case op_astore_3:
        case op_astore_3:
        case op_iastore:
        case op_iastore:
        case op_lastore:
        case op_lastore:
        case op_fastore:
        case op_fastore:
        case op_dastore:
        case op_dastore:
        case op_aastore:
        case op_aastore:
        case op_bastore:
        case op_bastore:
        case op_castore:
        case op_castore:
        case op_sastore:
        case op_sastore:
        case op_pop:
        case op_pop:
        case op_pop2:
        case op_pop2:
        case op_dup:
        case op_dup:
        case op_dup_x1:
        case op_dup_x1:
        case op_dup_x2:
        case op_dup_x2:
        case op_dup2:
        case op_dup2:
        case op_dup2_x1:
        case op_dup2_x1:
        case op_dup2_x2:
        case op_dup2_x2:
        case op_swap:
        case op_swap:
        case op_iadd:
        case op_iadd:
        case op_isub:
        case op_isub:
        case op_imul:
        case op_imul:
        case op_idiv:
        case op_idiv:
        case op_irem:
        case op_irem:
        case op_ishl:
        case op_ishl:
        case op_ishr:
        case op_ishr:
        case op_iushr:
        case op_iushr:
        case op_iand:
        case op_iand:
        case op_ior:
        case op_ior:
        case op_ixor:
        case op_ixor:
        case op_ladd:
        case op_ladd:
        case op_lsub:
        case op_lsub:
        case op_lmul:
        case op_lmul:
        case op_ldiv:
        case op_ldiv:
        case op_lrem:
        case op_lrem:
        case op_lshl:
        case op_lshl:
        case op_lshr:
        case op_lshr:
        case op_lushr:
        case op_lushr:
        case op_land:
        case op_land:
        case op_lor:
        case op_lor:
        case op_lxor:
        case op_lxor:
        case op_fadd:
        case op_fadd:
        case op_fsub:
        case op_fsub:
        case op_fmul:
        case op_fmul:
        case op_fdiv:
        case op_fdiv:
        case op_frem:
        case op_frem:
        case op_dadd:
        case op_dadd:
        case op_dsub:
        case op_dsub:
        case op_dmul:
        case op_dmul:
        case op_ddiv:
        case op_ddiv:
        case op_drem:
        case op_drem:
        case op_ineg:
        case op_ineg:
        case op_i2b:
        case op_i2b:
        case op_i2c:
        case op_i2c:
        case op_i2s:
        case op_i2s:
        case op_lneg:
        case op_lneg:
        case op_fneg:
        case op_fneg:
        case op_dneg:
        case op_dneg:
        case op_i2l:
        case op_i2l:
        case op_i2f:
        case op_i2f:
        case op_i2d:
        case op_i2d:
        case op_l2i:
        case op_l2i:
        case op_l2f:
        case op_l2f:
        case op_l2d:
        case op_l2d:
        case op_f2i:
        case op_f2i:
        case op_f2l:
        case op_f2l:
        case op_f2d:
        case op_f2d:
        case op_d2i:
        case op_d2i:
        case op_d2l:
        case op_d2l:
        case op_d2f:
        case op_d2f:
        case op_lcmp:
        case op_lcmp:
        case op_fcmpl:
        case op_fcmpl:
        case op_fcmpg:
        case op_fcmpg:
        case op_dcmpl:
        case op_dcmpl:
        case op_dcmpg:
        case op_dcmpg:
        case op_monitorenter:
        case op_monitorenter:
        case op_monitorexit:
        case op_monitorexit:
        case op_ireturn:
        case op_ireturn:
        case op_lreturn:
        case op_lreturn:
        case op_freturn:
        case op_freturn:
        case op_dreturn:
        case op_dreturn:
        case op_areturn:
        case op_areturn:
        case op_return:
        case op_return:
        case op_athrow:
        case op_athrow:
        case op_arraylength:
        case op_arraylength:
          break;
          break;
 
 
        case op_bipush:
        case op_bipush:
        case op_ldc:
        case op_ldc:
        case op_iload:
        case op_iload:
        case op_lload:
        case op_lload:
        case op_fload:
        case op_fload:
        case op_dload:
        case op_dload:
        case op_aload:
        case op_aload:
        case op_istore:
        case op_istore:
        case op_lstore:
        case op_lstore:
        case op_fstore:
        case op_fstore:
        case op_dstore:
        case op_dstore:
        case op_astore:
        case op_astore:
        case op_ret:
        case op_ret:
        case op_newarray:
        case op_newarray:
          get_byte ();
          get_byte ();
          break;
          break;
 
 
        case op_iinc:
        case op_iinc:
        case op_sipush:
        case op_sipush:
        case op_ldc_w:
        case op_ldc_w:
        case op_ldc2_w:
        case op_ldc2_w:
        case op_getstatic:
        case op_getstatic:
        case op_getfield:
        case op_getfield:
        case op_putfield:
        case op_putfield:
        case op_putstatic:
        case op_putstatic:
        case op_new:
        case op_new:
        case op_anewarray:
        case op_anewarray:
        case op_instanceof:
        case op_instanceof:
        case op_checkcast:
        case op_checkcast:
        case op_invokespecial:
        case op_invokespecial:
        case op_invokestatic:
        case op_invokestatic:
        case op_invokevirtual:
        case op_invokevirtual:
          get_short ();
          get_short ();
          break;
          break;
 
 
        case op_multianewarray:
        case op_multianewarray:
          get_short ();
          get_short ();
          get_byte ();
          get_byte ();
          break;
          break;
 
 
        case op_jsr:
        case op_jsr:
        case op_ifeq:
        case op_ifeq:
        case op_ifne:
        case op_ifne:
        case op_iflt:
        case op_iflt:
        case op_ifge:
        case op_ifge:
        case op_ifgt:
        case op_ifgt:
        case op_ifle:
        case op_ifle:
        case op_if_icmpeq:
        case op_if_icmpeq:
        case op_if_icmpne:
        case op_if_icmpne:
        case op_if_icmplt:
        case op_if_icmplt:
        case op_if_icmpge:
        case op_if_icmpge:
        case op_if_icmpgt:
        case op_if_icmpgt:
        case op_if_icmple:
        case op_if_icmple:
        case op_if_acmpeq:
        case op_if_acmpeq:
        case op_if_acmpne:
        case op_if_acmpne:
        case op_ifnull:
        case op_ifnull:
        case op_ifnonnull:
        case op_ifnonnull:
        case op_goto:
        case op_goto:
          note_branch_target (compute_jump (get_short ()));
          note_branch_target (compute_jump (get_short ()));
          break;
          break;
 
 
        case op_tableswitch:
        case op_tableswitch:
          {
          {
            jint low, hi;
            jint low, hi;
            skip_padding ();
            skip_padding ();
            note_branch_target (compute_jump (get_int ()));
            note_branch_target (compute_jump (get_int ()));
            low = get_int ();
            low = get_int ();
            hi = get_int ();
            hi = get_int ();
            if (low > hi)
            if (low > hi)
              verify_fail_pc ("invalid tableswitch", vfr->start_PC);
              verify_fail_pc ("invalid tableswitch", vfr->start_PC);
            for (i = low; i <= hi; ++i)
            for (i = low; i <= hi; ++i)
              note_branch_target (compute_jump (get_int ()));
              note_branch_target (compute_jump (get_int ()));
          }
          }
          break;
          break;
 
 
        case op_lookupswitch:
        case op_lookupswitch:
          {
          {
            int npairs;
            int npairs;
            skip_padding ();
            skip_padding ();
            note_branch_target (compute_jump (get_int ()));
            note_branch_target (compute_jump (get_int ()));
            npairs = get_int ();
            npairs = get_int ();
            if (npairs < 0)
            if (npairs < 0)
              verify_fail_pc ("too few pairs in lookupswitch", vfr->start_PC);
              verify_fail_pc ("too few pairs in lookupswitch", vfr->start_PC);
            while (npairs-- > 0)
            while (npairs-- > 0)
              {
              {
                get_int ();
                get_int ();
                note_branch_target (compute_jump (get_int ()));
                note_branch_target (compute_jump (get_int ()));
              }
              }
          }
          }
          break;
          break;
 
 
        case op_invokeinterface:
        case op_invokeinterface:
          get_short ();
          get_short ();
          get_byte ();
          get_byte ();
          get_byte ();
          get_byte ();
          break;
          break;
 
 
        case op_wide:
        case op_wide:
          {
          {
            opcode = (java_opcode) get_byte ();
            opcode = (java_opcode) get_byte ();
            get_short ();
            get_short ();
            if (opcode == op_iinc)
            if (opcode == op_iinc)
              get_short ();
              get_short ();
          }
          }
          break;
          break;
 
 
        case op_jsr_w:
        case op_jsr_w:
        case op_goto_w:
        case op_goto_w:
          note_branch_target (compute_jump (get_int ()));
          note_branch_target (compute_jump (get_int ()));
          break;
          break;
 
 
#if 0
#if 0
        /* These are unused here, but we call them out explicitly
        /* These are unused here, but we call them out explicitly
           so that -Wswitch-enum doesn't complain.  */
           so that -Wswitch-enum doesn't complain.  */
        case op_putfield_1:
        case op_putfield_1:
        case op_putfield_2:
        case op_putfield_2:
        case op_putfield_4:
        case op_putfield_4:
        case op_putfield_8:
        case op_putfield_8:
        case op_putfield_a:
        case op_putfield_a:
        case op_putstatic_1:
        case op_putstatic_1:
        case op_putstatic_2:
        case op_putstatic_2:
        case op_putstatic_4:
        case op_putstatic_4:
        case op_putstatic_8:
        case op_putstatic_8:
        case op_putstatic_a:
        case op_putstatic_a:
        case op_getfield_1:
        case op_getfield_1:
        case op_getfield_2s:
        case op_getfield_2s:
        case op_getfield_2u:
        case op_getfield_2u:
        case op_getfield_4:
        case op_getfield_4:
        case op_getfield_8:
        case op_getfield_8:
        case op_getfield_a:
        case op_getfield_a:
        case op_getstatic_1:
        case op_getstatic_1:
        case op_getstatic_2s:
        case op_getstatic_2s:
        case op_getstatic_2u:
        case op_getstatic_2u:
        case op_getstatic_4:
        case op_getstatic_4:
        case op_getstatic_8:
        case op_getstatic_8:
        case op_getstatic_a:
        case op_getstatic_a:
#endif /* VFY_FAST_OPCODES  */
#endif /* VFY_FAST_OPCODES  */
        default:
        default:
          verify_fail_pc ("unrecognized instruction in branch_prepass",
          verify_fail_pc ("unrecognized instruction in branch_prepass",
                          vfr->start_PC);
                          vfr->start_PC);
        }
        }
 
 
      /* See if any previous branch tried to branch to the middle of
      /* See if any previous branch tried to branch to the middle of
         this instruction.  */
         this instruction.  */
      for (pc = vfr->start_PC + 1; pc < vfr->PC; ++pc)
      for (pc = vfr->start_PC + 1; pc < vfr->PC; ++pc)
        {
        {
          if ((vfr->flags[pc] & FLAG_BRANCH_TARGET))
          if ((vfr->flags[pc] & FLAG_BRANCH_TARGET))
            verify_fail_pc ("branch to middle of instruction", pc);
            verify_fail_pc ("branch to middle of instruction", pc);
        }
        }
    }
    }
 
 
  /* Verify exception handlers.  */
  /* Verify exception handlers.  */
  for (i = 0; i < vfr->current_method->exc_count; ++i)
  for (i = 0; i < vfr->current_method->exc_count; ++i)
    {
    {
      int handler, start, end, htype;
      int handler, start, end, htype;
      vfy_get_exception (vfr->exception, i, &handler, &start, &end, &htype);
      vfy_get_exception (vfr->exception, i, &handler, &start, &end, &htype);
      if (! (vfr->flags[handler] & FLAG_INSN_START))
      if (! (vfr->flags[handler] & FLAG_INSN_START))
        verify_fail_pc ("exception handler not at instruction start",
        verify_fail_pc ("exception handler not at instruction start",
                        handler);
                        handler);
      if (! (vfr->flags[start] & FLAG_INSN_START))
      if (! (vfr->flags[start] & FLAG_INSN_START))
        verify_fail_pc ("exception start not at instruction start", start);
        verify_fail_pc ("exception start not at instruction start", start);
      if (end != vfr->current_method->code_length
      if (end != vfr->current_method->code_length
          && ! (vfr->flags[end] & FLAG_INSN_START))
          && ! (vfr->flags[end] & FLAG_INSN_START))
        verify_fail_pc ("exception end not at instruction start", end);
        verify_fail_pc ("exception end not at instruction start", end);
 
 
      vfr->flags[handler] |= FLAG_BRANCH_TARGET;
      vfr->flags[handler] |= FLAG_BRANCH_TARGET;
    }
    }
}
}
 
 
static void
static void
check_pool_index (int index)
check_pool_index (int index)
{
{
  if (index < 0 || index >= vfy_get_constants_size (vfr->current_class))
  if (index < 0 || index >= vfy_get_constants_size (vfr->current_class))
    verify_fail_pc ("constant pool index out of range", vfr->start_PC);
    verify_fail_pc ("constant pool index out of range", vfr->start_PC);
}
}
 
 
static type
static type
check_class_constant (int index)
check_class_constant (int index)
{
{
  type t = { (type_val) 0, 0, 0 };
  type t = { (type_val) 0, 0, 0 };
  vfy_constants *pool;
  vfy_constants *pool;
 
 
  check_pool_index (index);
  check_pool_index (index);
  pool = vfy_get_constants (vfr->current_class);
  pool = vfy_get_constants (vfr->current_class);
  if (vfy_tag (pool, index) == JV_CONSTANT_ResolvedClass)
  if (vfy_tag (pool, index) == JV_CONSTANT_ResolvedClass)
    init_type_from_class (&t, vfy_get_pool_class (pool, index));
    init_type_from_class (&t, vfy_get_pool_class (pool, index));
  else if (vfy_tag (pool, index) == JV_CONSTANT_Class)
  else if (vfy_tag (pool, index) == JV_CONSTANT_Class)
    init_type_from_string (&t, vfy_get_pool_string (pool, index));
    init_type_from_string (&t, vfy_get_pool_string (pool, index));
  else
  else
    verify_fail_pc ("expected class constant", vfr->start_PC);
    verify_fail_pc ("expected class constant", vfr->start_PC);
  return t;
  return t;
}
}
 
 
static type
static type
check_constant (int index)
check_constant (int index)
{
{
  type t = { (type_val) 0, 0, 0 };
  type t = { (type_val) 0, 0, 0 };
  vfy_constants *pool;
  vfy_constants *pool;
 
 
  check_pool_index (index);
  check_pool_index (index);
  pool = vfy_get_constants (vfr->current_class);
  pool = vfy_get_constants (vfr->current_class);
  if (vfy_tag (pool, index) == JV_CONSTANT_ResolvedString
  if (vfy_tag (pool, index) == JV_CONSTANT_ResolvedString
      || vfy_tag (pool, index) == JV_CONSTANT_String)
      || vfy_tag (pool, index) == JV_CONSTANT_String)
    init_type_from_class (&t, vfy_string_type ());
    init_type_from_class (&t, vfy_string_type ());
  else if (vfy_tag (pool, index) == JV_CONSTANT_Integer)
  else if (vfy_tag (pool, index) == JV_CONSTANT_Integer)
    init_type_from_tag (&t, int_type);
    init_type_from_tag (&t, int_type);
  else if (vfy_tag (pool, index) == JV_CONSTANT_Float)
  else if (vfy_tag (pool, index) == JV_CONSTANT_Float)
    init_type_from_tag (&t, float_type);
    init_type_from_tag (&t, float_type);
  else if (vfy_tag (pool, index) == JV_CONSTANT_Class
  else if (vfy_tag (pool, index) == JV_CONSTANT_Class
           || vfy_tag (pool, index) == JV_CONSTANT_ResolvedClass)
           || vfy_tag (pool, index) == JV_CONSTANT_ResolvedClass)
    /* FIXME: should only allow this for 1.5 bytecode.  */
    /* FIXME: should only allow this for 1.5 bytecode.  */
    init_type_from_class (&t, vfy_class_type ());
    init_type_from_class (&t, vfy_class_type ());
  else
  else
    verify_fail_pc ("String, int, or float constant expected", vfr->start_PC);
    verify_fail_pc ("String, int, or float constant expected", vfr->start_PC);
  return t;
  return t;
}
}
 
 
static type
static type
check_wide_constant (int index)
check_wide_constant (int index)
{
{
  type t = { (type_val) 0, 0, 0 };
  type t = { (type_val) 0, 0, 0 };
  vfy_constants *pool;
  vfy_constants *pool;
 
 
  check_pool_index (index);
  check_pool_index (index);
  pool = vfy_get_constants (vfr->current_class);
  pool = vfy_get_constants (vfr->current_class);
  if (vfy_tag (pool, index) == JV_CONSTANT_Long)
  if (vfy_tag (pool, index) == JV_CONSTANT_Long)
    init_type_from_tag (&t, long_type);
    init_type_from_tag (&t, long_type);
  else if (vfy_tag (pool, index) == JV_CONSTANT_Double)
  else if (vfy_tag (pool, index) == JV_CONSTANT_Double)
    init_type_from_tag (&t, double_type);
    init_type_from_tag (&t, double_type);
  else
  else
    verify_fail_pc ("long or double constant expected", vfr->start_PC);
    verify_fail_pc ("long or double constant expected", vfr->start_PC);
  return t;
  return t;
}
}
 
 
/* Helper for both field and method.  These are laid out the same in
/* Helper for both field and method.  These are laid out the same in
   the constant pool.  */
   the constant pool.  */
static type
static type
handle_field_or_method (int index, int expected,
handle_field_or_method (int index, int expected,
                        vfy_string *name, vfy_string *fmtype)
                        vfy_string *name, vfy_string *fmtype)
{
{
  vfy_uint_16 class_index, name_and_type_index;
  vfy_uint_16 class_index, name_and_type_index;
  vfy_uint_16 name_index, desc_index;
  vfy_uint_16 name_index, desc_index;
  vfy_constants *pool;
  vfy_constants *pool;
 
 
  check_pool_index (index);
  check_pool_index (index);
  pool = vfy_get_constants (vfr->current_class);
  pool = vfy_get_constants (vfr->current_class);
  if (vfy_tag (pool, index) != expected)
  if (vfy_tag (pool, index) != expected)
    verify_fail_pc ("didn't see expected constant", vfr->start_PC);
    verify_fail_pc ("didn't see expected constant", vfr->start_PC);
  /* Once we know we have a Fieldref or Methodref we assume that it
  /* Once we know we have a Fieldref or Methodref we assume that it
     is correctly laid out in the constant pool.  I think the code
     is correctly laid out in the constant pool.  I think the code
     in defineclass.cc guarantees this.  */
     in defineclass.cc guarantees this.  */
  vfy_load_indexes (pool, index, &class_index, &name_and_type_index);
  vfy_load_indexes (pool, index, &class_index, &name_and_type_index);
  vfy_load_indexes (pool, name_and_type_index, &name_index, &desc_index);
  vfy_load_indexes (pool, name_and_type_index, &name_index, &desc_index);
 
 
  *name = vfy_get_pool_string (pool, name_index);
  *name = vfy_get_pool_string (pool, name_index);
  *fmtype = vfy_get_pool_string (pool, desc_index);
  *fmtype = vfy_get_pool_string (pool, desc_index);
 
 
  return check_class_constant (class_index);
  return check_class_constant (class_index);
}
}
 
 
/* Return field's type, compute class' type if requested.  If
/* Return field's type, compute class' type if requested.  If
   PUTFIELD is true, use the special 'putfield' semantics.  */
   PUTFIELD is true, use the special 'putfield' semantics.  */
static type
static type
check_field_constant (int index, type *class_type, bool putfield)
check_field_constant (int index, type *class_type, bool putfield)
{
{
  vfy_string name, field_type;
  vfy_string name, field_type;
  const char *typec;
  const char *typec;
  type t;
  type t;
 
 
  type ct = handle_field_or_method (index,
  type ct = handle_field_or_method (index,
                                    JV_CONSTANT_Fieldref,
                                    JV_CONSTANT_Fieldref,
                                    &name, &field_type);
                                    &name, &field_type);
  if (class_type)
  if (class_type)
    *class_type = ct;
    *class_type = ct;
  typec = vfy_string_bytes (field_type);
  typec = vfy_string_bytes (field_type);
  if (typec[0] == '[' || typec[0] == 'L')
  if (typec[0] == '[' || typec[0] == 'L')
    init_type_from_string (&t, field_type);
    init_type_from_string (&t, field_type);
  else
  else
    init_type_from_tag (&t, get_type_val_for_signature (typec[0]));
    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
  /* 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
     field declared in this class, even if `this' has not yet been
     initialized.  */
     initialized.  */
  if (putfield
  if (putfield
      && ! type_initialized (&vfr->current_state->this_type)
      && ! type_initialized (&vfr->current_state->this_type)
      && vfr->current_state->this_type.pc == SELF
      && vfr->current_state->this_type.pc == SELF
      && types_equal (&vfr->current_state->this_type, &ct)
      && types_equal (&vfr->current_state->this_type, &ct)
      && vfy_class_has_field (vfr->current_class, name, field_type))
      && vfy_class_has_field (vfr->current_class, name, field_type))
    /* Note that we don't actually know whether we're going to match
    /* Note that we don't actually know whether we're going to match
       against 'this' or some other object of the same type.  So,
       against 'this' or some other object of the same type.  So,
       here we set things up so that it doesn't matter.  This relies
       here we set things up so that it doesn't matter.  This relies
       on knowing what our caller is up to.  */
       on knowing what our caller is up to.  */
    type_set_uninitialized (class_type, EITHER);
    type_set_uninitialized (class_type, EITHER);
 
 
  return t;
  return t;
}
}
 
 
static type
static type
check_method_constant (int index, bool is_interface,
check_method_constant (int index, bool is_interface,
                            vfy_string *method_name,
                            vfy_string *method_name,
                            vfy_string *method_signature)
                            vfy_string *method_signature)
{
{
  return handle_field_or_method (index,
  return handle_field_or_method (index,
                                 (is_interface
                                 (is_interface
                                  ? JV_CONSTANT_InterfaceMethodref
                                  ? JV_CONSTANT_InterfaceMethodref
                                  : JV_CONSTANT_Methodref),
                                  : JV_CONSTANT_Methodref),
                                 method_name, method_signature);
                                 method_name, method_signature);
}
}
 
 
static const char *
static const char *
get_one_type (const char *p, type *t)
get_one_type (const char *p, type *t)
{
{
  const char *start = p;
  const char *start = p;
  vfy_jclass k;
  vfy_jclass k;
  type_val rt;
  type_val rt;
  char v;
  char v;
 
 
  int arraycount = 0;
  int arraycount = 0;
  while (*p == '[')
  while (*p == '[')
    {
    {
      ++arraycount;
      ++arraycount;
      ++p;
      ++p;
    }
    }
 
 
  v = *p++;
  v = *p++;
 
 
  if (v == 'L')
  if (v == 'L')
    {
    {
      vfy_string name;
      vfy_string name;
      while (*p != ';')
      while (*p != ';')
        ++p;
        ++p;
      ++p;
      ++p;
      name = vfy_get_string (start, p - start);
      name = vfy_get_string (start, p - start);
      *t = make_type_from_string (name);
      *t = make_type_from_string (name);
      return p;
      return p;
    }
    }
 
 
  /* Casting to jchar here is ok since we are looking at an ASCII
  /* Casting to jchar here is ok since we are looking at an ASCII
     character.  */
     character.  */
  rt = get_type_val_for_signature (v);
  rt = get_type_val_for_signature (v);
 
 
  if (arraycount == 0)
  if (arraycount == 0)
    {
    {
      /* Callers of this function eventually push their arguments on
      /* Callers of this function eventually push their arguments on
         the stack.  So, promote them here.  */
         the stack.  So, promote them here.  */
      type new_t = make_type (rt);
      type new_t = make_type (rt);
      vfy_promote_type (&new_t);
      vfy_promote_type (&new_t);
      *t = new_t;
      *t = new_t;
      return p;
      return p;
    }
    }
 
 
  k = construct_primitive_array_type (rt);
  k = construct_primitive_array_type (rt);
  while (--arraycount > 0)
  while (--arraycount > 0)
    k = vfy_get_array_class (k);
    k = vfy_get_array_class (k);
  *t = make_type_from_class (k);
  *t = make_type_from_class (k);
  return p;
  return p;
}
}
 
 
static void
static void
compute_argument_types (vfy_string signature, type *types)
compute_argument_types (vfy_string signature, type *types)
{
{
  int i;
  int i;
  const char *p = vfy_string_bytes (signature);
  const char *p = vfy_string_bytes (signature);
 
 
  /* Skip `('.  */
  /* Skip `('.  */
  ++p;
  ++p;
 
 
  i = 0;
  i = 0;
  while (*p != ')')
  while (*p != ')')
    p = get_one_type (p, &types[i++]);
    p = get_one_type (p, &types[i++]);
}
}
 
 
static type
static type
compute_return_type (vfy_string signature)
compute_return_type (vfy_string signature)
{
{
  const char *p = vfy_string_bytes (signature);
  const char *p = vfy_string_bytes (signature);
  type t;
  type t;
  while (*p != ')')
  while (*p != ')')
    ++p;
    ++p;
  ++p;
  ++p;
  get_one_type (p, &t);
  get_one_type (p, &t);
  return t;
  return t;
}
}
 
 
static void
static void
check_return_type (type onstack)
check_return_type (type onstack)
{
{
  type rt = compute_return_type (vfy_get_signature (vfr->current_method));
  type rt = compute_return_type (vfy_get_signature (vfr->current_method));
  if (! types_compatible (&rt, &onstack))
  if (! types_compatible (&rt, &onstack))
    verify_fail ("incompatible return type");
    verify_fail ("incompatible return type");
}
}
 
 
/* Initialize the stack for the new method.  Returns true if this
/* Initialize the stack for the new method.  Returns true if this
   method is an instance initializer.  */
   method is an instance initializer.  */
static bool
static bool
initialize_stack (void)
initialize_stack (void)
{
{
  int arg_count, i;
  int arg_count, i;
  int var = 0;
  int var = 0;
  bool is_init = vfy_strings_equal (vfy_get_method_name (vfr->current_method),
  bool is_init = vfy_strings_equal (vfy_get_method_name (vfr->current_method),
                                    vfy_init_name());
                                    vfy_init_name());
  bool is_clinit = vfy_strings_equal (vfy_get_method_name (vfr->current_method),
  bool is_clinit = vfy_strings_equal (vfy_get_method_name (vfr->current_method),
                                      vfy_clinit_name());
                                      vfy_clinit_name());
 
 
  if (! vfy_is_static (vfr->current_method))
  if (! vfy_is_static (vfr->current_method))
    {
    {
      type kurr = make_type_from_class (vfr->current_class);
      type kurr = make_type_from_class (vfr->current_class);
      if (is_init)
      if (is_init)
        {
        {
          type_set_uninitialized (&kurr, SELF);
          type_set_uninitialized (&kurr, SELF);
          is_init = true;
          is_init = true;
        }
        }
      else if (is_clinit)
      else if (is_clinit)
        verify_fail ("<clinit> method must be static");
        verify_fail ("<clinit> method must be static");
      set_variable (0, kurr);
      set_variable (0, kurr);
      state_set_this_type (vfr->current_state, &kurr);
      state_set_this_type (vfr->current_state, &kurr);
      ++var;
      ++var;
    }
    }
  else
  else
    {
    {
      if (is_init)
      if (is_init)
        verify_fail ("<init> method must be non-static");
        verify_fail ("<init> method must be non-static");
    }
    }
 
 
  /* We have to handle wide arguments specially here.  */
  /* We have to handle wide arguments specially here.  */
  arg_count = vfy_count_arguments (vfy_get_signature (vfr->current_method));
  arg_count = vfy_count_arguments (vfy_get_signature (vfr->current_method));
  {
  {
    type *arg_types = (type *) vfy_alloc (arg_count * sizeof (type));
    type *arg_types = (type *) vfy_alloc (arg_count * sizeof (type));
    compute_argument_types (vfy_get_signature (vfr->current_method), arg_types);
    compute_argument_types (vfy_get_signature (vfr->current_method), arg_types);
    for (i = 0; i < arg_count; ++i)
    for (i = 0; i < arg_count; ++i)
      {
      {
        set_variable (var, arg_types[i]);
        set_variable (var, arg_types[i]);
        ++var;
        ++var;
        if (type_iswide (&arg_types[i]))
        if (type_iswide (&arg_types[i]))
          ++var;
          ++var;
      }
      }
    vfy_free (arg_types);
    vfy_free (arg_types);
  }
  }
 
 
  return is_init;
  return is_init;
}
}
 
 
static void
static void
verify_instructions_0 (void)
verify_instructions_0 (void)
{
{
  int i;
  int i;
  bool this_is_init;
  bool this_is_init;
 
 
  vfr->current_state = make_state (vfr->current_method->max_stack,
  vfr->current_state = make_state (vfr->current_method->max_stack,
                                   vfr->current_method->max_locals);
                                   vfr->current_method->max_locals);
 
 
  vfr->PC = 0;
  vfr->PC = 0;
  vfr->start_PC = 0;
  vfr->start_PC = 0;
 
 
  /*  True if we are verifying an instance initializer.  */
  /*  True if we are verifying an instance initializer.  */
  this_is_init = initialize_stack ();
  this_is_init = initialize_stack ();
 
 
  vfr->states = (state_list **) vfy_alloc (sizeof (state_list *)
  vfr->states = (state_list **) vfy_alloc (sizeof (state_list *)
                                      * vfr->current_method->code_length);
                                      * vfr->current_method->code_length);
 
 
  for (i = 0; i < vfr->current_method->code_length; ++i)
  for (i = 0; i < vfr->current_method->code_length; ++i)
    vfr->states[i] = NULL;
    vfr->states[i] = NULL;
 
 
  vfr->next_verify_state = NULL;
  vfr->next_verify_state = NULL;
 
 
  while (true)
  while (true)
    {
    {
      java_opcode opcode;
      java_opcode opcode;
 
 
      /* If the PC was invalidated, get a new one from the work list.  */
      /* If the PC was invalidated, get a new one from the work list.  */
      if (vfr->PC == NO_NEXT)
      if (vfr->PC == NO_NEXT)
        {
        {
          state *new_state = pop_jump ();
          state *new_state = pop_jump ();
          /* If it is null, we're done.  */
          /* If it is null, we're done.  */
          if (new_state == NULL)
          if (new_state == NULL)
            break;
            break;
 
 
          vfr->PC = new_state->pc;
          vfr->PC = new_state->pc;
          debug_print ("== State pop from pending list\n");
          debug_print ("== State pop from pending list\n");
          /* Set up the current state.  */
          /* Set up the current state.  */
          copy_state (vfr->current_state, new_state,
          copy_state (vfr->current_state, new_state,
            vfr->current_method->max_stack, vfr->current_method->max_locals);
            vfr->current_method->max_stack, vfr->current_method->max_locals);
        }
        }
      else
      else
        {
        {
          /* We only have to do this checking in the situation where
          /* We only have to do this checking in the situation where
             control flow falls through from the previous instruction.
             control flow falls through from the previous instruction.
             Otherwise merging is done at the time we push the branch.
             Otherwise merging is done at the time we push the branch.
             Note that we'll catch the off-the-end problem just
             Note that we'll catch the off-the-end problem just
             below.  */
             below.  */
          if (vfr->PC < vfr->current_method->code_length
          if (vfr->PC < vfr->current_method->code_length
              && vfr->states[vfr->PC] != NULL)
              && vfr->states[vfr->PC] != NULL)
            {
            {
              /* We've already visited this instruction.  So merge
              /* We've already visited this instruction.  So merge
                 the states together.  It is simplest, but not most
                 the states together.  It is simplest, but not most
                 efficient, to just always invalidate the PC here.  */
                 efficient, to just always invalidate the PC here.  */
              merge_into (vfr->PC, vfr->current_state);
              merge_into (vfr->PC, vfr->current_state);
              invalidate_pc ();
              invalidate_pc ();
              continue;
              continue;
            }
            }
        }
        }
 
 
      /* Control can't fall off the end of the bytecode.  We need to
      /* Control can't fall off the end of the bytecode.  We need to
         check this in both cases, not just the fall-through case,
         check this in both cases, not just the fall-through case,
         because we don't check to see whether a `jsr' appears at
         because we don't check to see whether a `jsr' appears at
         the end of the bytecode until we process a `ret'.  */
         the end of the bytecode until we process a `ret'.  */
      if (vfr->PC >= vfr->current_method->code_length)
      if (vfr->PC >= vfr->current_method->code_length)
        verify_fail ("fell off end");
        verify_fail ("fell off end");
      vfr->flags[vfr->PC] |= FLAG_INSN_SEEN;
      vfr->flags[vfr->PC] |= FLAG_INSN_SEEN;
 
 
      /* We only have to keep saved state at branch targets.  If
      /* We only have to keep saved state at branch targets.  If
         we're at a branch target and the state here hasn't been set
         we're at a branch target and the state here hasn't been set
         yet, we set it now.  You might notice that `ret' targets
         yet, we set it now.  You might notice that `ret' targets
         won't necessarily have FLAG_BRANCH_TARGET set.  This
         won't necessarily have FLAG_BRANCH_TARGET set.  This
         doesn't matter, since those states will be filled in by
         doesn't matter, since those states will be filled in by
         merge_into.  */
         merge_into.  */
      /* Note that other parts of the compiler assume that there is a
      /* Note that other parts of the compiler assume that there is a
         label with a type map at PC=0.  */
         label with a type map at PC=0.  */
      if (vfr->states[vfr->PC] == NULL
      if (vfr->states[vfr->PC] == NULL
          && (vfr->PC == 0 || (vfr->flags[vfr->PC] & FLAG_BRANCH_TARGET) != 0))
          && (vfr->PC == 0 || (vfr->flags[vfr->PC] & FLAG_BRANCH_TARGET) != 0))
        add_new_state (vfr->PC, vfr->current_state);
        add_new_state (vfr->PC, vfr->current_state);
 
 
      /* Set this before handling exceptions so that debug output is
      /* Set this before handling exceptions so that debug output is
         sane.  */
         sane.  */
      vfr->start_PC = vfr->PC;
      vfr->start_PC = vfr->PC;
 
 
      /* Update states for all active exception handlers.  Ordinarily
      /* Update states for all active exception handlers.  Ordinarily
         there are not many exception handlers.  So we simply run
         there are not many exception handlers.  So we simply run
         through them all.  */
         through them all.  */
      for (i = 0; i < vfr->current_method->exc_count; ++i)
      for (i = 0; i < vfr->current_method->exc_count; ++i)
        {
        {
          int hpc, start, end, htype;
          int hpc, start, end, htype;
          vfy_get_exception (vfr->exception, i, &hpc, &start, &end, &htype);
          vfy_get_exception (vfr->exception, i, &hpc, &start, &end, &htype);
          if (vfr->PC >= start && vfr->PC < end)
          if (vfr->PC >= start && vfr->PC < end)
            {
            {
              type handler = make_type_from_class (vfy_throwable_type ());
              type handler = make_type_from_class (vfy_throwable_type ());
              if (htype != 0)
              if (htype != 0)
                handler = check_class_constant (htype);
                handler = check_class_constant (htype);
              push_exception_jump (handler, hpc);
              push_exception_jump (handler, hpc);
            }
            }
        }
        }
 
 
 
 
      debug_print_state (vfr->current_state, "   ", vfr->PC,
      debug_print_state (vfr->current_state, "   ", vfr->PC,
                         vfr->current_method->max_stack,
                         vfr->current_method->max_stack,
                         vfr->current_method->max_locals);
                         vfr->current_method->max_locals);
      opcode = (java_opcode) vfr->bytecode[vfr->PC++];
      opcode = (java_opcode) vfr->bytecode[vfr->PC++];
      switch (opcode)
      switch (opcode)
        {
        {
        case op_nop:
        case op_nop:
          break;
          break;
 
 
        case op_aconst_null:
        case op_aconst_null:
          push_type (null_type);
          push_type (null_type);
          break;
          break;
 
 
        case op_iconst_m1:
        case op_iconst_m1:
        case op_iconst_0:
        case op_iconst_0:
        case op_iconst_1:
        case op_iconst_1:
        case op_iconst_2:
        case op_iconst_2:
        case op_iconst_3:
        case op_iconst_3:
        case op_iconst_4:
        case op_iconst_4:
        case op_iconst_5:
        case op_iconst_5:
          push_type (int_type);
          push_type (int_type);
          break;
          break;
 
 
        case op_lconst_0:
        case op_lconst_0:
        case op_lconst_1:
        case op_lconst_1:
          push_type (long_type);
          push_type (long_type);
          break;
          break;
 
 
        case op_fconst_0:
        case op_fconst_0:
        case op_fconst_1:
        case op_fconst_1:
        case op_fconst_2:
        case op_fconst_2:
          push_type (float_type);
          push_type (float_type);
          break;
          break;
 
 
        case op_dconst_0:
        case op_dconst_0:
        case op_dconst_1:
        case op_dconst_1:
          push_type (double_type);
          push_type (double_type);
          break;
          break;
 
 
        case op_bipush:
        case op_bipush:
          get_byte ();
          get_byte ();
          push_type (int_type);
          push_type (int_type);
          break;
          break;
 
 
        case op_sipush:
        case op_sipush:
          get_short ();
          get_short ();
          push_type (int_type);
          push_type (int_type);
          break;
          break;
 
 
        case op_ldc:
        case op_ldc:
          push_type_t (check_constant (get_byte ()));
          push_type_t (check_constant (get_byte ()));
          break;
          break;
        case op_ldc_w:
        case op_ldc_w:
          push_type_t (check_constant (get_ushort ()));
          push_type_t (check_constant (get_ushort ()));
          break;
          break;
        case op_ldc2_w:
        case op_ldc2_w:
          push_type_t (check_wide_constant (get_ushort ()));
          push_type_t (check_wide_constant (get_ushort ()));
          break;
          break;
 
 
        case op_iload:
        case op_iload:
          push_type_t (get_variable (get_byte (), int_type));
          push_type_t (get_variable (get_byte (), int_type));
          break;
          break;
        case op_lload:
        case op_lload:
          push_type_t (get_variable (get_byte (), long_type));
          push_type_t (get_variable (get_byte (), long_type));
          break;
          break;
        case op_fload:
        case op_fload:
          push_type_t (get_variable (get_byte (), float_type));
          push_type_t (get_variable (get_byte (), float_type));
          break;
          break;
        case op_dload:
        case op_dload:
          push_type_t (get_variable (get_byte (), double_type));
          push_type_t (get_variable (get_byte (), double_type));
          break;
          break;
        case op_aload:
        case op_aload:
          push_type_t (get_variable (get_byte (), reference_type));
          push_type_t (get_variable (get_byte (), reference_type));
          break;
          break;
 
 
        case op_iload_0:
        case op_iload_0:
        case op_iload_1:
        case op_iload_1:
        case op_iload_2:
        case op_iload_2:
        case op_iload_3:
        case op_iload_3:
          push_type_t (get_variable (opcode - op_iload_0, int_type));
          push_type_t (get_variable (opcode - op_iload_0, int_type));
          break;
          break;
        case op_lload_0:
        case op_lload_0:
        case op_lload_1:
        case op_lload_1:
        case op_lload_2:
        case op_lload_2:
        case op_lload_3:
        case op_lload_3:
          push_type_t (get_variable (opcode - op_lload_0, long_type));
          push_type_t (get_variable (opcode - op_lload_0, long_type));
          break;
          break;
        case op_fload_0:
        case op_fload_0:
        case op_fload_1:
        case op_fload_1:
        case op_fload_2:
        case op_fload_2:
        case op_fload_3:
        case op_fload_3:
          push_type_t (get_variable (opcode - op_fload_0, float_type));
          push_type_t (get_variable (opcode - op_fload_0, float_type));
          break;
          break;
        case op_dload_0:
        case op_dload_0:
        case op_dload_1:
        case op_dload_1:
        case op_dload_2:
        case op_dload_2:
        case op_dload_3:
        case op_dload_3:
          push_type_t (get_variable (opcode - op_dload_0, double_type));
          push_type_t (get_variable (opcode - op_dload_0, double_type));
          break;
          break;
        case op_aload_0:
        case op_aload_0:
        case op_aload_1:
        case op_aload_1:
        case op_aload_2:
        case op_aload_2:
        case op_aload_3:
        case op_aload_3:
          push_type_t (get_variable (opcode - op_aload_0, reference_type));
          push_type_t (get_variable (opcode - op_aload_0, reference_type));
          break;
          break;
        case op_iaload:
        case op_iaload:
          pop_type (int_type);
          pop_type (int_type);
          push_type_t (require_array_type (pop_init_ref (reference_type),
          push_type_t (require_array_type (pop_init_ref (reference_type),
                                         int_type));
                                         int_type));
          break;
          break;
        case op_laload:
        case op_laload:
          pop_type (int_type);
          pop_type (int_type);
          push_type_t (require_array_type (pop_init_ref (reference_type),
          push_type_t (require_array_type (pop_init_ref (reference_type),
                                         long_type));
                                         long_type));
          break;
          break;
        case op_faload:
        case op_faload:
          pop_type (int_type);
          pop_type (int_type);
          push_type_t (require_array_type (pop_init_ref (reference_type),
          push_type_t (require_array_type (pop_init_ref (reference_type),
                                         float_type));
                                         float_type));
          break;
          break;
        case op_daload:
        case op_daload:
          pop_type (int_type);
          pop_type (int_type);
          push_type_t (require_array_type (pop_init_ref (reference_type),
          push_type_t (require_array_type (pop_init_ref (reference_type),
                                         double_type));
                                         double_type));
          break;
          break;
        case op_aaload:
        case op_aaload:
          pop_type (int_type);
          pop_type (int_type);
          push_type_t (require_array_type (pop_init_ref (reference_type),
          push_type_t (require_array_type (pop_init_ref (reference_type),
                                         reference_type));
                                         reference_type));
          break;
          break;
        case op_baload:
        case op_baload:
          pop_type (int_type);
          pop_type (int_type);
          require_array_type (pop_init_ref (reference_type), byte_type);
          require_array_type (pop_init_ref (reference_type), byte_type);
          push_type (int_type);
          push_type (int_type);
          break;
          break;
        case op_caload:
        case op_caload:
          pop_type (int_type);
          pop_type (int_type);
          require_array_type (pop_init_ref (reference_type), char_type);
          require_array_type (pop_init_ref (reference_type), char_type);
          push_type (int_type);
          push_type (int_type);
          break;
          break;
        case op_saload:
        case op_saload:
          pop_type (int_type);
          pop_type (int_type);
          require_array_type (pop_init_ref (reference_type), short_type);
          require_array_type (pop_init_ref (reference_type), short_type);
          push_type (int_type);
          push_type (int_type);
          break;
          break;
        case op_istore:
        case op_istore:
          set_variable (get_byte (), pop_type (int_type));
          set_variable (get_byte (), pop_type (int_type));
          break;
          break;
        case op_lstore:
        case op_lstore:
          set_variable (get_byte (), pop_type (long_type));
          set_variable (get_byte (), pop_type (long_type));
          break;
          break;
        case op_fstore:
        case op_fstore:
          set_variable (get_byte (), pop_type (float_type));
          set_variable (get_byte (), pop_type (float_type));
          break;
          break;
        case op_dstore:
        case op_dstore:
          set_variable (get_byte (), pop_type (double_type));
          set_variable (get_byte (), pop_type (double_type));
          break;
          break;
        case op_astore:
        case op_astore:
          set_variable (get_byte (), pop_ref_or_return ());
          set_variable (get_byte (), pop_ref_or_return ());
          break;
          break;
        case op_istore_0:
        case op_istore_0:
        case op_istore_1:
        case op_istore_1:
        case op_istore_2:
        case op_istore_2:
        case op_istore_3:
        case op_istore_3:
          set_variable (opcode - op_istore_0, pop_type (int_type));
          set_variable (opcode - op_istore_0, pop_type (int_type));
          break;
          break;
        case op_lstore_0:
        case op_lstore_0:
        case op_lstore_1:
        case op_lstore_1:
        case op_lstore_2:
        case op_lstore_2:
        case op_lstore_3:
        case op_lstore_3:
          set_variable (opcode - op_lstore_0, pop_type (long_type));
          set_variable (opcode - op_lstore_0, pop_type (long_type));
          break;
          break;
        case op_fstore_0:
        case op_fstore_0:
        case op_fstore_1:
        case op_fstore_1:
        case op_fstore_2:
        case op_fstore_2:
        case op_fstore_3:
        case op_fstore_3:
          set_variable (opcode - op_fstore_0, pop_type (float_type));
          set_variable (opcode - op_fstore_0, pop_type (float_type));
          break;
          break;
        case op_dstore_0:
        case op_dstore_0:
        case op_dstore_1:
        case op_dstore_1:
        case op_dstore_2:
        case op_dstore_2:
        case op_dstore_3:
        case op_dstore_3:
          set_variable (opcode - op_dstore_0, pop_type (double_type));
          set_variable (opcode - op_dstore_0, pop_type (double_type));
          break;
          break;
        case op_astore_0:
        case op_astore_0:
        case op_astore_1:
        case op_astore_1:
        case op_astore_2:
        case op_astore_2:
        case op_astore_3:
        case op_astore_3:
          set_variable (opcode - op_astore_0, pop_ref_or_return ());
          set_variable (opcode - op_astore_0, pop_ref_or_return ());
          break;
          break;
        case op_iastore:
        case op_iastore:
          pop_type (int_type);
          pop_type (int_type);
          pop_type (int_type);
          pop_type (int_type);
          require_array_type (pop_init_ref (reference_type), int_type);
          require_array_type (pop_init_ref (reference_type), int_type);
          break;
          break;
        case op_lastore:
        case op_lastore:
          pop_type (long_type);
          pop_type (long_type);
          pop_type (int_type);
          pop_type (int_type);
          require_array_type (pop_init_ref (reference_type), long_type);
          require_array_type (pop_init_ref (reference_type), long_type);
          break;
          break;
        case op_fastore:
        case op_fastore:
          pop_type (float_type);
          pop_type (float_type);
          pop_type (int_type);
          pop_type (int_type);
          require_array_type (pop_init_ref (reference_type), float_type);
          require_array_type (pop_init_ref (reference_type), float_type);
          break;
          break;
        case op_dastore:
        case op_dastore:
          pop_type (double_type);
          pop_type (double_type);
          pop_type (int_type);
          pop_type (int_type);
          require_array_type (pop_init_ref (reference_type), double_type);
          require_array_type (pop_init_ref (reference_type), double_type);
          break;
          break;
        case op_aastore:
        case op_aastore:
          pop_type (reference_type);
          pop_type (reference_type);
          pop_type (int_type);
          pop_type (int_type);
          require_array_type (pop_init_ref (reference_type), reference_type);
          require_array_type (pop_init_ref (reference_type), reference_type);
          break;
          break;
        case op_bastore:
        case op_bastore:
          pop_type (int_type);
          pop_type (int_type);
          pop_type (int_type);
          pop_type (int_type);
          require_array_type (pop_init_ref (reference_type), byte_type);
          require_array_type (pop_init_ref (reference_type), byte_type);
          break;
          break;
        case op_castore:
        case op_castore:
          pop_type (int_type);
          pop_type (int_type);
          pop_type (int_type);
          pop_type (int_type);
          require_array_type (pop_init_ref (reference_type), char_type);
          require_array_type (pop_init_ref (reference_type), char_type);
          break;
          break;
        case op_sastore:
        case op_sastore:
          pop_type (int_type);
          pop_type (int_type);
          pop_type (int_type);
          pop_type (int_type);
          require_array_type (pop_init_ref (reference_type), short_type);
          require_array_type (pop_init_ref (reference_type), short_type);
          break;
          break;
        case op_pop:
        case op_pop:
          pop32 ();
          pop32 ();
          break;
          break;
        case op_pop2:
        case op_pop2:
          {
          {
            type t = pop_raw ();
            type t = pop_raw ();
            if (! type_iswide (&t))
            if (! type_iswide (&t))
              pop32 ();
              pop32 ();
          }
          }
          break;
          break;
        case op_dup:
        case op_dup:
          {
          {
            type t = pop32 ();
            type t = pop32 ();
            push_type_t (t);
            push_type_t (t);
            push_type_t (t);
            push_type_t (t);
          }
          }
          break;
          break;
        case op_dup_x1:
        case op_dup_x1:
          {
          {
            type t1 = pop32 ();
            type t1 = pop32 ();
            type t2 = pop32 ();
            type t2 = pop32 ();
            push_type_t (t1);
            push_type_t (t1);
            push_type_t (t2);
            push_type_t (t2);
            push_type_t (t1);
            push_type_t (t1);
          }
          }
          break;
          break;
        case op_dup_x2:
        case op_dup_x2:
          {
          {
            type t1 = pop32 ();
            type t1 = pop32 ();
            type t2 = pop_raw ();
            type t2 = pop_raw ();
            if (! type_iswide (&t2))
            if (! type_iswide (&t2))
              {
              {
                type t3 = pop32 ();
                type t3 = pop32 ();
                push_type_t (t1);
                push_type_t (t1);
                push_type_t (t3);
                push_type_t (t3);
              }
              }
            else
            else
              push_type_t (t1);
              push_type_t (t1);
            push_type_t (t2);
            push_type_t (t2);
            push_type_t (t1);
            push_type_t (t1);
          }
          }
          break;
          break;
        case op_dup2:
        case op_dup2:
          {
          {
            type t = pop_raw ();
            type t = pop_raw ();
            if (! type_iswide (&t))
            if (! type_iswide (&t))
              {
              {
                type t2 = pop32 ();
                type t2 = pop32 ();
                push_type_t (t2);
                push_type_t (t2);
                push_type_t (t);
                push_type_t (t);
                push_type_t (t2);
                push_type_t (t2);
              }
              }
            else
            else
              push_type_t (t);
              push_type_t (t);
            push_type_t (t);
            push_type_t (t);
          }
          }
          break;
          break;
        case op_dup2_x1:
        case op_dup2_x1:
          {
          {
            type t1 = pop_raw ();
            type t1 = pop_raw ();
            type t2 = pop32 ();
            type t2 = pop32 ();
            if (! type_iswide (&t1))
            if (! type_iswide (&t1))
              {
              {
                type t3 = pop32 ();
                type t3 = pop32 ();
                push_type_t (t2);
                push_type_t (t2);
                push_type_t (t1);
                push_type_t (t1);
                push_type_t (t3);
                push_type_t (t3);
              }
              }
            else
            else
              push_type_t (t1);
              push_type_t (t1);
            push_type_t (t2);
            push_type_t (t2);
            push_type_t (t1);
            push_type_t (t1);
          }
          }
          break;
          break;
        case op_dup2_x2:
        case op_dup2_x2:
          {
          {
            type t1 = pop_raw ();
            type t1 = pop_raw ();
            if (type_iswide (&t1))
            if (type_iswide (&t1))
              {
              {
                type t2 = pop_raw ();
                type t2 = pop_raw ();
                if (type_iswide (&t2))
                if (type_iswide (&t2))
                  {
                  {
                    push_type_t (t1);
                    push_type_t (t1);
                    push_type_t (t2);
                    push_type_t (t2);
                  }
                  }
                else
                else
                  {
                  {
                    type t3 = pop32 ();
                    type t3 = pop32 ();
                    push_type_t (t1);
                    push_type_t (t1);
                    push_type_t (t3);
                    push_type_t (t3);
                    push_type_t (t2);
                    push_type_t (t2);
                  }
                  }
                push_type_t (t1);
                push_type_t (t1);
              }
              }
            else
            else
              {
              {
                type t2 = pop32 ();
                type t2 = pop32 ();
                type t3 = pop_raw ();
                type t3 = pop_raw ();
                if (type_iswide (&t3))
                if (type_iswide (&t3))
                  {
                  {
                    push_type_t (t2);
                    push_type_t (t2);
                    push_type_t (t1);
                    push_type_t (t1);
                  }
                  }
                else
                else
                  {
                  {
                    type t4 = pop32 ();
                    type t4 = pop32 ();
                    push_type_t (t2);
                    push_type_t (t2);
                    push_type_t (t1);
                    push_type_t (t1);
                    push_type_t (t4);
                    push_type_t (t4);
                  }
                  }
                push_type_t (t3);
                push_type_t (t3);
                push_type_t (t2);
                push_type_t (t2);
                push_type_t (t1);
                push_type_t (t1);
              }
              }
          }
          }
          break;
          break;
        case op_swap:
        case op_swap:
          {
          {
            type t1 = pop32 ();
            type t1 = pop32 ();
            type t2 = pop32 ();
            type t2 = pop32 ();
            push_type_t (t1);
            push_type_t (t1);
            push_type_t (t2);
            push_type_t (t2);
          }
          }
          break;
          break;
        case op_iadd:
        case op_iadd:
        case op_isub:
        case op_isub:
        case op_imul:
        case op_imul:
        case op_idiv:
        case op_idiv:
        case op_irem:
        case op_irem:
        case op_ishl:
        case op_ishl:
        case op_ishr:
        case op_ishr:
        case op_iushr:
        case op_iushr:
        case op_iand:
        case op_iand:
        case op_ior:
        case op_ior:
        case op_ixor:
        case op_ixor:
          pop_type (int_type);
          pop_type (int_type);
          push_type_t (pop_type (int_type));
          push_type_t (pop_type (int_type));
          break;
          break;
        case op_ladd:
        case op_ladd:
        case op_lsub:
        case op_lsub:
        case op_lmul:
        case op_lmul:
        case op_ldiv:
        case op_ldiv:
        case op_lrem:
        case op_lrem:
        case op_land:
        case op_land:
        case op_lor:
        case op_lor:
        case op_lxor:
        case op_lxor:
          pop_type (long_type);
          pop_type (long_type);
          push_type_t (pop_type (long_type));
          push_type_t (pop_type (long_type));
          break;
          break;
        case op_lshl:
        case op_lshl:
        case op_lshr:
        case op_lshr:
        case op_lushr:
        case op_lushr:
          pop_type (int_type);
          pop_type (int_type);
          push_type_t (pop_type (long_type));
          push_type_t (pop_type (long_type));
          break;
          break;
        case op_fadd:
        case op_fadd:
        case op_fsub:
        case op_fsub:
        case op_fmul:
        case op_fmul:
        case op_fdiv:
        case op_fdiv:
        case op_frem:
        case op_frem:
          pop_type (float_type);
          pop_type (float_type);
          push_type_t (pop_type (float_type));
          push_type_t (pop_type (float_type));
          break;
          break;
        case op_dadd:
        case op_dadd:
        case op_dsub:
        case op_dsub:
        case op_dmul:
        case op_dmul:
        case op_ddiv:
        case op_ddiv:
        case op_drem:
        case op_drem:
          pop_type (double_type);
          pop_type (double_type);
          push_type_t (pop_type (double_type));
          push_type_t (pop_type (double_type));
          break;
          break;
        case op_ineg:
        case op_ineg:
        case op_i2b:
        case op_i2b:
        case op_i2c:
        case op_i2c:
        case op_i2s:
        case op_i2s:
          push_type_t (pop_type (int_type));
          push_type_t (pop_type (int_type));
          break;
          break;
        case op_lneg:
        case op_lneg:
          push_type_t (pop_type (long_type));
          push_type_t (pop_type (long_type));
          break;
          break;
        case op_fneg:
        case op_fneg:
          push_type_t (pop_type (float_type));
          push_type_t (pop_type (float_type));
          break;
          break;
        case op_dneg:
        case op_dneg:
          push_type_t (pop_type (double_type));
          push_type_t (pop_type (double_type));
          break;
          break;
        case op_iinc:
        case op_iinc:
          get_variable (get_byte (), int_type);
          get_variable (get_byte (), int_type);
          get_byte ();
          get_byte ();
          break;
          break;
        case op_i2l:
        case op_i2l:
          pop_type (int_type);
          pop_type (int_type);
          push_type (long_type);
          push_type (long_type);
          break;
          break;
        case op_i2f:
        case op_i2f:
          pop_type (int_type);
          pop_type (int_type);
          push_type (float_type);
          push_type (float_type);
          break;
          break;
        case op_i2d:
        case op_i2d:
          pop_type (int_type);
          pop_type (int_type);
          push_type (double_type);
          push_type (double_type);
          break;
          break;
        case op_l2i:
        case op_l2i:
          pop_type (long_type);
          pop_type (long_type);
          push_type (int_type);
          push_type (int_type);
          break;
          break;
        case op_l2f:
        case op_l2f:
          pop_type (long_type);
          pop_type (long_type);
          push_type (float_type);
          push_type (float_type);
          break;
          break;
        case op_l2d:
        case op_l2d:
          pop_type (long_type);
          pop_type (long_type);
          push_type (double_type);
          push_type (double_type);
          break;
          break;
        case op_f2i:
        case op_f2i:
          pop_type (float_type);
          pop_type (float_type);
          push_type (int_type);
          push_type (int_type);
          break;
          break;
        case op_f2l:
        case op_f2l:
          pop_type (float_type);
          pop_type (float_type);
          push_type (long_type);
          push_type (long_type);
          break;
          break;
        case op_f2d:
        case op_f2d:
          pop_type (float_type);
          pop_type (float_type);
          push_type (double_type);
          push_type (double_type);
          break;
          break;
        case op_d2i:
        case op_d2i:
          pop_type (double_type);
          pop_type (double_type);
          push_type (int_type);
          push_type (int_type);
          break;
          break;
        case op_d2l:
        case op_d2l:
          pop_type (double_type);
          pop_type (double_type);
          push_type (long_type);
          push_type (long_type);
          break;
          break;
        case op_d2f:
        case op_d2f:
          pop_type (double_type);
          pop_type (double_type);
          push_type (float_type);
          push_type (float_type);
          break;
          break;
        case op_lcmp:
        case op_lcmp:
          pop_type (long_type);
          pop_type (long_type);
          pop_type (long_type);
          pop_type (long_type);
          push_type (int_type);
          push_type (int_type);
          break;
          break;
        case op_fcmpl:
        case op_fcmpl:
        case op_fcmpg:
        case op_fcmpg:
          pop_type (float_type);
          pop_type (float_type);
          pop_type (float_type);
          pop_type (float_type);
          push_type (int_type);
          push_type (int_type);
          break;
          break;
        case op_dcmpl:
        case op_dcmpl:
        case op_dcmpg:
        case op_dcmpg:
          pop_type (double_type);
          pop_type (double_type);
          pop_type (double_type);
          pop_type (double_type);
          push_type (int_type);
          push_type (int_type);
          break;
          break;
        case op_ifeq:
        case op_ifeq:
        case op_ifne:
        case op_ifne:
        case op_iflt:
        case op_iflt:
        case op_ifge:
        case op_ifge:
        case op_ifgt:
        case op_ifgt:
        case op_ifle:
        case op_ifle:
          pop_type (int_type);
          pop_type (int_type);
          push_jump (get_short ());
          push_jump (get_short ());
          break;
          break;
        case op_if_icmpeq:
        case op_if_icmpeq:
        case op_if_icmpne:
        case op_if_icmpne:
        case op_if_icmplt:
        case op_if_icmplt:
        case op_if_icmpge:
        case op_if_icmpge:
        case op_if_icmpgt:
        case op_if_icmpgt:
        case op_if_icmple:
        case op_if_icmple:
          pop_type (int_type);
          pop_type (int_type);
          pop_type (int_type);
          pop_type (int_type);
          push_jump (get_short ());
          push_jump (get_short ());
          break;
          break;
        case op_if_acmpeq:
        case op_if_acmpeq:
        case op_if_acmpne:
        case op_if_acmpne:
          pop_type (reference_type);
          pop_type (reference_type);
          pop_type (reference_type);
          pop_type (reference_type);
          push_jump (get_short ());
          push_jump (get_short ());
          break;
          break;
        case op_goto:
        case op_goto:
          push_jump (get_short ());
          push_jump (get_short ());
          invalidate_pc ();
          invalidate_pc ();
          break;
          break;
        case op_jsr:
        case op_jsr:
          handle_jsr_insn (get_short ());
          handle_jsr_insn (get_short ());
          break;
          break;
        case op_ret:
        case op_ret:
          handle_ret_insn (get_byte ());
          handle_ret_insn (get_byte ());
          break;
          break;
        case op_tableswitch:
        case op_tableswitch:
          {
          {
            int i;
            int i;
            jint low, high;
            jint low, high;
            pop_type (int_type);
            pop_type (int_type);
            skip_padding ();
            skip_padding ();
            push_jump (get_int ());
            push_jump (get_int ());
            low = get_int ();
            low = get_int ();
            high = get_int ();
            high = get_int ();
            /* Already checked LOW -vs- HIGH.  */
            /* Already checked LOW -vs- HIGH.  */
            for (i = low; i <= high; ++i)
            for (i = low; i <= high; ++i)
              push_jump (get_int ());
              push_jump (get_int ());
            invalidate_pc ();
            invalidate_pc ();
          }
          }
          break;
          break;
 
 
        case op_lookupswitch:
        case op_lookupswitch:
          {
          {
            int i;
            int i;
            jint npairs, lastkey;
            jint npairs, lastkey;
 
 
            pop_type (int_type);
            pop_type (int_type);
            skip_padding ();
            skip_padding ();
            push_jump (get_int ());
            push_jump (get_int ());
            npairs = get_int ();
            npairs = get_int ();
            /* Already checked NPAIRS >= 0.  */
            /* Already checked NPAIRS >= 0.  */
            lastkey = 0;
            lastkey = 0;
            for (i = 0; i < npairs; ++i)
            for (i = 0; i < npairs; ++i)
              {
              {
                jint key = get_int ();
                jint key = get_int ();
                if (i > 0 && key <= lastkey)
                if (i > 0 && key <= lastkey)
                  verify_fail_pc ("lookupswitch pairs unsorted", vfr->start_PC);
                  verify_fail_pc ("lookupswitch pairs unsorted", vfr->start_PC);
                lastkey = key;
                lastkey = key;
                push_jump (get_int ());
                push_jump (get_int ());
              }
              }
            invalidate_pc ();
            invalidate_pc ();
          }
          }
          break;
          break;
        case op_ireturn:
        case op_ireturn:
          check_return_type (pop_type (int_type));
          check_return_type (pop_type (int_type));
          invalidate_pc ();
          invalidate_pc ();
          break;
          break;
        case op_lreturn:
        case op_lreturn:
          check_return_type (pop_type (long_type));
          check_return_type (pop_type (long_type));
          invalidate_pc ();
          invalidate_pc ();
          break;
          break;
        case op_freturn:
        case op_freturn:
          check_return_type (pop_type (float_type));
          check_return_type (pop_type (float_type));
          invalidate_pc ();
          invalidate_pc ();
          break;
          break;
        case op_dreturn:
        case op_dreturn:
          check_return_type (pop_type (double_type));
          check_return_type (pop_type (double_type));
          invalidate_pc ();
          invalidate_pc ();
          break;
          break;
        case op_areturn:
        case op_areturn:
          check_return_type (pop_init_ref (reference_type));
          check_return_type (pop_init_ref (reference_type));
          invalidate_pc ();
          invalidate_pc ();
          break;
          break;
        case op_return:
        case op_return:
          /* We only need to check this when the return type is void,
          /* We only need to check this when the return type is void,
             because all instance initializers return void.  We also
             because all instance initializers return void.  We also
             need to special-case Object constructors, as they can't
             need to special-case Object constructors, as they can't
             call a superclass <init>.  */
             call a superclass <init>.  */
          if (this_is_init && vfr->current_class != vfy_object_type ())
          if (this_is_init && vfr->current_class != vfy_object_type ())
            state_check_this_initialized (vfr->current_state);
            state_check_this_initialized (vfr->current_state);
          check_return_type (make_type (void_type));
          check_return_type (make_type (void_type));
          invalidate_pc ();
          invalidate_pc ();
          break;
          break;
        case op_getstatic:
        case op_getstatic:
          push_type_t (check_field_constant (get_ushort (), NULL, false));
          push_type_t (check_field_constant (get_ushort (), NULL, false));
          break;
          break;
        case op_putstatic:
        case op_putstatic:
          pop_type_t (check_field_constant (get_ushort (), NULL, false));
          pop_type_t (check_field_constant (get_ushort (), NULL, false));
          break;
          break;
        case op_getfield:
        case op_getfield:
          {
          {
            type klass;
            type klass;
            type field = check_field_constant (get_ushort (), &klass, false);
            type field = check_field_constant (get_ushort (), &klass, false);
            pop_type_t (klass);
            pop_type_t (klass);
            push_type_t (field);
            push_type_t (field);
          }
          }
          break;
          break;
        case op_putfield:
        case op_putfield:
          {
          {
            type klass;
            type klass;
            type field = check_field_constant (get_ushort (), &klass, true);
            type field = check_field_constant (get_ushort (), &klass, true);
            pop_type_t (field);
            pop_type_t (field);
            pop_type_t (klass);
            pop_type_t (klass);
          }
          }
          break;
          break;
 
 
        case op_invokevirtual:
        case op_invokevirtual:
        case op_invokespecial:
        case op_invokespecial:
        case op_invokestatic:
        case op_invokestatic:
        case op_invokeinterface:
        case op_invokeinterface:
          {
          {
            vfy_string method_name, method_signature;
            vfy_string method_name, method_signature;
            const char *namec;
            const char *namec;
            int i, arg_count;
            int i, arg_count;
            type rt;
            type rt;
            bool is_init = false;
            bool is_init = false;
 
 
            type class_type
            type class_type
              = check_method_constant (get_ushort (),
              = check_method_constant (get_ushort (),
                                       opcode == op_invokeinterface,
                                       opcode == op_invokeinterface,
                                       &method_name,
                                       &method_name,
                                       &method_signature);
                                       &method_signature);
            /* NARGS is only used when we're processing
            /* NARGS is only used when we're processing
               invokeinterface.  It is simplest for us to compute it
               invokeinterface.  It is simplest for us to compute it
               here and then verify it later.  */
               here and then verify it later.  */
            int nargs = 0;
            int nargs = 0;
            if (opcode == op_invokeinterface)
            if (opcode == op_invokeinterface)
              {
              {
                nargs = get_byte ();
                nargs = get_byte ();
                if (get_byte () != 0)
                if (get_byte () != 0)
                  verify_fail ("invokeinterface dummy byte is wrong");
                  verify_fail ("invokeinterface dummy byte is wrong");
              }
              }
 
 
            namec = vfy_string_bytes (method_name);
            namec = vfy_string_bytes (method_name);
 
 
            if (vfy_strings_equal (method_name, vfy_init_name()))
            if (vfy_strings_equal (method_name, vfy_init_name()))
              {
              {
                is_init = true;
                is_init = true;
                if (opcode != op_invokespecial)
                if (opcode != op_invokespecial)
                  verify_fail ("can't invoke <init>");
                  verify_fail ("can't invoke <init>");
              }
              }
            else if (namec[0] == '<')
            else if (namec[0] == '<')
              verify_fail ("can't invoke method starting with `<'");
              verify_fail ("can't invoke method starting with `<'");
 
 
            arg_count = vfy_count_arguments (method_signature);
            arg_count = vfy_count_arguments (method_signature);
            {
            {
              /* Pop arguments and check types.  */
              /* Pop arguments and check types.  */
              type *arg_types = (type *) vfy_alloc (arg_count * sizeof (type));
              type *arg_types = (type *) vfy_alloc (arg_count * sizeof (type));
 
 
              compute_argument_types (method_signature, arg_types);
              compute_argument_types (method_signature, arg_types);
              for (i = arg_count - 1; i >= 0; --i)
              for (i = arg_count - 1; i >= 0; --i)
                {
                {
                  /* This is only used for verifying the byte for
                  /* This is only used for verifying the byte for
                     invokeinterface.  */
                     invokeinterface.  */
                  nargs -= type_depth (&arg_types[i]);
                  nargs -= type_depth (&arg_types[i]);
                  pop_init_ref_t (arg_types[i]);
                  pop_init_ref_t (arg_types[i]);
                }
                }
 
 
              vfy_free (arg_types);
              vfy_free (arg_types);
            }
            }
 
 
            if (opcode == op_invokeinterface
            if (opcode == op_invokeinterface
                && nargs != 1)
                && nargs != 1)
              verify_fail ("wrong argument count for invokeinterface");
              verify_fail ("wrong argument count for invokeinterface");
 
 
            if (opcode != op_invokestatic)
            if (opcode != op_invokestatic)
              {
              {
                type raw;
                type raw;
                type t = class_type;
                type t = class_type;
                if (is_init)
                if (is_init)
                  {
                  {
                    /* In this case the PC doesn't matter.  */
                    /* In this case the PC doesn't matter.  */
                    type_set_uninitialized (&t, UNINIT);
                    type_set_uninitialized (&t, UNINIT);
                    /* FIXME: check to make sure that the <init>
                    /* FIXME: check to make sure that the <init>
                       call is to the right class.
                       call is to the right class.
                       It must either be super or an exact class
                       It must either be super or an exact class
                       match.  */
                       match.  */
                  }
                  }
                raw = pop_raw ();
                raw = pop_raw ();
                if (! types_compatible (&t, &raw))
                if (! types_compatible (&t, &raw))
                  verify_fail ("incompatible type on stack");
                  verify_fail ("incompatible type on stack");
 
 
                if (is_init)
                if (is_init)
                  state_set_initialized (vfr->current_state,
                  state_set_initialized (vfr->current_state,
                    type_get_pc (&raw), vfr->current_method->max_locals);
                    type_get_pc (&raw), vfr->current_method->max_locals);
              }
              }
 
 
            rt = compute_return_type (method_signature);
            rt = compute_return_type (method_signature);
            if (! type_isvoid (&rt))
            if (! type_isvoid (&rt))
              push_type_t (rt);
              push_type_t (rt);
          }
          }
          break;
          break;
 
 
        case op_new:
        case op_new:
          {
          {
            type t = check_class_constant (get_ushort ());
            type t = check_class_constant (get_ushort ());
            if (type_isarray (&t) || type_isinterface (&t)
            if (type_isarray (&t) || type_isinterface (&t)
                || type_isabstract (&t))
                || type_isabstract (&t))
              verify_fail ("type is array, interface, or abstract");
              verify_fail ("type is array, interface, or abstract");
            type_set_uninitialized (&t, vfr->start_PC);
            type_set_uninitialized (&t, vfr->start_PC);
            push_type_t (t);
            push_type_t (t);
          }
          }
          break;
          break;
 
 
        case op_newarray:
        case op_newarray:
          {
          {
            int atype = get_byte ();
            int atype = get_byte ();
            vfy_jclass k;
            vfy_jclass k;
            type t;
            type t;
            /* We intentionally have chosen constants to make this
            /* We intentionally have chosen constants to make this
               valid.  */
               valid.  */
            if (atype < boolean_type || atype > long_type)
            if (atype < boolean_type || atype > long_type)
              verify_fail_pc ("type not primitive", vfr->start_PC);
              verify_fail_pc ("type not primitive", vfr->start_PC);
            pop_type (int_type);
            pop_type (int_type);
            k = construct_primitive_array_type ((type_val) atype);
            k = construct_primitive_array_type ((type_val) atype);
            init_type_from_class (&t, k);
            init_type_from_class (&t, k);
            push_type_t (t);
            push_type_t (t);
          }
          }
          break;
          break;
        case op_anewarray:
        case op_anewarray:
          {
          {
            type t;
            type t;
            pop_type (int_type);
            pop_type (int_type);
            t = check_class_constant (get_ushort ());
            t = check_class_constant (get_ushort ());
            push_type_t (type_to_array (&t));
            push_type_t (type_to_array (&t));
          }
          }
          break;
          break;
        case op_arraylength:
        case op_arraylength:
          {
          {
            type t = pop_init_ref (reference_type);
            type t = pop_init_ref (reference_type);
            if (! type_isarray (&t) && ! type_isnull (&t))
            if (! type_isarray (&t) && ! type_isnull (&t))
              verify_fail ("array type expected");
              verify_fail ("array type expected");
            push_type (int_type);
            push_type (int_type);
          }
          }
          break;
          break;
        case op_athrow:
        case op_athrow:
          pop_type_t (make_type_from_class (vfy_throwable_type ()));
          pop_type_t (make_type_from_class (vfy_throwable_type ()));
          invalidate_pc ();
          invalidate_pc ();
          break;
          break;
        case op_checkcast:
        case op_checkcast:
          pop_init_ref (reference_type);
          pop_init_ref (reference_type);
          push_type_t (check_class_constant (get_ushort ()));
          push_type_t (check_class_constant (get_ushort ()));
          break;
          break;
        case op_instanceof:
        case op_instanceof:
          pop_init_ref (reference_type);
          pop_init_ref (reference_type);
          check_class_constant (get_ushort ());
          check_class_constant (get_ushort ());
          push_type (int_type);
          push_type (int_type);
          break;
          break;
        case op_monitorenter:
        case op_monitorenter:
          pop_init_ref (reference_type);
          pop_init_ref (reference_type);
          break;
          break;
        case op_monitorexit:
        case op_monitorexit:
          pop_init_ref (reference_type);
          pop_init_ref (reference_type);
          break;
          break;
        case op_wide:
        case op_wide:
          {
          {
            switch (get_byte ())
            switch (get_byte ())
              {
              {
              case op_iload:
              case op_iload:
                push_type_t (get_variable (get_ushort (), int_type));
                push_type_t (get_variable (get_ushort (), int_type));
                break;
                break;
              case op_lload:
              case op_lload:
                push_type_t (get_variable (get_ushort (), long_type));
                push_type_t (get_variable (get_ushort (), long_type));
                break;
                break;
              case op_fload:
              case op_fload:
                push_type_t (get_variable (get_ushort (), float_type));
                push_type_t (get_variable (get_ushort (), float_type));
                break;
                break;
              case op_dload:
              case op_dload:
                push_type_t (get_variable (get_ushort (), double_type));
                push_type_t (get_variable (get_ushort (), double_type));
                break;
                break;
              case op_aload:
              case op_aload:
                push_type_t (get_variable (get_ushort (), reference_type));
                push_type_t (get_variable (get_ushort (), reference_type));
                break;
                break;
              case op_istore:
              case op_istore:
                set_variable (get_ushort (), pop_type (int_type));
                set_variable (get_ushort (), pop_type (int_type));
                break;
                break;
              case op_lstore:
              case op_lstore:
                set_variable (get_ushort (), pop_type (long_type));
                set_variable (get_ushort (), pop_type (long_type));
                break;
                break;
              case op_fstore:
              case op_fstore:
                set_variable (get_ushort (), pop_type (float_type));
                set_variable (get_ushort (), pop_type (float_type));
                break;
                break;
              case op_dstore:
              case op_dstore:
                set_variable (get_ushort (), pop_type (double_type));
                set_variable (get_ushort (), pop_type (double_type));
                break;
                break;
              case op_astore:
              case op_astore:
                set_variable (get_ushort (), pop_init_ref (reference_type));
                set_variable (get_ushort (), pop_init_ref (reference_type));
                break;
                break;
              case op_ret:
              case op_ret:
                handle_ret_insn (get_short ());
                handle_ret_insn (get_short ());
                break;
                break;
              case op_iinc:
              case op_iinc:
                get_variable (get_ushort (), int_type);
                get_variable (get_ushort (), int_type);
                get_short ();
                get_short ();
                break;
                break;
              default:
              default:
                verify_fail_pc ("unrecognized wide instruction", vfr->start_PC);
                verify_fail_pc ("unrecognized wide instruction", vfr->start_PC);
              }
              }
          }
          }
          break;
          break;
        case op_multianewarray:
        case op_multianewarray:
          {
          {
            int i;
            int i;
            type atype = check_class_constant (get_ushort ());
            type atype = check_class_constant (get_ushort ());
            int dim = get_byte ();
            int dim = get_byte ();
            if (dim < 1)
            if (dim < 1)
              verify_fail_pc ("too few dimensions to multianewarray", vfr->start_PC);
              verify_fail_pc ("too few dimensions to multianewarray", vfr->start_PC);
            type_verify_dimensions (&atype, dim);
            type_verify_dimensions (&atype, dim);
            for (i = 0; i < dim; ++i)
            for (i = 0; i < dim; ++i)
              pop_type (int_type);
              pop_type (int_type);
            push_type_t (atype);
            push_type_t (atype);
          }
          }
          break;
          break;
        case op_ifnull:
        case op_ifnull:
        case op_ifnonnull:
        case op_ifnonnull:
          pop_type (reference_type);
          pop_type (reference_type);
          push_jump (get_short ());
          push_jump (get_short ());
          break;
          break;
        case op_goto_w:
        case op_goto_w:
          push_jump (get_int ());
          push_jump (get_int ());
          invalidate_pc ();
          invalidate_pc ();
          break;
          break;
        case op_jsr_w:
        case op_jsr_w:
          handle_jsr_insn (get_int ());
          handle_jsr_insn (get_int ());
          break;
          break;
 
 
        default:
        default:
          /* Unrecognized opcode.  */
          /* Unrecognized opcode.  */
          verify_fail_pc ("unrecognized instruction in verify_instructions_0",
          verify_fail_pc ("unrecognized instruction in verify_instructions_0",
                       vfr->start_PC);
                       vfr->start_PC);
        }
        }
    }
    }
}
}
 
 
/* This turns a `type' into something suitable for use by the type map
/* This turns a `type' into something suitable for use by the type map
   in the other parts of the compiler.  In particular, reference types
   in the other parts of the compiler.  In particular, reference types
   are mapped to Object, primitive types are unchanged, and other
   are mapped to Object, primitive types are unchanged, and other
   types are mapped using special functions declared in verify.h.  */
   types are mapped using special functions declared in verify.h.  */
static vfy_jclass
static vfy_jclass
collapse_type (type *t)
collapse_type (type *t)
{
{
  switch (t->key)
  switch (t->key)
    {
    {
    case void_type:
    case void_type:
    case boolean_type:
    case boolean_type:
    case char_type:
    case char_type:
    case float_type:
    case float_type:
    case double_type:
    case double_type:
    case byte_type:
    case byte_type:
    case short_type:
    case short_type:
    case int_type:
    case int_type:
    case long_type:
    case long_type:
      return vfy_get_primitive_type (t->key);
      return vfy_get_primitive_type (t->key);
 
 
    case unsuitable_type:
    case unsuitable_type:
    case continuation_type:
    case continuation_type:
      return vfy_unsuitable_type ();
      return vfy_unsuitable_type ();
 
 
    case return_address_type:
    case return_address_type:
      return vfy_return_address_type ();
      return vfy_return_address_type ();
 
 
    case null_type:
    case null_type:
      return vfy_null_type ();
      return vfy_null_type ();
 
 
    case reference_type:
    case reference_type:
    case uninitialized_reference_type:
    case uninitialized_reference_type:
      return vfy_object_type ();
      return vfy_object_type ();
    }
    }
 
 
  gcc_unreachable ();
  gcc_unreachable ();
}
}
 
 
static void
static void
verify_instructions (void)
verify_instructions (void)
{
{
  int i;
  int i;
 
 
  branch_prepass ();
  branch_prepass ();
  verify_instructions_0 ();
  verify_instructions_0 ();
 
 
  /* Now tell the rest of the compiler about the types we've found.  */
  /* Now tell the rest of the compiler about the types we've found.  */
  for (i = 0; i < vfr->current_method->code_length; ++i)
  for (i = 0; i < vfr->current_method->code_length; ++i)
    {
    {
      int j, slot;
      int j, slot;
      struct state *curr;
      struct state *curr;
 
 
      if ((vfr->flags[i] & FLAG_INSN_SEEN) != 0)
      if ((vfr->flags[i] & FLAG_INSN_SEEN) != 0)
        vfy_note_instruction_seen (i);
        vfy_note_instruction_seen (i);
 
 
      if (! vfr->states[i])
      if (! vfr->states[i])
        continue;
        continue;
 
 
      curr = vfr->states[i]->val;
      curr = vfr->states[i]->val;
      vfy_note_stack_depth (vfr->current_method, i, curr->stackdepth);
      vfy_note_stack_depth (vfr->current_method, i, curr->stackdepth);
 
 
      /* Tell the compiler about each local variable.  */
      /* Tell the compiler about each local variable.  */
      for (j = 0; j < vfr->current_method->max_locals; ++j)
      for (j = 0; j < vfr->current_method->max_locals; ++j)
        vfy_note_local_type (vfr->current_method, i, j,
        vfy_note_local_type (vfr->current_method, i, j,
                             collapse_type (&curr->locals[j]));
                             collapse_type (&curr->locals[j]));
      /* Tell the compiler about each stack slot.  */
      /* Tell the compiler about each stack slot.  */
      for (slot = j = 0; j < curr->stacktop; ++j, ++slot)
      for (slot = j = 0; j < curr->stacktop; ++j, ++slot)
        {
        {
          vfy_note_stack_type (vfr->current_method, i, slot,
          vfy_note_stack_type (vfr->current_method, i, slot,
                               collapse_type (&curr->stack[j]));
                               collapse_type (&curr->stack[j]));
          if (type_iswide (&curr->stack[j]))
          if (type_iswide (&curr->stack[j]))
            {
            {
              ++slot;
              ++slot;
              vfy_note_stack_type (vfr->current_method, i, slot,
              vfy_note_stack_type (vfr->current_method, i, slot,
                                   vfy_unsuitable_type ());
                                   vfy_unsuitable_type ());
            }
            }
        }
        }
      gcc_assert (slot == curr->stackdepth);
      gcc_assert (slot == curr->stackdepth);
    }
    }
}
}
 
 
static void
static void
make_verifier_context (vfy_method *m)
make_verifier_context (vfy_method *m)
{
{
  vfr = (verifier_context *) vfy_alloc (sizeof (struct verifier_context));
  vfr = (verifier_context *) vfy_alloc (sizeof (struct verifier_context));
 
 
  vfr->current_method = m;
  vfr->current_method = m;
  vfr->bytecode = vfy_get_bytecode (m);
  vfr->bytecode = vfy_get_bytecode (m);
  vfr->exception = vfy_get_exceptions (m);
  vfr->exception = vfy_get_exceptions (m);
  vfr->current_class = m->defining_class;
  vfr->current_class = m->defining_class;
 
 
  vfr->states = NULL;
  vfr->states = NULL;
  vfr->flags = NULL;
  vfr->flags = NULL;
  vfr->utf8_list = NULL;
  vfr->utf8_list = NULL;
  vfr->isect_list = NULL;
  vfr->isect_list = NULL;
}
}
 
 
static void
static void
free_verifier_context (void)
free_verifier_context (void)
{
{
  vfy_string_list *utf8_list;
  vfy_string_list *utf8_list;
  ref_intersection *isect_list;
  ref_intersection *isect_list;
 
 
  if (vfr->flags)
  if (vfr->flags)
    vfy_free (vfr->flags);
    vfy_free (vfr->flags);
 
 
  utf8_list = vfr->utf8_list;
  utf8_list = vfr->utf8_list;
  while (utf8_list != NULL)
  while (utf8_list != NULL)
    {
    {
      vfy_string_list *n = utf8_list->next;
      vfy_string_list *n = utf8_list->next;
      vfy_free (utf8_list);
      vfy_free (utf8_list);
      utf8_list = n;
      utf8_list = n;
    }
    }
 
 
  isect_list = vfr->isect_list;
  isect_list = vfr->isect_list;
  while (isect_list != NULL)
  while (isect_list != NULL)
    {
    {
      ref_intersection *next = isect_list->alloc_next;
      ref_intersection *next = isect_list->alloc_next;
      vfy_free (isect_list);
      vfy_free (isect_list);
      isect_list = next;
      isect_list = next;
    }
    }
 
 
  if (vfr->states != NULL)
  if (vfr->states != NULL)
    {
    {
      int i;
      int i;
      for (i = 0; i < vfr->current_method->code_length; ++i)
      for (i = 0; i < vfr->current_method->code_length; ++i)
        {
        {
          state_list *iter = vfr->states[i];
          state_list *iter = vfr->states[i];
          while (iter != NULL)
          while (iter != NULL)
            {
            {
              state_list *next = iter->next;
              state_list *next = iter->next;
              free_state (iter->val);
              free_state (iter->val);
              vfy_free (iter->val);
              vfy_free (iter->val);
              vfy_free (iter);
              vfy_free (iter);
              iter = next;
              iter = next;
            }
            }
        }
        }
      vfy_free (vfr->states);
      vfy_free (vfr->states);
    }
    }
 
 
  vfy_free (vfr);
  vfy_free (vfr);
}
}
 
 
int
int
verify_method (vfy_method *meth)
verify_method (vfy_method *meth)
{
{
  debug_print ("verify_method (%s) %i\n", vfy_string_bytes (meth->name),
  debug_print ("verify_method (%s) %i\n", vfy_string_bytes (meth->name),
               meth->code_length);
               meth->code_length);
 
 
  if (vfr != NULL)
  if (vfr != NULL)
    verify_fail ("verifier re-entered");
    verify_fail ("verifier re-entered");
 
 
  make_verifier_context (meth);
  make_verifier_context (meth);
  verify_instructions ();
  verify_instructions ();
  free_verifier_context ();
  free_verifier_context ();
  vfr = NULL;
  vfr = NULL;
 
 
  return 1;
  return 1;
}
}
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.