OSDN Git Service

2004-03-11 Michael Koch <konqueror@gmx.de>
[pf3gnuchains/gcc-fork.git] / libjava / defineclass.cc
index 09f8f47..2e8b4d9 100644 (file)
@@ -1,6 +1,6 @@
 // defineclass.cc - defining a class from .class format.
 
-/* Copyright (C) 1999  Cygnus Solutions
+/* Copyright (C) 1999, 2000, 2001, 2002, 2003  Free Software Foundation
 
    This file is part of libgcj.
 
@@ -18,12 +18,13 @@ details.  */
    currently being ignored ("InnerClasses", "LineNumber", etc...).  
 */
 
-#include <java-interp.h>
+#include <config.h>
 
-#ifdef INTERPRETER
+#include <java-interp.h>
 
+#include <stdlib.h>
 #include <java-cpool.h>
-#include <cni.h>
+#include <gcj/cni.h>
 
 #include <java/lang/Class.h>
 #include <java/lang/Float.h>
@@ -34,22 +35,14 @@ 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>
 
-#define ClassClass _CL_Q34java4lang5Class
-extern java::lang::Class ClassClass;
-#define StringClass _CL_Q34java4lang6String
-extern java::lang::Class StringClass;
-#define ClassObject _CL_Q34java4lang6Object
-extern java::lang::Class ClassObject;
-
-// 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)
        __attribute__ ((__noreturn__));
@@ -59,16 +52,11 @@ static void throw_no_class_def_found_error (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
@@ -87,7 +75,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
@@ -194,6 +182,36 @@ struct _Jv_ClassReader {
       throw_class_format_error ("erroneous constant pool tag");
   }
 
+  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");
+  }
+
   _Jv_ClassReader (jclass klass, jbyteArray data, jint offset, jint length)
   {
     if (klass == 0 || length < 0 || offset+length > data->length)
@@ -216,6 +234,7 @@ struct _Jv_ClassReader {
   void read_one_method_attribute (int method);
   void read_one_code_attribute (int method);
   void read_one_field_attribute (int field);
+  void throw_class_format_error (char *msg);
 
   /** check an utf8 entry, without creating a Utf8Const object */
   bool is_attribute_name (int index, char *name);
@@ -246,46 +265,17 @@ struct _Jv_ClassReader {
    * could be implemented in prims.cc (_Jv_makeUtf8Const), since it
    * computes the hash value anyway.
    */
-
-  static const int PUBLIC       = 0x001;
-  static const int PRIVATE      = 0x002;
-  static const int PROTECTED    = 0x004;
-  static const int STATIC       = 0x008;
-  static const int FINAL        = 0x010;
-  static const int SYNCHRONIZED = 0x020;
-  static const int VOLATILE     = 0x040;
-  static const int TRANSIENT    = 0x080;
-  static const int NATIVE       = 0x100;
-  static const int INTERFACE    = 0x200;
-  static const int ABSTRACT     = 0x400;
-  static const int ALL_FLAGS    = 0x7FF; 
-
 };
 
-/* 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 ();
-
 void
 _Jv_DefineClass (jclass klass, jbyteArray data, jint offset, jint length)
 {
-  if (character == 0)
-    prepare_character ();
-
   _Jv_ClassReader reader (klass, data, offset, length);
   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 */
 
@@ -348,8 +338,8 @@ _Jv_ClassReader::parse ()
 
 void _Jv_ClassReader::read_constpool ()
 {
-  tags    = (unsigned char*) _Jv_AllocBytesChecked (pool_count);
-  offsets = (unsigned int *) _Jv_AllocBytesChecked (sizeof (int)
+  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 */
@@ -413,15 +403,15 @@ void _Jv_ClassReader::read_fields ()
       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);
-      
+
       for (int j = 0; j < attributes_count; j++)
        {
          read_one_field_attribute (i);
@@ -494,10 +484,10 @@ void _Jv_ClassReader::read_methods ()
 
       check_tag (name_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);
@@ -514,10 +504,42 @@ 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 ();
+      // We use malloc here because the GC won't scan the method
+      // objects.  FIXME this means a memory leak if we GC a class.
+      // (Currently we never do.)
+      _Jv_Utf8Const **exceptions =
+       (_Jv_Utf8Const **) _Jv_Malloc ((num_exceptions + 1) * sizeof (_Jv_Utf8Const *));
+
+      int out = 0;
+      _Jv_word *pool_data = def->constants.data;
+      for (int i = 0; i < num_exceptions; ++i)
+       {
+         try
+           {
+             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; 
+               }
+           }
+         catch (java::lang::Throwable *exc)
+           {
+             _Jv_Free (exceptions);
+             throw exc;
+           }
+       }
+      exceptions[out] = NULL;
+      method->throws = exceptions;
     }
-  
+
   else if (is_attribute_name (name, "Code"))
     {
       int start_off = pos;
@@ -544,7 +566,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");
 
@@ -613,8 +637,9 @@ 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);
-  void **pool_data = (void**) _Jv_AllocBytesChecked (pool_count * sizeof (void*));
+  jbyte *pool_tags = (jbyte*) _Jv_AllocBytes (pool_count);
+  _Jv_word *pool_data
+    = (_Jv_word*) _Jv_AllocBytes (pool_count * sizeof (_Jv_word));
   
   def->constants.tags = pool_tags;
   def->constants.data = pool_data;
@@ -634,7 +659,7 @@ void _Jv_ClassReader::handleConstantPool ()
          check_tag (utf_index, JV_CONSTANT_Utf8);
          unsigned char *utf_data = bytes + offsets[utf_index];
          int len = get2u (utf_data);
-         pool_data[i] = (void*)_Jv_makeUtf8Const ((char*)(utf_data+2), len);
+         pool_data[i].utf8 = _Jv_makeUtf8Const ((char*)(utf_data+2), len);
          pool_tags[i] = JV_CONSTANT_String;
        }
       else
@@ -671,7 +696,7 @@ _Jv_ClassReader::prepare_pool_entry (int index, unsigned char this_tag)
      structure we are currently defining */
 
   unsigned char *pool_tags = (unsigned char*) def->constants.tags;
-  void         **pool_data = (void**) def->constants.data;
+  _Jv_word      *pool_data = def->constants.data;
 
   /* this entry was already prepared */
   if (pool_tags[index] == this_tag)
@@ -691,7 +716,7 @@ _Jv_ClassReader::prepare_pool_entry (int index, unsigned char this_tag)
        // order to accomondate gcj's internal representation.
 
        int len = get2u (this_data);
-       char *buffer = (char*) alloca (len);
+       char *buffer = (char*) __builtin_alloca (len);
        char *s = ((char*) this_data)+2;
 
        /* FIXME: avoid using a buffer here */
@@ -703,7 +728,7 @@ _Jv_ClassReader::prepare_pool_entry (int index, unsigned char this_tag)
              buffer[i] = (char) s[i];
          }
        
-       pool_data[index] = (void*)_Jv_makeUtf8Const (buffer, len);
+       pool_data[index].utf8 = _Jv_makeUtf8Const (buffer, len);
        pool_tags[index] = JV_CONSTANT_Utf8;
       }
       break;
@@ -715,9 +740,9 @@ _Jv_ClassReader::prepare_pool_entry (int index, unsigned char this_tag)
        prepare_pool_entry (utf_index, JV_CONSTANT_Utf8);
 
        if (verify)
-         _Jv_VerifyClassName ((_Jv_Utf8Const*)pool_data[utf_index]);
+         verify_classname (pool_data[utf_index].utf8);
                
-       pool_data[index] = pool_data[utf_index];
+       pool_data[index].utf8 = pool_data[utf_index].utf8;
        pool_tags[index] = JV_CONSTANT_Class;
       }
       break;
@@ -743,24 +768,22 @@ _Jv_ClassReader::prepare_pool_entry (int index, unsigned char this_tag)
        if (verify)
        {
          _Jv_ushort name_index, type_index;
-         _Jv_loadIndexes ((const void**)&pool_data[nat_index],
+         _Jv_loadIndexes (&pool_data[nat_index],
                           name_index, type_index);
 
          if (this_tag == JV_CONSTANT_Fieldref)
-           _Jv_VerifyFieldSignature
-             ((_Jv_Utf8Const*)pool_data[type_index]);
+           _Jv_VerifyFieldSignature (pool_data[type_index].utf8);
          else
-           _Jv_VerifyMethodSignature
-             ((_Jv_Utf8Const*)pool_data[type_index]);
+           _Jv_VerifyMethodSignature (pool_data[type_index].utf8);
 
-         _Jv_Utf8Const* name = (_Jv_Utf8Const*)pool_data[name_index];
+         _Jv_Utf8Const* name = pool_data[name_index].utf8;
 
          if (this_tag != JV_CONSTANT_Fieldref
              && (   _Jv_equalUtf8Consts (name, clinit_name)
                  || _Jv_equalUtf8Consts (name, init_name)))
            /* ignore */;
          else
-           _Jv_VerifyIdentifier ((_Jv_Utf8Const*)pool_data[name_index]);
+           verify_identifier (pool_data[name_index].utf8);
        }
            
        _Jv_storeIndexes (&pool_data[index], class_index, nat_index);
@@ -786,7 +809,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;
       }
@@ -802,7 +825,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;
       }
@@ -826,11 +850,13 @@ void
 _Jv_ClassReader::handleClassBegin
   (int access_flags, int this_class, int super_class)
 {
+  using namespace java::lang::reflect;
+
   unsigned char *pool_tags = (unsigned char*) def->constants.tags;
-  void         **pool_data = (void**) def->constants.data;
+  _Jv_word      *pool_data = def->constants.data;
 
   check_tag (this_class, JV_CONSTANT_Class);
-  _Jv_Utf8Const *loadedName = (_Jv_Utf8Const*)pool_data[this_class];
+  _Jv_Utf8Const *loadedName = pool_data[this_class].utf8;
 
   // was ClassLoader.defineClass called with an expected class name?
   if (def->name == 0)
@@ -864,23 +890,15 @@ _Jv_ClassReader::handleClassBegin
       throw_no_class_def_found_error (msg);
     }
 
-  def->accflags = access_flags;
-  pool_data[this_class] = (void*)def;
+  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)
+  if (super_class == 0 && ! (access_flags & Modifier::INTERFACE))
     {
-      // interfaces have java.lang.Object as super.
-      if (access_flags & INTERFACE)
-       {
-         def->superclass = (jclass)&ClassObject;
-       }
-
       // FIXME: Consider this carefully!  
-      else if (!_Jv_equalUtf8Consts (def->name, ClassObject.name))
-       {
-         throw_no_class_def_found_error ("loading java.lang.Object");
-       }
+      if (! _Jv_equalUtf8Consts (def->name, java::lang::Object::class$.name))
+       throw_no_class_def_found_error ("loading java.lang.Object");
     }
 
   // In the pre-loading state, it can be looked up in the
@@ -888,30 +906,38 @@ _Jv_ClassReader::handleClassBegin
   // to include references to this class.
 
   def->state = JV_STATE_PRELOADING;
-  _Jv_RegisterClass (def);
+
+  {
+    JvSynchronize sync (&java::lang::Class::class$);
+    _Jv_RegisterClass (def);
+  }
 
   if (super_class != 0)
     {
-      // load the super class
+      // Load the superclass.
       check_tag (super_class, JV_CONSTANT_Class);
-      _Jv_Utf8Const* super_name =
-       (_Jv_Utf8Const*)pool_data[super_class]; 
+      _Jv_Utf8Const* super_name = pool_data[super_class].utf8; 
 
-      // load the super class using our defining 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;
-      pool_data[super_class] = (void*) 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 ();
@@ -921,14 +947,16 @@ _Jv_ClassReader::handleClassBegin
 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
-  if ((super->accflags & (INTERFACE | FINAL)) != 0)
+  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 ((super->accflags & PUBLIC) == 0)
+  if ((super->accflags & Modifier::PUBLIC) == 0)
     {
       // With package scope, the classes must have the same
       // class loader.
@@ -950,25 +978,25 @@ _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_AllocBytes (count*sizeof (jclass));
   def->interface_count = count;
 }
 
 void _Jv_ClassReader::handleInterface (int if_number, int offset)
 {
-  void          ** pool_data = def->constants.data;
+  _Jv_word       * pool_data = def->constants.data;
   unsigned char  * pool_tags = (unsigned char*) def->constants.tags;
 
   jclass the_interface;
 
   if (pool_tags[offset] == JV_CONSTANT_Class)
     {
-      _Jv_Utf8Const* name = (_Jv_Utf8Const*) pool_data[offset];
+      _Jv_Utf8Const* name = pool_data[offset].utf8;
       the_interface =  _Jv_FindClass (name, def->loader);
     }
   else if (pool_tags[offset] == JV_CONSTANT_ResolvedClass)
     {
-      the_interface = (jclass)pool_data[offset];
+      the_interface = pool_data[offset].clazz;
     }
   else
     {
@@ -979,7 +1007,7 @@ void _Jv_ClassReader::handleInterface (int if_number, int offset)
   // allowed to implement that interface.
   checkImplements (def, the_interface);
   
-  pool_data[offset] = (void*)the_interface;
+  pool_data[offset].clazz = the_interface;
   pool_tags[offset] = JV_CONSTANT_ResolvedClass;
   
   def->interfaces[if_number] = the_interface;
@@ -988,15 +1016,17 @@ void _Jv_ClassReader::handleInterface (int if_number, int offset)
 void
 _Jv_ClassReader::checkImplements (jclass sub, jclass super)
 {
+  using namespace java::lang::reflect;
+
   // well, it *must* be an interface
-  if ((super->accflags & INTERFACE) == 0)
+  if ((super->accflags & Modifier::INTERFACE) == 0)
     {
       throw_incompatible_class_change_error (sub->getName ());
     }
 
   // if it has package scope, it must also be defined by the 
   // same loader.
-  if ((super->accflags & PUBLIC) == 0)
+  if ((super->accflags & Modifier::PUBLIC) == 0)
     {
       if (    sub->loader != super->loader
          || !_Jv_ClassNameSamePackage (sub->name, super->name))
@@ -1015,10 +1045,10 @@ _Jv_ClassReader::checkImplements (jclass sub, jclass super)
 void _Jv_ClassReader::handleFieldsBegin (int count)
 {
   def->fields = (_Jv_Field*) 
-    _Jv_AllocBytesChecked (count * sizeof (_Jv_Field));
+    _Jv_AllocBytes (count * sizeof (_Jv_Field));
   def->field_count = count;
   def->field_initializers = (_Jv_ushort*)
-    _Jv_AllocBytesChecked (count * sizeof (_Jv_ushort));
+    _Jv_AllocBytes (count * sizeof (_Jv_ushort));
   for (int i = 0; i < count; i++)
     def->field_initializers[i] = (_Jv_ushort) 0;
 }
@@ -1028,10 +1058,12 @@ void _Jv_ClassReader::handleField (int field_no,
                                   int name,
                                   int desc)
 {
-  void **const pool_data = def->constants.data;
+  using namespace java::lang::reflect;
+
+  _Jv_word *pool_data = def->constants.data;
 
   _Jv_Field *field = &def->fields[field_no];
-  _Jv_Utf8Const *field_name = (_Jv_Utf8Const*) pool_data[name];
+  _Jv_Utf8Const *field_name = pool_data[name].utf8;
 
 #ifndef COMPACT_FIELDS
   field->name      = field_name;
@@ -1039,25 +1071,37 @@ void _Jv_ClassReader::handleField (int field_no,
   field->nameIndex = name;
 #endif
 
-  if (verify)
-    _Jv_VerifyIdentifier (field_name);
+  // Ignore flags we don't know about.  
+  field->flags = flags & Modifier::ALL_FLAGS;
 
-  // ignore flags we don't know about.  
-  field->flags = flags & ALL_FLAGS;
+  _Jv_Utf8Const* sig = pool_data[desc].utf8;
 
   if (verify)
     {
-      if (field->flags & (SYNCHRONIZED|NATIVE|INTERFACE|ABSTRACT))
+      verify_identifier (field_name);
+
+      for (int i = 0; i < field_no; ++i)
+       {
+         if (_Jv_equalUtf8Consts (field_name, def->fields[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");
+       }
+
+      if (field->flags & (Modifier::SYNCHRONIZED
+                         | Modifier::NATIVE
+                         | Modifier::INTERFACE
+                         | Modifier::ABSTRACT))
        throw_class_format_error ("erroneous field access flags");
       
-      if (1 < ( ((field->flags & PUBLIC) ? 1 : 0)
-               +((field->flags & PRIVATE) ? 1 : 0)
-               +((field->flags & PROTECTED) ? 1 : 0)))
+      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 = (_Jv_Utf8Const*) pool_data[desc];
-
   if (verify)
     _Jv_VerifyFieldSignature (sig);
 
@@ -1072,9 +1116,13 @@ void _Jv_ClassReader::handleField (int field_no,
 void _Jv_ClassReader::handleConstantValueAttribute (int field_index, 
                                                    int value)
 {
+  using namespace java::lang::reflect;
+
   _Jv_Field *field = &def->fields[field_index];
 
-  if ((field->flags & (STATIC|FINAL|PRIVATE)) == 0)
+  if ((field->flags & (Modifier::STATIC
+                      | Modifier::FINAL
+                      | Modifier::PRIVATE)) == 0)
     {
       // Ignore, as per vmspec #4.7.2
       return;
@@ -1097,6 +1145,8 @@ void _Jv_ClassReader::handleConstantValueAttribute (int field_index,
 
 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.
 
@@ -1109,11 +1159,11 @@ void _Jv_ClassReader::handleFieldsEnd ()
   while (low < high)
     {
       // go forward on low, while it's a static
-      while (low < high && (fields[low].flags & STATIC) != 0)
+      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 & STATIC) == 0)
+      while (low < high && (fields[high].flags & Modifier::STATIC) == 0)
        high--;
 
       if (low==high)
@@ -1132,7 +1182,7 @@ void _Jv_ClassReader::handleFieldsEnd ()
       low  += 1;
     }
   
-  if ((fields[low].flags & STATIC) != 0) 
+  if ((fields[low].flags & Modifier::STATIC) != 0) 
     low += 1;
 
   def->static_field_count = low;
@@ -1140,16 +1190,20 @@ void _Jv_ClassReader::handleFieldsEnd ()
 
 
 
-void _Jv_ClassReader::handleMethodsBegin (int count)
+void
+_Jv_ClassReader::handleMethodsBegin (int count)
 {
-  def->methods = (_Jv_Method*)
-    _Jv_AllocBytesChecked (sizeof (_Jv_Method)*count);
+  def->methods = (_Jv_Method *) _Jv_AllocBytes (sizeof (_Jv_Method) * count);
 
-  def->interpreted_methods = (_Jv_InterpMethod**)
-    _Jv_AllocBytesChecked (sizeof (_Jv_InterpMethod*) * count);
+  def->interpreted_methods
+    = (_Jv_MethodBase **) _Jv_AllocBytes (sizeof (_Jv_MethodBase *)
+                                         * count);
 
   for (int i = 0; i < count; i++)
-    def->interpreted_methods[i] = 0;
+    {
+      def->interpreted_methods[i] = 0;
+      def->methods[i].index = (_Jv_ushort) -1;
+    }
 
   def->method_count = count;
 }
@@ -1158,22 +1212,25 @@ void _Jv_ClassReader::handleMethodsBegin (int count)
 void _Jv_ClassReader::handleMethod 
     (int mth_index, int accflags, int name, int desc)
 { 
-  void **const pool_data = def->constants.data;
+  using namespace java::lang::reflect;
+
+  _Jv_word *pool_data = def->constants.data;
   _Jv_Method *method = &def->methods[mth_index];
 
   check_tag (name, JV_CONSTANT_Utf8);
   prepare_pool_entry (name, JV_CONSTANT_Utf8);
-  method->name = (_Jv_Utf8Const*)pool_data[name];
+  method->name = pool_data[name].utf8;
 
   check_tag (desc, JV_CONSTANT_Utf8);
   prepare_pool_entry (desc, JV_CONSTANT_Utf8);
-  method->signature = (_Jv_Utf8Const*)pool_data[desc];
+  method->signature = pool_data[desc].utf8;
 
   // ignore unknown flags
-  method->accflags = accflags & ALL_FLAGS;
+  method->accflags = accflags & Modifier::ALL_FLAGS;
 
   // intialize...
   method->ncode = 0;
+  method->throws = NULL;
   
   if (verify)
     {
@@ -1181,16 +1238,26 @@ void _Jv_ClassReader::handleMethod
          || _Jv_equalUtf8Consts (method->name, init_name))
        /* ignore */;
       else
-       _Jv_VerifyIdentifier (method->name);
+       verify_identifier (method->name);
 
       _Jv_VerifyMethodSignature (method->signature);
 
-      if (method->accflags & (VOLATILE|TRANSIENT|INTERFACE))
+      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");
+       }
+
+      if (method->accflags & (Modifier::VOLATILE
+                             | Modifier::TRANSIENT
+                             | Modifier::INTERFACE))
        throw_class_format_error ("erroneous method access flags");
       
-      if (1 < ( ((method->accflags & PUBLIC) ? 1 : 0)
-               +((method->accflags & PRIVATE) ? 1 : 0)
-               +((method->accflags & PROTECTED) ? 1 : 0)))
+      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");
     }
 }
@@ -1201,60 +1268,170 @@ 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_AllocBytes (size));
 
+  method->deferred      = NULL;
   method->max_stack      = max_stack;
   method->max_locals     = max_locals;
   method->code_length    = code_length;
   method->exc_count      = exc_table_length;
   method->defining_class = def;
   method->self           = &def->methods[method_index];
+  method->prepared       = NULL;
 
   // 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 */
+  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 ();
+    }
 }
 
-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 = def->interpreted_methods[method_index];
+  _Jv_InterpMethod *method = reinterpret_cast<_Jv_InterpMethod *>
+    (def->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 ()
 {
+  using namespace java::lang::reflect;
+
   for (int i = 0; i < def->method_count; i++)
     {
       _Jv_Method *method = &def->methods[i];
-      if (method->accflags & (NATIVE|ABSTRACT))
+      if ((method->accflags & Modifier::NATIVE) != 0)
+       {
+         if (def->interpreted_methods[i] != 0)
+           throw_class_format_error ("code provided for native method");
+         else
+           {
+             _Jv_JNIMethod *m = (_Jv_JNIMethod *)
+               _Jv_AllocBytes (sizeof (_Jv_JNIMethod));
+             m->defining_class = def;
+             m->self = method;
+             m->function = NULL;
+             def->interpreted_methods[i] = m;
+             m->deferred = NULL;
+
+             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 ();
+               }
+           }
+       }
+      else if ((method->accflags & Modifier::ABSTRACT) != 0)
        {
          if (def->interpreted_methods[i] != 0)
-           throw_class_format_error ("code provided "
-                                     "for abstract or native method");
+           throw_class_format_error ("code provided for abstract method");
        }
       else
        {
          if (def->interpreted_methods[i] == 0)
-           throw_class_format_error ("abstract or native method "
-                                     "with no code");
+           throw_class_format_error ("method with no code");
+       }
+    }
+}
+
+void _Jv_ClassReader::throw_class_format_error (char *msg)
+{
+  jstring str;
+  if (def->name != NULL)
+    {
+      jsize mlen = strlen (msg);
+      unsigned char* data = (unsigned char*) def->name->data;
+      int ulen = def->name->length;
+      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 (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 (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 */
 
@@ -1263,7 +1440,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)
 {
@@ -1275,7 +1452,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': 
@@ -1284,36 +1462,36 @@ _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;
@@ -1321,41 +1499,32 @@ _Jv_VerifyFieldSignature (_Jv_Utf8Const*sig)
 
   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");
-
-  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");
+    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)
 {
@@ -1368,7 +1537,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 
@@ -1385,10 +1554,10 @@ 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;
@@ -1397,54 +1566,62 @@ _Jv_VerifyIdentifier (_Jv_Utf8Const* name)
 
   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;
   int ch;
 
+  if ('[' == UTF8_PEEK (ptr, limit))
+    {
+      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 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->data[0],
+                             (_Jv_ushort) name->length);
 }
 
-
-/** returns true, if name1 and name2 represents classes in the same
-    package. */
-    
+/* Returns true, if NAME1 and NAME2 represent classes in the same
+   package.  */
 bool
 _Jv_ClassNameSamePackage (_Jv_Utf8Const *name1, _Jv_Utf8Const *name2)
 {
@@ -1459,22 +1636,22 @@ _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
+  // Now the length of NAME1's package name is LEN.
   int len = last1 - (unsigned char*) name1->data;
 
-  // if this is longer than name2, then we're off
+  // If this is longer than NAME2, then we're off.
   if (len > name2->length)
     return false;
 
-  // then compare the first len bytes for equality
+  // Then compare the first len bytes for equality.
   if (memcmp ((void*) name1->data, (void*) name2->data, 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 =
@@ -1490,67 +1667,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 */
-