OSDN Git Service

2012-04-23 Andrew Haley <aph@redhat.com>
[pf3gnuchains/gcc-fork.git] / libjava / defineclass.cc
index d580516..17f6081 100644 (file)
@@ -1,6 +1,7 @@
 // defineclass.cc - defining a class from .class format.
 
-/* Copyright (C) 1999, 2000  Free Software Foundation
+/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   Free Software Foundation
 
    This file is part of libgcj.
 
@@ -22,11 +23,11 @@ details.  */
 
 #include <java-interp.h>
 
-#ifdef INTERPRETER
-
 #include <stdlib.h>
+#include <stdio.h>
 #include <java-cpool.h>
 #include <gcj/cni.h>
+#include <execution.h>
 
 #include <java/lang/Class.h>
 #include <java/lang/Float.h>
@@ -37,35 +38,33 @@ details.  */
 #include <java/lang/ClassFormatError.h>
 #include <java/lang/NoClassDefFoundError.h>
 #include <java/lang/ClassCircularityError.h>
-#include <java/lang/ClassNotFoundException.h>
 #include <java/lang/IncompatibleClassChangeError.h>
 #include <java/lang/reflect/Modifier.h>
+#include <java/lang/reflect/Field.h>
+#include <java/lang/reflect/Method.h>
+#include <java/security/ProtectionDomain.h>
+#include <java/io/DataOutputStream.h>
+#include <java/io/ByteArrayOutputStream.h>
 
-// we don't verify method names that match these.
-static _Jv_Utf8Const *clinit_name = _Jv_makeUtf8Const ("<clinit>", 8);
-static _Jv_Utf8Const *init_name = _Jv_makeUtf8Const ("<init>", 6);
+using namespace gcj;
 
+#ifdef INTERPRETER
 
-// these go in some seperate functions, to avoid having _Jv_InitClass
+// these go in some separate functions, to avoid having _Jv_InitClass
 // inserted all over the place.
-static void throw_internal_error (char *msg)
+static void throw_internal_error (const char *msg)
        __attribute__ ((__noreturn__));
 static void throw_no_class_def_found_error (jstring msg)
        __attribute__ ((__noreturn__));
-static void throw_no_class_def_found_error (char *msg)
+static void throw_no_class_def_found_error (const char *msg)
        __attribute__ ((__noreturn__));
 static void throw_class_format_error (jstring msg)
        __attribute__ ((__noreturn__));
-static void throw_class_format_error (char *msg)
-       __attribute__ ((__noreturn__));
 static void throw_incompatible_class_change_error (jstring msg)
        __attribute__ ((__noreturn__));
 static void throw_class_circularity_error (jstring msg)
        __attribute__ ((__noreturn__));
 
-static jdouble long_bits_to_double (jlong);
-static jfloat int_bits_to_float (jint);
-
 /**
  * We define class reading using a class.  It is practical, since then
  * the entire class-reader can be a friend of class Class (it needs to
@@ -76,7 +75,8 @@ static jfloat int_bits_to_float (jint);
  * public or private members here.
  */
 
-struct _Jv_ClassReader {
+struct _Jv_ClassReader
+{
 
   // do verification?  Currently, there is no option to disable this.
   // This flag just controls the verificaiton done by the class loader;
@@ -84,7 +84,7 @@ struct _Jv_ClassReader {
   // allways on.  You always want this as far as I can see, but it also
   // controls weither identifiers and type descriptors/signatures are
   // verified as legal.  This could be somewhat more expensive since it
-  // will call Characher.isJavaIdentifier{Start,Part} for each character
+  // will call Character.isJavaIdentifier{Start,Part} for each character
   // in any identifier (field name or method name) it comes by.  Thus,
   // it might be useful to turn off this verification for classes that
   // come from a trusted source.  However, for GCJ, trusted classes are
@@ -92,6 +92,10 @@ struct _Jv_ClassReader {
 
   bool verify;
 
+  // original input data.
+  jbyteArray input_data;
+  jint input_offset;
+
   // input data.
   unsigned char     *bytes;
   int                len;
@@ -105,7 +109,21 @@ struct _Jv_ClassReader {
   unsigned int      *offsets;
 
   // the class to define (see java-interp.h)
-  _Jv_InterpClass   *def;
+  jclass          def;
+
+  // the classes associated interpreter data.
+  _Jv_InterpClass  *def_interp;
+
+  // The name we found.
+  _Jv_Utf8Const **found_name;
+
+  // True if this is a 1.5 class file.
+  bool             is_15;
+
+  // Buffer holding extra reflection data.
+  ::java::io::ByteArrayOutputStream *reflection_data;
+  ::java::io::DataOutputStream *data_stream;
+
 
   /* check that the given number of input bytes are available */
   inline void check (int num)
@@ -121,7 +139,7 @@ struct _Jv_ClassReader {
     pos += num;
   }
   
-  /* read an unsignend 1-byte unit */
+  /* read an unsigned 1-byte unit */
   inline static jint get1u (unsigned char* bytes)
   {
     return bytes[0];
@@ -191,31 +209,100 @@ struct _Jv_ClassReader {
       throw_class_format_error ("erroneous constant pool tag");
   }
 
-  _Jv_ClassReader (jclass klass, jbyteArray data, jint offset, jint length)
+  inline void verify_identifier (_Jv_Utf8Const* name)
+  {
+    if (! _Jv_VerifyIdentifier (name))
+      throw_class_format_error ("erroneous identifier");
+  }
+
+  inline void verify_classname (unsigned char* ptr, _Jv_ushort length)
+  {
+    if (! _Jv_VerifyClassName (ptr, length))
+      throw_class_format_error ("erroneous class name");
+  }
+
+  inline void verify_classname (_Jv_Utf8Const *name)
+  {
+    if (! _Jv_VerifyClassName (name))
+      throw_class_format_error ("erroneous class name");
+  }
+
+  inline void verify_field_signature (_Jv_Utf8Const *sig)
+  {
+    if (! _Jv_VerifyFieldSignature (sig))
+      throw_class_format_error ("erroneous type descriptor");
+  }
+
+  inline void verify_method_signature (_Jv_Utf8Const *sig)
+  {
+    if (! _Jv_VerifyMethodSignature (sig))
+      throw_class_format_error ("erroneous type descriptor");
+  }
+
+  ::java::io::DataOutputStream *get_reflection_stream ()
+  {
+    if (reflection_data == NULL)
+      {
+       reflection_data = new ::java::io::ByteArrayOutputStream();
+       data_stream = new ::java::io::DataOutputStream(reflection_data);
+      }
+    return data_stream;
+  }
+
+  _Jv_ClassReader (jclass klass, jbyteArray data, jint offset, jint length,
+                  java::security::ProtectionDomain *pd,
+                  _Jv_Utf8Const **name_result)
   {
     if (klass == 0 || length < 0 || offset+length > data->length)
       throw_internal_error ("arguments to _Jv_DefineClass");
 
     verify = true;
+    input_data = data;
+    input_offset = offset;
     bytes  = (unsigned char*) (elements (data)+offset);
     len    = length;
     pos    = 0;
-    def    = (_Jv_InterpClass*) klass;
+    is_15  = false;
+
+    def    = klass;
+    found_name = name_result;
+    reflection_data = NULL;
+    data_stream = NULL;
+
+    def->size_in_bytes = -1;
+    def->vtable_method_count = -1;
+    def->engine = &_Jv_soleInterpreterEngine;
+    def->protectionDomain = pd;
   }
 
   /** and here goes the parser members defined out-of-line */
   void parse ();
   void read_constpool ();
-  void prepare_pool_entry (int index, unsigned char tag);
+  void prepare_pool_entry (int index, unsigned char tag,
+                          bool rewrite = true);
   void read_fields ();
   void read_methods ();
   void read_one_class_attribute ();
   void read_one_method_attribute (int method);
   void read_one_code_attribute (int method);
-  void read_one_field_attribute (int field);
+  void read_one_field_attribute (int field, bool *);
+  void throw_class_format_error (const char *msg);
+
+  void handleEnclosingMethod(int);
+  void handleGenericSignature(jv_attr_type, unsigned short, int);
+  void handleAnnotationElement();
+  void handleAnnotation();
+  void handleAnnotations();
+  void handleMemberAnnotations(jv_attr_type, int, int);
+  void handleAnnotationDefault(int, int);
+  void handleParameterAnnotations(int, int);
+  void finish_reflection_data ();
 
   /** check an utf8 entry, without creating a Utf8Const object */
-  bool is_attribute_name (int index, char *name);
+  bool is_attribute_name (int index, const char *name);
+  
+  /** return the value of a utf8 entry in the passed array */
+  int pool_Utf8_to_char_arr (int index, char **entry);
 
   /** here goes the class-loader members defined out-of-line */
   void handleConstantPool ();
@@ -223,9 +310,8 @@ struct _Jv_ClassReader {
   void handleInterfacesBegin (int);
   void handleInterface (int, int);
   void handleFieldsBegin (int);
-  void handleField (int, int, int, int);
-  void handleFieldsEnd ();
-  void handleConstantValueAttribute (int,int);
+  void handleField (int, int, int, int, int *);
+  void handleConstantValueAttribute (int, int, bool *);
   void handleMethodsBegin (int);
   void handleMethod (int, int, int, int);
   void handleMethodsEnd ();
@@ -245,46 +331,53 @@ struct _Jv_ClassReader {
    */
 };
 
-/* This is used for the isJavaIdentifierStart & isJavaIdentifierPart
-   methods, so we avoid doing _Jv_InitClass all the time */
-
-static const java::lang::Character *character = 0;
-static void prepare_character ();
-
+// Note that *NAME_RESULT will only be set if the class is registered
+// with the class loader.  This is how the caller can know whether
+// unregistration is require.
 void
-_Jv_DefineClass (jclass klass, jbyteArray data, jint offset, jint length)
+_Jv_DefineClass (jclass klass, jbyteArray data, jint offset, jint length,
+                java::security::ProtectionDomain *pd,
+                _Jv_Utf8Const **name_result)
 {
-  if (character == 0)
-    prepare_character ();
-
-  _Jv_ClassReader reader (klass, data, offset, length);
+  _Jv_ClassReader reader (klass, data, offset, length, pd, name_result);
   reader.parse();
 
   /* that's it! */
 }
 
-/** put it after _Jv_DefineClass, so it doesn't get inlined */
-static void prepare_character ()
-{
-  character = new java::lang::Character ('!');
-}
-
 \f
 /** This section defines the parsing/scanning of the class data */
 
+// Major and minor version numbers for various releases.
+#define MAJOR_1_1 45
+#define MINOR_1_1  3
+#define MAJOR_1_2 46
+#define MINOR_1_2  0
+#define MAJOR_1_3 47
+#define MINOR_1_3  0
+#define MAJOR_1_4 48
+#define MINOR_1_4  0
+#define MAJOR_1_5 49
+#define MINOR_1_5  0
+#define MAJOR_1_6 50
+#define MINOR_1_6  0
+#define MAJOR_1_7 51
+#define MINOR_1_7  0
+
 void
 _Jv_ClassReader::parse ()
 {
   int magic = read4 ();
-
-  /* FIXME: Decide which range of version numbers to allow */
-
-  /* int minor_version = */ read2u ();
-  /* int major_verson  = */ read2u ();
-
   if (magic != (int) 0xCAFEBABE)
     throw_class_format_error ("bad magic number");
 
+  int minor_version = read2u ();
+  int major_version = read2u ();
+  if (major_version < MAJOR_1_1 || major_version > MAJOR_1_7
+      || (major_version == MAJOR_1_7 && minor_version > MINOR_1_7))
+    throw_class_format_error ("unrecognized class file version");
+  is_15 = (major_version >= MAJOR_1_5);
+
   pool_count = read2u ();
 
   read_constpool ();
@@ -299,8 +392,13 @@ _Jv_ClassReader::parse ()
 
   handleClassBegin (access_flags, this_class, super_class);
 
+  // Allocate our aux_info here, after the name is set, to fulfill our
+  // contract with the collector interface.
+  def->aux_info = (void *) _Jv_AllocRawObj (sizeof (_Jv_InterpClass));
+  def_interp = (_Jv_InterpClass *) def->aux_info;
+
   int interfaces_count = read2u (); 
-       
+
   handleInterfacesBegin (interfaces_count);
 
   for (int i = 0; i < interfaces_count; i++)
@@ -323,17 +421,246 @@ _Jv_ClassReader::parse ()
   if (pos != len)
     throw_class_format_error ("unused data before end of file");
 
-  // tell everyone we're done.
-  def->state = JV_STATE_LOADED;
+  finish_reflection_data ();
+
+  // Tell everyone we're done.
+  def->state = JV_STATE_READ;
+  if (gcj::verbose_class_flag)
+    _Jv_Linker::print_class_loaded (def);
+  ++gcj::loadedClasses;
   def->notifyAll ();
+}
 
+void
+_Jv_ClassReader::finish_reflection_data ()
+{
+  if (data_stream == NULL)
+    return;
+  data_stream->writeByte(JV_DONE_ATTR);
+  data_stream->flush();
+  int nbytes = reflection_data->count;
+  unsigned char *new_bytes = (unsigned char *) _Jv_AllocBytes (nbytes);
+  memcpy (new_bytes, elements (reflection_data->buf), nbytes);
+  def->reflection_data = new_bytes;
+}
+
+void
+_Jv_ClassReader::handleEnclosingMethod (int len)
+{
+  if (len != 4)
+    throw_class_format_error ("invalid EnclosingMethod attribute");
+  // FIXME: only allow one...
+
+  int class_index = read2u();
+  check_tag (class_index, JV_CONSTANT_Class);
+  prepare_pool_entry (class_index, JV_CONSTANT_Class);
+
+  int method_index = read2u();
+  // Zero is ok and means no enclosing method.
+  if (method_index != 0)
+    {
+      check_tag (method_index, JV_CONSTANT_NameAndType);
+      prepare_pool_entry (method_index, JV_CONSTANT_NameAndType);
+    }
+
+  ::java::io::DataOutputStream *stream = get_reflection_stream ();
+  stream->writeByte(JV_CLASS_ATTR);
+  stream->writeInt(5);
+  stream->writeByte(JV_ENCLOSING_METHOD_KIND);
+  stream->writeShort(class_index);
+  stream->writeShort(method_index);
+}
+
+void
+_Jv_ClassReader::handleGenericSignature (jv_attr_type type,
+                                        unsigned short index,
+                                        int len)
+{
+  if (len != 2)
+    throw_class_format_error ("invalid Signature attribute");
+
+  int cpool_idx = read2u();
+  check_tag (cpool_idx, JV_CONSTANT_Utf8);
+  prepare_pool_entry (cpool_idx, JV_CONSTANT_Utf8, false);
+
+  ::java::io::DataOutputStream *stream = get_reflection_stream ();
+  stream->writeByte(type);
+  int attrlen = 3;
+  if (type != JV_CLASS_ATTR)
+    attrlen += 2;
+  stream->writeInt(attrlen);
+  if (type != JV_CLASS_ATTR)
+    stream->writeShort(index);
+  stream->writeByte(JV_SIGNATURE_KIND);
+  stream->writeShort(cpool_idx);
+}
+
+void
+_Jv_ClassReader::handleAnnotationElement()
+{
+  int tag = read1u();
+  switch (tag)
+    {
+    case 'B':
+    case 'C':
+    case 'S':
+    case 'Z':
+    case 'I':
+      {
+       int index = read2u();
+       check_tag (index, JV_CONSTANT_Integer);
+       prepare_pool_entry (index, JV_CONSTANT_Integer);
+      }
+      break;
+    case 'D':
+      {
+       int index = read2u();
+       check_tag (index, JV_CONSTANT_Double);
+       prepare_pool_entry (index, JV_CONSTANT_Double);
+      }
+      break;
+    case 'F':
+      {
+       int index = read2u();
+       check_tag (index, JV_CONSTANT_Float);
+       prepare_pool_entry (index, JV_CONSTANT_Float);
+      }
+      break;
+    case 'J':
+      {
+       int index = read2u();
+       check_tag (index, JV_CONSTANT_Long);
+       prepare_pool_entry (index, JV_CONSTANT_Long);
+      }
+      break;
+    case 's':
+      {
+       int index = read2u();
+       // Despite what the JVM spec says, compilers generate a Utf8
+       // constant here, not a String.
+       check_tag (index, JV_CONSTANT_Utf8);
+       prepare_pool_entry (index, JV_CONSTANT_Utf8, false);
+      }
+      break;
+
+    case 'e':
+      {
+       int type_name_index = read2u();
+       int const_name_index = read2u ();
+       check_tag (type_name_index, JV_CONSTANT_Utf8);
+       prepare_pool_entry (type_name_index, JV_CONSTANT_Utf8);
+       check_tag (const_name_index, JV_CONSTANT_Utf8);
+       prepare_pool_entry (const_name_index, JV_CONSTANT_Utf8, false);
+      }
+      break;
+    case 'c':
+      {
+       int index = read2u();
+       check_tag (index, JV_CONSTANT_Utf8);
+       prepare_pool_entry (index, JV_CONSTANT_Utf8);
+      }
+      break;
+    case '@':
+      handleAnnotation();
+      break;
+    case '[':
+      {
+       int n_array_elts = read2u ();
+       for (int i = 0; i < n_array_elts; ++i)
+         handleAnnotationElement();
+      }
+      break;
+    default:
+      throw_class_format_error ("invalid annotation element");
+    }
+}
+
+void
+_Jv_ClassReader::handleAnnotation()
+{
+  int type_index = read2u();
+  check_tag (type_index, JV_CONSTANT_Utf8);
+  prepare_pool_entry (type_index, JV_CONSTANT_Utf8);
+
+  int npairs = read2u();
+  for (int i = 0; i < npairs; ++i)
+    {
+      int name_index = read2u();
+      check_tag (name_index, JV_CONSTANT_Utf8);
+      prepare_pool_entry (name_index, JV_CONSTANT_Utf8, false);
+      handleAnnotationElement();
+    }
+}
+
+void
+_Jv_ClassReader::handleAnnotations()
+{
+  int num = read2u();
+  while (num--)
+    handleAnnotation();
+}
+
+void
+_Jv_ClassReader::handleMemberAnnotations(jv_attr_type member_type,
+                                        int member_index,
+                                        int len)
+{
+  // We're going to copy the bytes in verbatim.  But first we want to
+  // make sure the attribute is well-formed, and we want to prepare
+  // the constant pool.  So, we save our starting point.
+  int orig_pos = pos;
+
+  handleAnnotations();
+  // FIXME: check that we read all LEN bytes?
+
+  ::java::io::DataOutputStream *stream = get_reflection_stream ();
+  stream->writeByte(member_type);
+  int newLen = len + 1;
+  if (member_type != JV_CLASS_ATTR)
+    newLen += 2;
+  stream->writeInt(newLen);
+  stream->writeByte(JV_ANNOTATIONS_KIND);
+  if (member_type != JV_CLASS_ATTR)
+    stream->writeShort(member_index);
+  // Write the data as-is.
+  stream->write(input_data, input_offset + orig_pos, len);
+}
+
+void
+_Jv_ClassReader::handleAnnotationDefault(int member_index, int len)
+{
+  int orig_pos = pos;
+  handleAnnotationElement();
+
+  ::java::io::DataOutputStream *stream = get_reflection_stream ();
+  stream->writeByte(JV_METHOD_ATTR);
+  stream->writeInt(len + 3);
+  stream->writeByte(JV_ANNOTATION_DEFAULT_KIND);
+  stream->writeShort(member_index);
+  stream->write(input_data, input_offset + orig_pos, len);
+}
+
+void
+_Jv_ClassReader::handleParameterAnnotations(int member_index, int len)
+{
+  int orig_pos = pos;
+
+  int n_params = read1u();
+  for (int i = 0; i < n_params; ++i)
+    handleAnnotations();
+
+  ::java::io::DataOutputStream *stream = get_reflection_stream ();
+  stream->writeByte(JV_METHOD_ATTR);
+  stream->writeInt(len + 3);
+  stream->writeByte(JV_PARAMETER_ANNOTATIONS_KIND);
+  stream->writeShort(member_index);
+  stream->write(input_data, input_offset + orig_pos, len);
 }
 
 void _Jv_ClassReader::read_constpool ()
 {
-  tags    = (unsigned char*) _Jv_AllocBytesChecked (pool_count);
-  offsets = (unsigned int *) _Jv_AllocBytesChecked (sizeof (int)
-                                                   * pool_count) ;
+  tags    = (unsigned char*) _Jv_AllocBytes (pool_count);
+  offsets = (unsigned int *) _Jv_AllocBytes (sizeof (int) * pool_count) ;
 
   /** first, we scan the constant pool, collecting tags and offsets */
   tags[0]   = JV_CONSTANT_Undefined;
@@ -390,32 +717,72 @@ void _Jv_ClassReader::read_fields ()
   int fields_count = read2u ();
   handleFieldsBegin (fields_count);
 
+  // We want to sort the fields so that static fields come first,
+  // followed by instance fields.  We do this before parsing the
+  // fields so that we can have the new indices available when
+  // creating the annotation data structures.
+
+  // Allocate this on the heap in case there are a large number of
+  // fields.
+  int *fieldmap = (int *) _Jv_AllocBytes (fields_count * sizeof (int));
+  int save_pos = pos;
+  int static_count = 0, instance_count = -1;
+  for (int i = 0; i < fields_count; ++i)
+    {
+      using namespace java::lang::reflect;
+
+      int access_flags = read2u ();
+      skip (4);
+      int attributes_count = read2u ();
+
+      if ((access_flags & Modifier::STATIC) != 0) 
+       fieldmap[i] = static_count++;
+      else
+       fieldmap[i] = instance_count--;
+
+      for (int j = 0; j < attributes_count; ++j)
+       {
+         skip (2);
+         int length = read4 ();
+         skip (length);
+       }
+    }
+  pos = save_pos;
+
+  // In the loop above, instance fields are represented by negative
+  // numbers.  Here we rewrite these to be proper offsets.
+  for (int i = 0; i < fields_count; ++i)
+    {
+      if (fieldmap[i] < 0)
+       fieldmap[i] = static_count - 1 - fieldmap[i];
+    }
+  def->static_field_count = static_count;
+
   for (int i = 0; i < fields_count; i++)
     {
       int access_flags     = read2u ();
       int name_index       = read2u ();
       int descriptor_index = read2u ();
       int attributes_count = read2u ();
-      
+
       check_tag (name_index, JV_CONSTANT_Utf8);
       prepare_pool_entry (name_index, JV_CONSTANT_Utf8);
 
       check_tag (descriptor_index, JV_CONSTANT_Utf8);
       prepare_pool_entry (descriptor_index, JV_CONSTANT_Utf8);
-      
-      handleField (i, access_flags, name_index, descriptor_index);
-      
+
+      handleField (i, access_flags, name_index, descriptor_index, fieldmap);
+
+      bool found_value = false;
       for (int j = 0; j < attributes_count; j++)
        {
-         read_one_field_attribute (i);
+         read_one_field_attribute (fieldmap[i], &found_value);
        }
     }
-
-  handleFieldsEnd ();
 }
 
 bool
-_Jv_ClassReader::is_attribute_name (int index, char *name)
+_Jv_ClassReader::is_attribute_name (int index, const char *name)
 {
   check_tag (index, JV_CONSTANT_Utf8);
   int len = get2u (bytes+offsets[index]);
@@ -425,7 +792,20 @@ _Jv_ClassReader::is_attribute_name (int index, char *name)
     return !memcmp (bytes+offsets[index]+2, name, len);
 }
 
-void _Jv_ClassReader::read_one_field_attribute (int field_index)
+// Get a UTF8 value from the constant pool and turn it into a garbage
+// collected char array.
+int _Jv_ClassReader::pool_Utf8_to_char_arr (int index, char** entry)
+{
+  check_tag (index, JV_CONSTANT_Utf8);
+  int len = get2u (bytes + offsets[index]);
+  *entry = reinterpret_cast<char *> (_Jv_AllocBytes (len + 1));
+  (*entry)[len] = '\0';
+  memcpy (*entry, bytes + offsets[index] + 2, len);
+  return len + 1;
+}
+
+void _Jv_ClassReader::read_one_field_attribute (int field_index,
+                                               bool *found_value)
 {
   int name = read2u ();
   int length = read4 ();
@@ -441,22 +821,23 @@ void _Jv_ClassReader::read_one_field_attribute (int field_index)
              || tags[cv] == JV_CONSTANT_Long
              || tags[cv] == JV_CONSTANT_Double
              || tags[cv] == JV_CONSTANT_String))
-         {
-           handleConstantValueAttribute (field_index, cv);
-         }
-       else
-         {
-           throw_class_format_error ("erroneous ConstantValue attribute");
-         }
-
-       if (length != 2) 
+       {
+         handleConstantValueAttribute (field_index, cv, found_value);
+       }
+      else
+       {
          throw_class_format_error ("erroneous ConstantValue attribute");
-      }
+       }
 
-    else
-      {
-       skip (length);
-      }
+      if (length != 2) 
+       throw_class_format_error ("erroneous ConstantValue attribute");
+    }
+  else if (is_attribute_name (name, "Signature"))
+    handleGenericSignature(JV_FIELD_ATTR, field_index, length);
+  else if (is_attribute_name (name, "RuntimeVisibleAnnotations"))
+    handleMemberAnnotations(JV_FIELD_ATTR, field_index, length);
+  else
+    skip (length);
 }
 
 void _Jv_ClassReader::read_methods ()
@@ -473,14 +854,14 @@ void _Jv_ClassReader::read_methods ()
       int attributes_count = read2u ();
       
       check_tag (name_index, JV_CONSTANT_Utf8);
-      prepare_pool_entry (descriptor_index, JV_CONSTANT_Utf8);
+      prepare_pool_entry (name_index, JV_CONSTANT_Utf8);
 
-      check_tag (name_index, JV_CONSTANT_Utf8);
+      check_tag (descriptor_index, JV_CONSTANT_Utf8);
       prepare_pool_entry (descriptor_index, JV_CONSTANT_Utf8);
-      
+
       handleMethod (i, access_flags, name_index,
                    descriptor_index);
-      
+
       for (int j = 0; j < attributes_count; j++)
        {
          read_one_method_attribute (i);
@@ -497,10 +878,32 @@ void _Jv_ClassReader::read_one_method_attribute (int method_index)
 
   if (is_attribute_name (name, "Exceptions"))
     {
-      /* we ignore this for now */
-      skip (length);
+      _Jv_Method *method = reinterpret_cast<_Jv_Method *>
+       (&def->methods[method_index]);
+      if (method->throws != NULL)
+       throw_class_format_error ("only one Exceptions attribute allowed per method");
+
+      int num_exceptions = read2u ();
+      _Jv_Utf8Const **exceptions =
+       (_Jv_Utf8Const **) _Jv_AllocBytes ((num_exceptions + 1)
+                                          * sizeof (_Jv_Utf8Const *));
+
+      int out = 0;
+      _Jv_word *pool_data = def->constants.data;
+      for (int i = 0; i < num_exceptions; ++i)
+       {
+         int ndx = read2u ();
+         // JLS 2nd Ed. 4.7.5 requires that the tag not be 0.
+         if (ndx != 0)
+           {
+             check_tag (ndx, JV_CONSTANT_Class);
+             exceptions[out++] = pool_data[ndx].utf8; 
+           }
+       }
+      exceptions[out] = NULL;
+      method->throws = exceptions;
     }
-  
+
   else if (is_attribute_name (name, "Code"))
     {
       int start_off = pos;
@@ -527,7 +930,9 @@ void _Jv_ClassReader::read_one_method_attribute (int method_index)
 
          if (start_pc > end_pc
              || start_pc < 0
-             || end_pc >= code_length
+             // END_PC can be equal to CODE_LENGTH.
+             // See JVM Spec 4.7.4.
+             || end_pc > code_length
              || handler_pc >= code_length)
            throw_class_format_error ("erroneous exception handler info");
 
@@ -556,7 +961,14 @@ void _Jv_ClassReader::read_one_method_attribute (int method_index)
       if ((pos - start_off) != length)
        throw_class_format_error ("code attribute too short");
     }
-
+  else if (is_attribute_name (name, "Signature"))
+    handleGenericSignature(JV_METHOD_ATTR, method_index, length);
+  else if (is_attribute_name (name, "RuntimeVisibleAnnotations"))
+    handleMemberAnnotations(JV_METHOD_ATTR, method_index, length);
+  else if (is_attribute_name (name, "RuntimeVisibleParameterAnnotations"))
+    handleParameterAnnotations(method_index, length);
+  else if (is_attribute_name (name, "AnnotationDefault"))
+    handleAnnotationDefault(method_index, length);
   else
     {
       /* ignore unknown attributes */
@@ -564,26 +976,95 @@ void _Jv_ClassReader::read_one_method_attribute (int method_index)
     }
 }
 
-void _Jv_ClassReader::read_one_code_attribute (int /*method*/
+void _Jv_ClassReader::read_one_code_attribute (int method_index
 {
-  /* ignore for now, ... later we may want to pick up
-     line number information, for debugging purposes;
-     in fact, the whole debugger issue is open!  */
-
-  /* int name = */ read2u ();
+  int name = read2u ();
   int length = read4 ();
-  skip (length);
-
+  if (is_attribute_name (name, "LineNumberTable"))
+    {
+      _Jv_InterpMethod *method = reinterpret_cast<_Jv_InterpMethod *>
+       (def_interp->interpreted_methods[method_index]);
+      if (method->line_table != NULL)
+       throw_class_format_error ("Method already has LineNumberTable");
+
+      int table_len = read2u ();
+      _Jv_LineTableEntry* table
+       = (_Jv_LineTableEntry *) _Jv_AllocBytes (table_len
+                                                * sizeof (_Jv_LineTableEntry));
+      for (int i = 0; i < table_len; i++)
+       {
+        table[i].bytecode_pc = read2u ();
+        table[i].line = read2u ();
+       }
+      method->line_table_len = table_len;
+      method->line_table = table;
+    }
+  else if (is_attribute_name (name, "LocalVariableTable"))
+    {
+      _Jv_InterpMethod *method = reinterpret_cast<_Jv_InterpMethod *>
+                              (def_interp->interpreted_methods[method_index]);
+      if (method->local_var_table != NULL)
+        throw_class_format_error ("Method already has LocalVariableTable");
+       
+      int table_len = read2u ();
+      _Jv_LocalVarTableEntry *table 
+        = reinterpret_cast<_Jv_LocalVarTableEntry *>
+            (_Jv_AllocRawObj (table_len * sizeof (_Jv_LocalVarTableEntry)));
+                               
+      for (int i = 0; i < table_len; i++)
+        {
+          table[i].bytecode_pc = read2u ();
+          table[i].length = read2u ();
+          pool_Utf8_to_char_arr (read2u (), &table[i].name);
+          pool_Utf8_to_char_arr (read2u (), &table[i].descriptor);
+          table[i].slot = read2u ();
+          
+          if (table[i].slot > method->max_locals || table[i].slot < 0)
+            throw_class_format_error ("Malformed Local Variable Table: Invalid Slot");
+        }
+           
+      method->local_var_table_len = table_len;
+      method->local_var_table = table;
+    }
+  else
+    {
+      /* ignore unknown code attributes */
+      skip (length);
+    }
 }
 
 void _Jv_ClassReader::read_one_class_attribute () 
 {
-  /* we also ignore the class attributes, ...
-     some day we'll add inner-classes support. */
-
-  /* int name = */ read2u ();
+  int name = read2u ();
   int length = read4 ();
-  skip (length);
+  if (is_attribute_name (name, "SourceFile"))
+    {
+      int source_index = read2u ();
+      check_tag (source_index, JV_CONSTANT_Utf8);
+      prepare_pool_entry (source_index, JV_CONSTANT_Utf8, false);
+      def_interp->source_file_name = _Jv_NewStringUtf8Const
+       (def->constants.data[source_index].utf8);
+    }
+  else if (is_attribute_name (name, "Signature"))
+    handleGenericSignature(JV_CLASS_ATTR, 0, length);
+  else if (is_attribute_name (name, "EnclosingMethod"))
+    handleEnclosingMethod(length);
+  else if (is_attribute_name (name, "RuntimeVisibleAnnotations"))
+    handleMemberAnnotations(JV_CLASS_ATTR, 0, length);
+  else if (is_attribute_name (name, "InnerClasses"))
+    {
+      ::java::io::DataOutputStream *stream = get_reflection_stream ();
+      stream->writeByte(JV_CLASS_ATTR);
+      stream->writeInt(length + 1);
+      stream->writeByte(JV_INNER_CLASSES_KIND);
+      stream->write(input_data, input_offset + pos, length);
+      skip (length);
+    }
+  else
+    {
+      /* Currently, we ignore most class attributes. */
+     skip (length);
+    }
 }
 
 
@@ -595,11 +1076,10 @@ void _Jv_ClassReader::handleConstantPool ()
 {
   /** now, we actually define the class' constant pool */
 
-  // the pool is scanned explicitly by the collector
-  jbyte *pool_tags = (jbyte*) _Jv_AllocBytesChecked (pool_count);
+  jbyte *pool_tags = (jbyte*) _Jv_AllocBytes (pool_count);
   _Jv_word *pool_data
-    = (_Jv_word*) _Jv_AllocBytesChecked (pool_count * sizeof (_Jv_word));
-  
+    = (_Jv_word*) _Jv_AllocRawObj (pool_count * sizeof (_Jv_word));
+
   def->constants.tags = pool_tags;
   def->constants.data = pool_data;
   def->constants.size = pool_count;
@@ -647,9 +1127,15 @@ void _Jv_ClassReader::handleConstantPool ()
 }
 
 /* this is a recursive procedure, which will prepare pool entries as needed.
-   Which is how we avoid initializing those entries which go unused. */
+   Which is how we avoid initializing those entries which go unused. 
+   
+   REWRITE is true iff this pool entry is the Utf8 representation of a
+   class name or a signature.
+*/
+
 void
-_Jv_ClassReader::prepare_pool_entry (int index, unsigned char this_tag)
+_Jv_ClassReader::prepare_pool_entry (int index, unsigned char this_tag,
+                                    bool rewrite)
 {
   /* these two, pool_data and pool_tags, point into the class
      structure we are currently defining */
@@ -670,25 +1156,29 @@ _Jv_ClassReader::prepare_pool_entry (int index, unsigned char this_tag)
     {
     case JV_CONSTANT_Utf8: 
       {
-       // If we came here, it is because some other tag needs this
-       // utf8-entry for type information!  Thus, we translate /'s to .'s in
-       // order to accomondate gcj's internal representation.
-
        int len = get2u (this_data);
-       char *buffer = (char*) __builtin_alloca (len);
        char *s = ((char*) this_data)+2;
+       pool_tags[index] = JV_CONSTANT_Utf8;
 
-       /* FIXME: avoid using a buffer here */
+       if (! rewrite)
+         {
+           pool_data[index].utf8 = _Jv_makeUtf8Const (s, len);
+           break;
+         }
+
+       // If REWRITE is set, it is because some other tag needs this
+       // utf8-entry for type information: it is a class or a
+       // signature.  Thus, we translate /'s to .'s in order to
+       // accomondate gcj's internal representation.
+       char *buffer = (char*) __builtin_alloca (len);
        for (int i = 0; i < len; i++)
          {
            if (s[i] == '/')
              buffer[i] = '.';
            else
-             buffer[i] = (char) s[i];
+             buffer[i] = s[i];
          }
-       
        pool_data[index].utf8 = _Jv_makeUtf8Const (buffer, len);
-       pool_tags[index] = JV_CONSTANT_Utf8;
       }
       break;
            
@@ -699,7 +1189,7 @@ _Jv_ClassReader::prepare_pool_entry (int index, unsigned char this_tag)
        prepare_pool_entry (utf_index, JV_CONSTANT_Utf8);
 
        if (verify)
-         _Jv_VerifyClassName (pool_data[utf_index].utf8);
+         verify_classname (pool_data[utf_index].utf8);
                
        pool_data[index].utf8 = pool_data[utf_index].utf8;
        pool_tags[index] = JV_CONSTANT_Class;
@@ -731,9 +1221,9 @@ _Jv_ClassReader::prepare_pool_entry (int index, unsigned char this_tag)
                           name_index, type_index);
 
          if (this_tag == JV_CONSTANT_Fieldref)
-           _Jv_VerifyFieldSignature (pool_data[type_index].utf8);
+           verify_field_signature (pool_data[type_index].utf8);
          else
-           _Jv_VerifyMethodSignature (pool_data[type_index].utf8);
+           verify_method_signature (pool_data[type_index].utf8);
 
          _Jv_Utf8Const* name = pool_data[name_index].utf8;
 
@@ -742,7 +1232,7 @@ _Jv_ClassReader::prepare_pool_entry (int index, unsigned char this_tag)
                  || _Jv_equalUtf8Consts (name, init_name)))
            /* ignore */;
          else
-           _Jv_VerifyIdentifier (pool_data[name_index].utf8);
+           verify_identifier (pool_data[name_index].utf8);
        }
            
        _Jv_storeIndexes (&pool_data[index], class_index, nat_index);
@@ -756,8 +1246,7 @@ _Jv_ClassReader::prepare_pool_entry (int index, unsigned char this_tag)
        _Jv_ushort type_index = get2u (this_data+2);
 
        check_tag (name_index, JV_CONSTANT_Utf8);
-       prepare_pool_entry (name_index, JV_CONSTANT_Utf8);          
-
+       prepare_pool_entry (name_index, JV_CONSTANT_Utf8, false);
        check_tag (type_index, JV_CONSTANT_Utf8);
        prepare_pool_entry (type_index, JV_CONSTANT_Utf8);
 
@@ -768,7 +1257,7 @@ _Jv_ClassReader::prepare_pool_entry (int index, unsigned char this_tag)
            
     case JV_CONSTANT_Float:
       {
-       jfloat f = int_bits_to_float ((jint) get4 (this_data));
+       jfloat f = java::lang::Float::intBitsToFloat ((jint) get4 (this_data));
        _Jv_storeFloat (&pool_data[index], f);
        pool_tags[index] = JV_CONSTANT_Float;
       }
@@ -784,7 +1273,8 @@ _Jv_ClassReader::prepare_pool_entry (int index, unsigned char this_tag)
            
     case JV_CONSTANT_Double:
       {
-       jdouble d = long_bits_to_double ((jlong) get8 (this_data));
+       jdouble d
+         = java::lang::Double::longBitsToDouble ((jlong) get8 (this_data));
        _Jv_storeDouble (&pool_data[index], d);
        pool_tags[index] = JV_CONSTANT_Double;
       }
@@ -805,8 +1295,7 @@ _Jv_ClassReader::prepare_pool_entry (int index, unsigned char this_tag)
 
 
 void
-_Jv_ClassReader::handleClassBegin
-  (int access_flags, int this_class, int super_class)
+_Jv_ClassReader::handleClassBegin (int access_flags, int this_class, int super_class)
 {
   using namespace java::lang::reflect;
 
@@ -819,7 +1308,7 @@ _Jv_ClassReader::handleClassBegin
   // was ClassLoader.defineClass called with an expected class name?
   if (def->name == 0)
     {
-      jclass orig = _Jv_FindClassInCache (loadedName, def->loader);
+      jclass orig = def->loader->findLoadedClass(loadedName->toString());
 
       if (orig == 0)
        {
@@ -842,82 +1331,85 @@ _Jv_ClassReader::handleClassBegin
       jstring msg = JvNewStringUTF ("loaded class ");
       msg = msg->concat (def->getName ());
       msg = msg->concat (_Jv_NewStringUTF (" was in fact named "));
-      jstring klass_name = _Jv_NewStringUTF (loadedName->data);
+      jstring klass_name = loadedName->toString();
       msg = msg->concat (klass_name);
 
       throw_no_class_def_found_error (msg);
     }
 
-  def->accflags = access_flags;
+  def->accflags = access_flags | java::lang::reflect::Modifier::INTERPRETED;
   pool_data[this_class].clazz = def;
   pool_tags[this_class] = JV_CONSTANT_ResolvedClass;
 
   if (super_class == 0)
     {
-      // interfaces have java.lang.Object as super.
-      if (access_flags & Modifier::INTERFACE)
-       {
-         def->superclass = (jclass)&java::lang::Class::class$;
-       }
-
-      // FIXME: Consider this carefully!  
-      else if (!_Jv_equalUtf8Consts (def->name,
-                                    java::lang::Class::class$.name))
-       {
-         throw_no_class_def_found_error ("loading java.lang.Object");
-       }
+      // Note that this is ok if we are defining java.lang.Object.
+      // But there is no way to have this class be interpreted.
+      throw_class_format_error ("no superclass reference");
     }
 
-  // In the pre-loading state, it can be looked up in the
-  // cache only by this thread!  This allows the super-class
-  // to include references to this class.
-
   def->state = JV_STATE_PRELOADING;
-  _Jv_RegisterClass (def);
+
+  // Register this class with its defining loader as well (despite the
+  // name of the function we're calling), so that super class lookups
+  // work properly.  If there is an error, our caller will unregister
+  // this class from the class loader.  Also, we don't need to hold a
+  // lock here, as our caller has acquired it.
+  _Jv_RegisterInitiatingLoader (def, def->loader);
+
+  // Note that we found a name so that unregistration can happen if
+  // needed.
+  *found_name = def->name;
 
   if (super_class != 0)
     {
-      // load the super class
+      // Load the superclass.
       check_tag (super_class, JV_CONSTANT_Class);
       _Jv_Utf8Const* super_name = pool_data[super_class].utf8; 
 
-      // load the super class using our defining loader
-      jclass the_super = _Jv_FindClass (super_name,
-                                       def->loader);
+      // Load the superclass using our defining loader.
+      jclass the_super = _Jv_FindClass (super_name, def->loader);
 
       // This will establish that we are allowed to be a subclass,
-      // and check for class circularity error
+      // and check for class circularity error.
       checkExtends (def, the_super);
 
-      def->superclass = the_super;
+      // Note: for an interface we will find Object as the
+      // superclass.  We still check it above to ensure class file
+      // validity, but we simply assign `null' to the actual field in
+      // this case.
+      def->superclass = (((access_flags & Modifier::INTERFACE))
+                        ? NULL : the_super);
       pool_data[super_class].clazz = the_super;
       pool_tags[super_class] = JV_CONSTANT_ResolvedClass;
     }
-           
-  // now we've come past the circularity problem, we can 
-  // now say that we're loading...
+
+  // Now we've come past the circularity problem, we can 
+  // now say that we're loading.
 
   def->state = JV_STATE_LOADING;
   def->notifyAll ();
 }
 
-///// implements the checks described in sect. 5.3.5.3
+///// Implements the checks described in sect. 5.3.5.3
 void
 _Jv_ClassReader::checkExtends (jclass sub, jclass super)
 {
   using namespace java::lang::reflect;
 
-  // having an interface or a final class as a superclass is no good
+  _Jv_Linker::wait_for_state (super, JV_STATE_LOADING);
+
+  // Having an interface or a final class as a superclass is no good.
   if ((super->accflags & (Modifier::INTERFACE | Modifier::FINAL)) != 0)
     {
       throw_incompatible_class_change_error (sub->getName ());
     }
 
-  // if the super class is not public, we need to check some more
+  // If the super class is not public, we need to check some more.
   if ((super->accflags & Modifier::PUBLIC) == 0)
     {
-      // With package scope, the classes must have the same
-      // class loader.
+      // With package scope, the classes must have the same class
+      // loader.
       if (   sub->loader != super->loader
          || !_Jv_ClassNameSamePackage (sub->name, super->name))
        {
@@ -925,7 +1417,7 @@ _Jv_ClassReader::checkExtends (jclass sub, jclass super)
        }
     } 
 
-  for (; super != 0; super = super->superclass)
+  for (; super != 0; super = super->getSuperclass ())
     {
       if (super == sub)
        throw_class_circularity_error (sub->getName ());
@@ -936,7 +1428,7 @@ _Jv_ClassReader::checkExtends (jclass sub, jclass super)
 
 void _Jv_ClassReader::handleInterfacesBegin (int count)
 {
-  def->interfaces = (jclass*) _Jv_AllocBytesChecked (count*sizeof (jclass));
+  def->interfaces = (jclass*) _Jv_AllocRawObj (count*sizeof (jclass));
   def->interface_count = count;
 }
 
@@ -1002,57 +1494,63 @@ _Jv_ClassReader::checkImplements (jclass sub, jclass super)
 
 void _Jv_ClassReader::handleFieldsBegin (int count)
 {
-  def->fields = (_Jv_Field*) 
-    _Jv_AllocBytesChecked (count * sizeof (_Jv_Field));
+  def->fields = (_Jv_Field*) _Jv_AllocRawObj (count * sizeof (_Jv_Field));
   def->field_count = count;
-  def->field_initializers = (_Jv_ushort*)
-    _Jv_AllocBytesChecked (count * sizeof (_Jv_ushort));
+  def_interp->field_initializers
+    = (_Jv_ushort*) _Jv_AllocRawObj (count * sizeof (_Jv_ushort));
   for (int i = 0; i < count; i++)
-    def->field_initializers[i] = (_Jv_ushort) 0;
+    def_interp->field_initializers[i] = (_Jv_ushort) 0;
 }
 
 void _Jv_ClassReader::handleField (int field_no,
                                   int flags,
                                   int name,
-                                  int desc)
+                                  int desc,
+                                  int *fieldmap)
 {
   using namespace java::lang::reflect;
 
   _Jv_word *pool_data = def->constants.data;
 
-  _Jv_Field *field = &def->fields[field_no];
+  _Jv_Field *field = &def->fields[fieldmap[field_no]];
   _Jv_Utf8Const *field_name = pool_data[name].utf8;
 
-#ifndef COMPACT_FIELDS
   field->name      = field_name;
-#else
-  field->nameIndex = name;
-#endif
 
-  if (verify)
-    _Jv_VerifyIdentifier (field_name);
+  // Ignore flags we don't know about.  
+  field->flags = flags & (Field::FIELD_MODIFIERS
+                         | Modifier::SYNTHETIC
+                         | Modifier::ENUM);
 
-  // ignore flags we don't know about.  
-  field->flags = flags & Modifier::ALL_FLAGS;
+  _Jv_Utf8Const* sig = pool_data[desc].utf8;
 
   if (verify)
     {
-      if (field->flags & (Modifier::SYNCHRONIZED
-                         | Modifier::NATIVE
-                         | Modifier::INTERFACE
-                         | Modifier::ABSTRACT))
-       throw_class_format_error ("erroneous field access flags");
-      
+      verify_identifier (field_name);
+
+      for (int i = 0; i < field_no; ++i)
+       {
+         if (_Jv_equalUtf8Consts (field_name, def->fields[fieldmap[i]].name)
+             && _Jv_equalUtf8Consts (sig,
+                                     // We know the other fields are
+                                     // unresolved.
+                                     (_Jv_Utf8Const *) def->fields[i].type))
+           throw_class_format_error ("duplicate field name");
+       }
+
+      // At most one of PUBLIC, PRIVATE, or PROTECTED is allowed.
       if (1 < ( ((field->flags & Modifier::PUBLIC) ? 1 : 0)
                +((field->flags & Modifier::PRIVATE) ? 1 : 0)
                +((field->flags & Modifier::PROTECTED) ? 1 : 0)))
        throw_class_format_error ("erroneous field access flags");
-    }
 
-  _Jv_Utf8Const* sig = pool_data[desc].utf8;
+      // FIXME: JVM spec S4.5: Verify ACC_FINAL and ACC_VOLATILE are not 
+      // both set. Verify modifiers for interface fields.
+      
+    }
 
   if (verify)
-    _Jv_VerifyFieldSignature (sig);
+    verify_field_signature (sig);
 
   // field->type is really a jclass, but while it is still
   // unresolved we keep an _Jv_Utf8Const* instead.
@@ -1063,7 +1561,8 @@ void _Jv_ClassReader::handleField (int field_no,
 
 
 void _Jv_ClassReader::handleConstantValueAttribute (int field_index, 
-                                                   int value)
+                                                   int value,
+                                                   bool *found_value)
 {
   using namespace java::lang::reflect;
 
@@ -1078,11 +1577,11 @@ void _Jv_ClassReader::handleConstantValueAttribute (int field_index,
     }
 
   // do not allow multiple constant fields!
-  if (field->flags & _Jv_FIELD_CONSTANT_VALUE)
+  if (*found_value)
     throw_class_format_error ("field has multiple ConstantValue attributes");
 
-  field->flags |= _Jv_FIELD_CONSTANT_VALUE;
-  def->field_initializers[field_index] = value;
+  *found_value = true;
+  def_interp->field_initializers[field_index] = value;
 
   /* type check the initializer */
   
@@ -1092,65 +1591,20 @@ void _Jv_ClassReader::handleConstantValueAttribute (int field_index,
   /* FIXME: do the rest */
 }
 
-void _Jv_ClassReader::handleFieldsEnd ()
-{
-  using namespace java::lang::reflect;
-
-  // We need to reorganize the fields so that the static ones are first,
-  // to conform to GCJ class layout.
-
-  int low            = 0;
-  int high           = def->field_count-1;
-  _Jv_Field  *fields = def->fields;
-  _Jv_ushort *inits  = def->field_initializers;
-
-  // this is kind of a raw version of quicksort.
-  while (low < high)
-    {
-      // go forward on low, while it's a static
-      while (low < high && (fields[low].flags & Modifier::STATIC) != 0)
-       low++;
-      
-      // go backwards on high, while it's a non-static
-      while (low < high && (fields[high].flags & Modifier::STATIC) == 0)
-       high--;
-
-      if (low==high)
-       break;
-
-      _Jv_Field  tmp  = fields[low];
-      _Jv_ushort itmp = inits[low];
-         
-      fields[low] = fields[high];
-      inits[low]  = inits[high];
-         
-      fields[high] = tmp;
-      inits[high]  = itmp;
-         
-      high -= 1;
-      low  += 1;
-    }
-  
-  if ((fields[low].flags & Modifier::STATIC) != 0) 
-    low += 1;
-
-  def->static_field_count = low;
-}
-
-
-
 void
 _Jv_ClassReader::handleMethodsBegin (int count)
 {
-  def->methods = (_Jv_Method*)
-    _Jv_AllocBytesChecked (sizeof (_Jv_Method)*count);
+  def->methods = (_Jv_Method *) _Jv_AllocRawObj (sizeof (_Jv_Method) * count);
 
-  def->interpreted_methods
-    = (_Jv_MethodBase **) _Jv_AllocBytesChecked (sizeof (_Jv_MethodBase *)
-                                                * count);
+  def_interp->interpreted_methods
+    = (_Jv_MethodBase **) _Jv_AllocRawObj (sizeof (_Jv_MethodBase *)
+                                          * count);
 
   for (int i = 0; i < count; i++)
-    def->interpreted_methods[i] = 0;
+    {
+      def_interp->interpreted_methods[i] = 0;
+      def->methods[i].index = (_Jv_ushort) -1;
+    }
 
   def->method_count = count;
 }
@@ -1165,7 +1619,7 @@ void _Jv_ClassReader::handleMethod
   _Jv_Method *method = &def->methods[mth_index];
 
   check_tag (name, JV_CONSTANT_Utf8);
-  prepare_pool_entry (name, JV_CONSTANT_Utf8);
+  prepare_pool_entry (name, JV_CONSTANT_Utf8, false);
   method->name = pool_data[name].utf8;
 
   check_tag (desc, JV_CONSTANT_Utf8);
@@ -1173,10 +1627,14 @@ void _Jv_ClassReader::handleMethod
   method->signature = pool_data[desc].utf8;
 
   // ignore unknown flags
-  method->accflags = accflags & Modifier::ALL_FLAGS;
+  method->accflags = accflags & (Method::METHOD_MODIFIERS
+                                | Modifier::BRIDGE
+                                | Modifier::SYNTHETIC
+                                | Modifier::VARARGS);
 
-  // intialize...
+  // Initialize...
   method->ncode = 0;
+  method->throws = NULL;
   
   if (verify)
     {
@@ -1184,19 +1642,27 @@ void _Jv_ClassReader::handleMethod
          || _Jv_equalUtf8Consts (method->name, init_name))
        /* ignore */;
       else
-       _Jv_VerifyIdentifier (method->name);
+       verify_identifier (method->name);
 
-      _Jv_VerifyMethodSignature (method->signature);
+      verify_method_signature (method->signature);
 
-      if (method->accflags & (Modifier::VOLATILE
-                             | Modifier::TRANSIENT
-                             | Modifier::INTERFACE))
-       throw_class_format_error ("erroneous method access flags");
-      
+      for (int i = 0; i < mth_index; ++i)
+       {
+         if (_Jv_equalUtf8Consts (method->name, def->methods[i].name)
+             && _Jv_equalUtf8Consts (method->signature,
+                                     def->methods[i].signature))
+           throw_class_format_error ("duplicate method");
+       }
+
+      // At most one of PUBLIC, PRIVATE, or PROTECTED is allowed.
       if (1 < ( ((method->accflags & Modifier::PUBLIC) ? 1 : 0)
                +((method->accflags & Modifier::PRIVATE) ? 1 : 0)
                +((method->accflags & Modifier::PROTECTED) ? 1 : 0)))
        throw_class_format_error ("erroneous method access flags");
+
+      // FIXME: JVM spec S4.6: if ABSTRACT modifier is set, verify other 
+      // flags are not set. Verify flags for interface methods.  Verify
+      // modifiers for initializers. 
     }
 }
 
@@ -1206,37 +1672,51 @@ void _Jv_ClassReader::handleCodeAttribute
 {
   int size = _Jv_InterpMethod::size (exc_table_length, code_length);
   _Jv_InterpMethod *method = 
-    (_Jv_InterpMethod*) (_Jv_AllocBytesChecked (size));
+    (_Jv_InterpMethod*) (_Jv_AllocRawObj (size));
 
   method->max_stack      = max_stack;
   method->max_locals     = max_locals;
   method->code_length    = code_length;
   method->exc_count      = exc_table_length;
+  method->is_15          = is_15;
   method->defining_class = def;
   method->self           = &def->methods[method_index];
+  method->prepared       = NULL;
+  method->line_table_len = 0;
+  method->line_table     = NULL;
+#ifdef DIRECT_THREADED
+  method->thread_count   = 0;
+#endif
 
   // grab the byte code!
   memcpy ((void*) method->bytecode (),
          (void*) (bytes+code_start),
          code_length);
-  
-  def->interpreted_methods[method_index] = method;
 
-  /* that's all we do for now */
+  def_interp->interpreted_methods[method_index] = method;
+
+  if ((method->self->accflags & java::lang::reflect::Modifier::STATIC))
+    {
+      // Precompute the ncode field for a static method.  This lets us
+      // call a static method of an interpreted class from precompiled
+      // code without first resolving the class (that will happen
+      // during class initialization instead).
+      method->self->ncode = method->ncode (def);
+    }
 }
 
-void _Jv_ClassReader::handleExceptionTableEntry 
+void _Jv_ClassReader::handleExceptionTableEntry
   (int method_index, int exc_index, 
    int start_pc, int end_pc, int handler_pc, int catch_type)
 {
   _Jv_InterpMethod *method = reinterpret_cast<_Jv_InterpMethod *>
-    (def->interpreted_methods[method_index]);
+    (def_interp->interpreted_methods[method_index]);
   _Jv_InterpException *exc = method->exceptions ();
 
-  exc[exc_index].start_pc     = start_pc;
-  exc[exc_index].end_pc       = end_pc;
-  exc[exc_index].handler_pc   = handler_pc;
-  exc[exc_index].handler_type = catch_type;
+  exc[exc_index].start_pc.i     = start_pc;
+  exc[exc_index].end_pc.i       = end_pc;
+  exc[exc_index].handler_pc.i   = handler_pc;
+  exc[exc_index].handler_type.i = catch_type;
 }
 
 void _Jv_ClassReader::handleMethodsEnd ()
@@ -1248,33 +1728,119 @@ void _Jv_ClassReader::handleMethodsEnd ()
       _Jv_Method *method = &def->methods[i];
       if ((method->accflags & Modifier::NATIVE) != 0)
        {
-         if (def->interpreted_methods[i] != 0)
+         if (def_interp->interpreted_methods[i] != 0)
            throw_class_format_error ("code provided for native method");
          else
            {
              _Jv_JNIMethod *m = (_Jv_JNIMethod *)
-               _Jv_AllocBytesChecked (sizeof (_Jv_JNIMethod));
+               _Jv_AllocRawObj (sizeof (_Jv_JNIMethod));
              m->defining_class = def;
              m->self = method;
              m->function = NULL;
-             def->interpreted_methods[i] = m;
+             def_interp->interpreted_methods[i] = m;
+
+             if ((method->accflags & Modifier::STATIC))
+               {
+                 // Precompute the ncode field for a static method.
+                 // This lets us call a static method of an
+                 // interpreted class from precompiled code without
+                 // first resolving the class (that will happen
+                 // during class initialization instead).
+                 method->ncode = m->ncode (def);
+               }
            }
        }
       else if ((method->accflags & Modifier::ABSTRACT) != 0)
        {
-         if (def->interpreted_methods[i] != 0)
+         if (def_interp->interpreted_methods[i] != 0)
            throw_class_format_error ("code provided for abstract method");
+         method->ncode = (void *) &_Jv_ThrowAbstractMethodError;
        }
       else
        {
-         if (def->interpreted_methods[i] == 0)
+         if (def_interp->interpreted_methods[i] == 0)
            throw_class_format_error ("method with no code");
        }
     }
+}
 
+void _Jv_ClassReader::throw_class_format_error (const char *msg)
+{
+  jstring str;
+  if (def->name != NULL)
+    {
+      jsize mlen = strlen (msg);
+      unsigned char* data = (unsigned char*) def->name->chars();
+      int ulen = def->name->len();
+      unsigned char* limit = data + ulen;
+      jsize nlen = _Jv_strLengthUtf8 ((char *) data, ulen);
+      jsize len = nlen + mlen + 3;
+      str = JvAllocString(len);
+      jchar *chrs = JvGetStringChars(str);
+      while (data < limit)
+       *chrs++ = UTF8_GET(data, limit);
+      *chrs++ = ' ';
+      *chrs++ = '(';
+      for (;;)
+       {
+         char c = *msg++;
+         if (c == 0)
+           break;
+         *chrs++ = c & 0xFFFF;
+       }
+      *chrs++ = ')';
+    }
+  else
+    str = JvNewStringLatin1 (msg);
+  ::throw_class_format_error (str);
 }
+\f
+/** Here we define the exceptions that can be thrown */
+
+static void
+throw_no_class_def_found_error (jstring msg)
+{
+  throw (msg
+        ? new java::lang::NoClassDefFoundError (msg)
+        : new java::lang::NoClassDefFoundError);
+}
+
+static void
+throw_no_class_def_found_error (const char *msg)
+{
+  throw_no_class_def_found_error (JvNewStringLatin1 (msg));
+}
+
+static void
+throw_class_format_error (jstring msg)
+{
+  throw (msg
+        ? new java::lang::ClassFormatError (msg)
+        : new java::lang::ClassFormatError);
+}
+
+static void
+throw_internal_error (const char *msg)
+{
+  throw new java::lang::InternalError (JvNewStringLatin1 (msg));
+}
+
+static void
+throw_incompatible_class_change_error (jstring msg)
+{
+  throw new java::lang::IncompatibleClassChangeError (msg);
+}
+
+static void
+throw_class_circularity_error (jstring msg)
+{
+  throw new java::lang::ClassCircularityError (msg);
+}
+
+#endif /* INTERPRETER */
 
 \f
+
 /** This section takes care of verifying integrity of identifiers,
     signatures, field ddescriptors, and class names */
 
@@ -1283,7 +1849,7 @@ void _Jv_ClassReader::handleMethodsEnd ()
      int xxch = UTF8_GET(PTR,LIMIT); \
      PTR = xxkeep; xxch; })
 
-/* verify one element of a type descriptor or signature */
+/* Verify one element of a type descriptor or signature.  */
 static unsigned char*
 _Jv_VerifyOne (unsigned char* ptr, unsigned char* limit, bool void_ok)
 {
@@ -1295,7 +1861,8 @@ _Jv_VerifyOne (unsigned char* ptr, unsigned char* limit, bool void_ok)
   switch (ch)
     {
     case 'V':
-      if (! void_ok) return 0;
+      if (! void_ok)
+       return 0;
 
     case 'S': case 'B': case 'I': case 'J':
     case 'Z': case 'C': case 'F': case 'D': 
@@ -1304,78 +1871,69 @@ _Jv_VerifyOne (unsigned char* ptr, unsigned char* limit, bool void_ok)
     case 'L':
       {
        unsigned char *start = ptr, *end;
-       do {
-         if (ptr > limit)
-           return 0;
-               
-         end = ptr;
-               
-         if ((ch = UTF8_GET (ptr, limit)) == -1)
-           return 0;
-               
-       } while (ch != ';');
-       _Jv_VerifyClassName (start, (unsigned short) (end-start));
+       do
+         {
+           if (ptr > limit)
+             return 0;
+
+           end = ptr;
+
+           if ((ch = UTF8_GET (ptr, limit)) == -1)
+             return 0;
+
+         }
+       while (ch != ';');
+       if (! _Jv_VerifyClassName (start, (unsigned short) (end-start)))
+         return 0;
       }
       break;
 
     case '[':
       return _Jv_VerifyOne (ptr, limit, false);
       break;
-       
+
     default:
       return 0;
     }
 
   return ptr;
-    
 }
 
-
-/** verification and loading procedures **/
-
-void
+/* Verification and loading procedures.  */
+bool
 _Jv_VerifyFieldSignature (_Jv_Utf8Const*sig)
 {
-  unsigned char* ptr = (unsigned char*) sig->data;
-  unsigned char* limit = ptr + sig->length;
+  unsigned char* ptr = (unsigned char*) sig->chars();
+  unsigned char* limit = ptr + sig->len();
 
   ptr = _Jv_VerifyOne (ptr, limit, false);
 
-  if (ptr != limit)
-    throw_class_format_error ("erroneous type descriptor");
+  return ptr == limit;
 }
 
-void
+bool
 _Jv_VerifyMethodSignature (_Jv_Utf8Const*sig)
 {
-  unsigned char* ptr = (unsigned char*) sig->data;
-  unsigned char* limit = ptr + sig->length;
-
-  if (ptr == limit)
-    throw_class_format_error ("erroneous type descriptor");
+  unsigned char* ptr = (unsigned char*) sig->chars();
+  unsigned char* limit = ptr + sig->len();
 
-  if (UTF8_GET(ptr,limit) != '(')
-    throw_class_format_error ("erroneous type descriptor");
+  if (ptr == limit || UTF8_GET(ptr,limit) != '(')
+    return false;
 
   while (ptr && UTF8_PEEK (ptr, limit) != ')')
     ptr = _Jv_VerifyOne (ptr, limit, false);
-    
-  if (UTF8_GET (ptr, limit) != ')')
-    throw_class_format_error ("erroneous type descriptor");
+
+  if (! ptr || UTF8_GET (ptr, limit) != ')')
+    return false;
 
   // get the return type
   ptr = _Jv_VerifyOne (ptr, limit, true);
 
-  if (ptr != limit)
-    throw_class_format_error ("erroneous type descriptor");
-
-  return;
-
+  return ptr == limit;
 }
 
-/* we try to avoid calling the Character methods all the time, 
-   in fact, they will only be called for non-standard things */
-
+/* We try to avoid calling the Character methods all the time, in
+   fact, they will only be called for non-standard things. */
 static __inline__ int 
 is_identifier_start (int c)
 {
@@ -1388,7 +1946,7 @@ is_identifier_start (int c)
   if (ch == 0x5FU)                     /* _ */
     return 1;
 
-  return character->isJavaIdentifierStart ((jchar) ch);
+  return java::lang::Character::isJavaIdentifierStart ((jchar) ch);
 }
 
 static __inline__ int 
@@ -1405,30 +1963,30 @@ is_identifier_part (int c)
   if (ch == 0x5FU || ch == 0x24U)       /* _ $ */
     return 1;
 
-  return character->isJavaIdentifierStart ((jchar) ch);
+  return java::lang::Character::isJavaIdentifierStart ((jchar) ch);
 }
 
-void 
+bool
 _Jv_VerifyIdentifier (_Jv_Utf8Const* name)
 {
-  unsigned char *ptr   = (unsigned char*) name->data;
-  unsigned char *limit = ptr + name->length;
+  unsigned char *ptr   = (unsigned char*) name->chars();
+  unsigned char *limit = (unsigned char*) name->limit();
   int ch;
 
   if ((ch = UTF8_GET (ptr, limit))==-1
       || ! is_identifier_start (ch))
-    throw_class_format_error ("erroneous identifier");
+    return false;
 
   while (ptr != limit)
     {
       if ((ch = UTF8_GET (ptr, limit))==-1
          || ! is_identifier_part (ch))
-       throw_class_format_error ("erroneous identifier");
+       return false;
     }
+  return true;
 }
 
-
-void
+bool
 _Jv_VerifyClassName (unsigned char* ptr, _Jv_ushort length)
 {
   unsigned char *limit = ptr+length;
@@ -1436,48 +1994,47 @@ _Jv_VerifyClassName (unsigned char* ptr, _Jv_ushort length)
 
   if ('[' == UTF8_PEEK (ptr, limit))
     {
-      if (! _Jv_VerifyOne (++ptr, limit, false))
-        throw_class_format_error ("erroneous class name");
+      unsigned char *end = _Jv_VerifyOne (++ptr, limit, false);
+      // _Jv_VerifyOne must leave us looking at the terminating nul
+      // byte.
+      if (! end || *end)
+       return false;
       else
-        return;
+        return true;
     }
 
  next_level:
-  do {
+  for (;;) {
     if ((ch = UTF8_GET (ptr, limit))==-1)
-      throw_class_format_error ("erroneous class name");
+      return false;
     if (! is_identifier_start (ch))
-      throw_class_format_error ("erroneous class name");
-    do {
+      return false;
+    for (;;) {
       if (ptr == limit)
-       return;
+       return true;
       else if ((ch = UTF8_GET (ptr, limit))==-1)
-       throw_class_format_error ("erroneous class name");
+       return false;
       else if (ch == '.')
        goto next_level;
       else if (! is_identifier_part (ch))
-       throw_class_format_error ("erroneous class name");
-    } while (true);
-  } while (true);
-
+       return false;
+    }
+  }
 }
 
-void
+bool
 _Jv_VerifyClassName (_Jv_Utf8Const *name)
 {
-    _Jv_VerifyClassName ((unsigned char*)&name->data[0],
-                        (_Jv_ushort) name->length);
+  return _Jv_VerifyClassName ((unsigned char*)name->chars(), name->len());
 }
 
-
-/** returns true, if name1 and name2 represents classes in the same
-    package. */
-    
+/* Returns true, if NAME1 and NAME2 represent classes in the same
+   package.  Neither NAME2 nor NAME2 may name an array type.  */
 bool
 _Jv_ClassNameSamePackage (_Jv_Utf8Const *name1, _Jv_Utf8Const *name2)
 {
-  unsigned char* ptr1 = (unsigned char*) name1->data;
-  unsigned char* limit1 = ptr1 + name1->length;
+  unsigned char* ptr1 = (unsigned char*) name1->chars();
+  unsigned char* limit1 = (unsigned char*) name1->limit();
 
   unsigned char* last1 = ptr1;
 
@@ -1487,26 +2044,25 @@ _Jv_ClassNameSamePackage (_Jv_Utf8Const *name1, _Jv_Utf8Const *name2)
 
     if (ch1 == '.')
       last1 = ptr1;
-       
+
     else if (ch1 == -1)
       return false;
   }
 
-  // now the length of name1's package name is len
-  int len = last1 - (unsigned char*) name1->data;
+  // Now the length of NAME1's package name is LEN.
+  int len = last1 - (unsigned char*) name1->chars();
 
-  // if this is longer than name2, then we're off
-  if (len > name2->length)
+  // If this is longer than NAME2, then we're off.
+  if (len > name2->len())
     return false;
 
-  // then compare the first len bytes for equality
-  if (memcmp ((void*) name1->data, (void*) name2->data, len) == 0)
+  // Then compare the first len bytes for equality.
+  if (memcmp ((void*) name1->chars(), (void*) name2->chars(), len) == 0)
     {
-      // check that there are no .'s after position len in name2
+      // Check that there are no .'s after position LEN in NAME2.
 
-      unsigned char* ptr2 = (unsigned char*) name2->data + len;
-      unsigned char* limit2 =
-       (unsigned char*) name2->data + name2->length;
+      unsigned char* ptr2 = (unsigned char*) name2->chars() + len;
+      unsigned char* limit2 = (unsigned char*) name2->limit();
 
       while (ptr2 < limit2)
        {
@@ -1518,67 +2074,3 @@ _Jv_ClassNameSamePackage (_Jv_Utf8Const *name1, _Jv_Utf8Const *name2)
     }
   return false;
 }
-
-
-\f
-/** Here we define the exceptions that can be thrown */
-
-static void
-throw_no_class_def_found_error (jstring msg)
-{
-  if (msg == 0)
-    JvThrow (new java::lang::NoClassDefFoundError);
-  else
-    JvThrow (new java::lang::NoClassDefFoundError (msg));
-}
-
-static void
-throw_no_class_def_found_error (char *msg)
-{
-  throw_no_class_def_found_error (JvNewStringLatin1 (msg));
-}
-
-static void
-throw_class_format_error (jstring msg)
-{
-  if (msg == 0)
-    JvThrow (new java::lang::ClassFormatError);
-  else
-    JvThrow (new java::lang::ClassFormatError (msg));
-}
-
-static void
-throw_class_format_error (char *msg)
-{
-  throw_class_format_error (JvNewStringLatin1 (msg));
-}
-
-static void
-throw_internal_error (char *msg)
-{
-  JvThrow 
-    (new java::lang::InternalError (JvNewStringLatin1 (msg)));
-}
-
-static jfloat int_bits_to_float (jint value)
-{
-  return java::lang::Float::intBitsToFloat (value);
-}
-
-static jdouble long_bits_to_double (jlong value)
-{
-  return java::lang::Double::longBitsToDouble (value);
-}
-
-static void throw_incompatible_class_change_error (jstring msg)
-{
-  JvThrow (new java::lang::IncompatibleClassChangeError (msg));
-}
-
-static void throw_class_circularity_error (jstring msg)
-{
-  JvThrow (new java::lang::ClassCircularityError (msg));
-}
-
-#endif /* INTERPRETER */
-