Home | History | Annotate | Download | only in cls
      1 /* Copyright (C) 2003 Vladimir Roubtsov. All rights reserved.
      2  *
      3  * This program and the accompanying materials are made available under
      4  * the terms of the Common Public License v1.0 which accompanies this distribution,
      5  * and is available at http://www.eclipse.org/legal/cpl-v10.html
      6  *
      7  * $Id: ClassDef.java,v 1.1.1.1.2.1 2004/07/16 23:32:30 vlad_r Exp $
      8  */
      9 package com.vladium.jcd.cls;
     10 
     11 import java.io.DataOutputStream;
     12 import java.io.IOException;
     13 import java.security.MessageDigest;
     14 import java.security.NoSuchAlgorithmException;
     15 import java.util.Arrays;
     16 
     17 import com.vladium.jcd.cls.attribute.AttributeElementFactory;
     18 import com.vladium.jcd.cls.attribute.Attribute_info;
     19 import com.vladium.jcd.cls.attribute.CodeAttribute_info;
     20 import com.vladium.jcd.cls.attribute.InnerClassesAttribute_info;
     21 import com.vladium.jcd.cls.constant.CONSTANT_Class_info;
     22 import com.vladium.jcd.cls.constant.CONSTANT_Fieldref_info;
     23 import com.vladium.jcd.cls.constant.CONSTANT_NameAndType_info;
     24 import com.vladium.jcd.cls.constant.CONSTANT_String_info;
     25 import com.vladium.jcd.cls.constant.CONSTANT_Utf8_info;
     26 import com.vladium.jcd.compiler.IClassFormatOutput;
     27 import com.vladium.jcd.lib.Types;
     28 import com.vladium.jcd.lib.UDataOutputStream;
     29 import com.vladium.util.ByteArrayOStream;
     30 
     31 // ----------------------------------------------------------------------------
     32 /**
     33  * This class represents the abstract syntax table (AST) that {@link com.vladium.jcd.parser.ClassDefParser}
     34  * produces from bytecode. Most elements are either settable or extendible.
     35  * This class also implements {@link com.vladium.jcd.compiler.IClassFormatOutput}
     36  * and works with {@link com.vladium.jcd.compiler.ClassWriter} to produce
     37  * bytecode without an external compiler.<P>
     38  *
     39  * MT-safety: this class and all interfaces used by it are not safe for
     40  * access from multiple concurrent threads.
     41  *
     42  * @author (C) 2001, Vlad Roubtsov
     43  */
     44 public
     45 final class ClassDef implements Cloneable, IAccessFlags, IClassFormatOutput
     46 {
     47     // public: ................................................................
     48 
     49 
     50     public ClassDef ()
     51     {
     52         m_version = new int [2];
     53 
     54         m_constants = ElementFactory.newConstantCollection (-1);
     55         m_interfaces = ElementFactory.newInterfaceCollection (-1);
     56         m_fields = ElementFactory.newFieldCollection (-1);
     57         m_methods = ElementFactory.newMethodCollection (-1);
     58         m_attributes = ElementFactory.newAttributeCollection (-1);
     59     }
     60 
     61     // Visitor:
     62 
     63     public void accept (final IClassDefVisitor visitor, final Object ctx)
     64     {
     65         visitor.visit (this, ctx);
     66     }
     67 
     68 
     69     public long getMagic ()
     70     {
     71         return m_magic;
     72     }
     73 
     74     public void setMagic (final long magic)
     75     {
     76         m_magic = magic;
     77     }
     78 
     79 
     80     public int [] getVersion ()
     81     {
     82         return m_version;
     83     }
     84 
     85     public void setVersion (final int [] version)
     86     {
     87         m_version [0] = version [0];
     88         m_version [1] = version [1];
     89     }
     90 
     91     public final void setDeclaredSUID (final long suid)
     92     {
     93         m_declaredSUID = suid;
     94     }
     95 
     96 
     97     public int getThisClassIndex ()
     98     {
     99         return m_this_class_index;
    100     }
    101 
    102     public void setThisClassIndex (final int this_class_index)
    103     {
    104         m_this_class_index = this_class_index;
    105     }
    106 
    107     public CONSTANT_Class_info getThisClass ()
    108     {
    109         return (CONSTANT_Class_info) m_constants.get (m_this_class_index);
    110     }
    111 
    112     public CONSTANT_Class_info getSuperClass ()
    113     {
    114         return (CONSTANT_Class_info) m_constants.get (m_super_class_index);
    115     }
    116 
    117     public String getName ()
    118     {
    119         return getThisClass ().getName (this);
    120     }
    121 
    122 
    123     public int getSuperClassIndex ()
    124     {
    125         return m_super_class_index;
    126     }
    127 
    128     public void setSuperClassIndex (final int super_class_index)
    129     {
    130         m_super_class_index = super_class_index;
    131     }
    132 
    133     // IAccessFlags:
    134 
    135     public final int getAccessFlags ()
    136     {
    137         return m_access_flags;
    138     }
    139 
    140     public final void setAccessFlags (final int flags)
    141     {
    142         m_access_flags = flags;
    143     }
    144 
    145     public boolean isInterface ()
    146     {
    147         return (m_access_flags & ACC_INTERFACE) != 0;
    148     }
    149 
    150     public boolean isSynthetic ()
    151     {
    152         return m_attributes.hasSynthetic ();
    153     }
    154 
    155     public boolean isNested (final int [] nestedAccessFlags)
    156     {
    157         final InnerClassesAttribute_info innerClassesAttribute = m_attributes.getInnerClassesAttribute ();
    158 
    159         if (innerClassesAttribute == null)
    160             return false;
    161         else
    162             return innerClassesAttribute.makesClassNested (m_this_class_index, nestedAccessFlags);
    163     }
    164 
    165     // methods for getting various nested tables:
    166 
    167     public IConstantCollection getConstants ()
    168     {
    169         return m_constants;
    170     }
    171 
    172     public IInterfaceCollection getInterfaces ()
    173     {
    174         return m_interfaces;
    175     }
    176 
    177     public IFieldCollection getFields ()
    178     {
    179         return m_fields;
    180     }
    181 
    182     public IMethodCollection getMethods ()
    183     {
    184         return m_methods;
    185     }
    186 
    187     public IAttributeCollection getAttributes ()
    188     {
    189         return m_attributes;
    190     }
    191 
    192     public int [] getFields (final String name)
    193     {
    194         return m_fields.get (this, name);
    195     }
    196 
    197     public int [] getMethods (final String name)
    198     {
    199         return m_methods.get (this, name);
    200     }
    201 
    202     // Cloneable:
    203 
    204     /**
    205      * Performs a deep copy.
    206      */
    207     public Object clone ()
    208     {
    209         try
    210         {
    211             final ClassDef _clone = (ClassDef) super.clone ();
    212 
    213             // do deep copy:
    214             _clone.m_version = (int []) m_version.clone ();
    215             _clone.m_constants = (IConstantCollection) m_constants.clone ();
    216             _clone.m_interfaces = (IInterfaceCollection) m_interfaces.clone ();
    217             _clone.m_fields = (IFieldCollection) m_fields.clone ();
    218             _clone.m_methods = (IMethodCollection) m_methods.clone ();
    219             _clone.m_attributes = (IAttributeCollection) m_attributes.clone ();
    220 
    221             return _clone;
    222         }
    223         catch (CloneNotSupportedException e)
    224         {
    225             throw new InternalError (e.toString ());
    226         }
    227     }
    228 
    229 
    230     // IClassFormatOutput:
    231 
    232     public void writeInClassFormat (final UDataOutputStream out) throws IOException
    233     {
    234         if (out == null) throw new IllegalArgumentException ("null input: out");
    235 
    236         out.writeU4 (m_magic);
    237 
    238         out.writeU2 (m_version [1]);
    239         out.writeU2 (m_version [0]);
    240 
    241         m_constants.writeInClassFormat (out);
    242 
    243         out.writeU2 (m_access_flags);
    244 
    245         out.writeU2 (m_this_class_index);
    246         out.writeU2 (m_super_class_index);
    247 
    248         m_interfaces.writeInClassFormat (out);
    249         m_fields.writeInClassFormat (out);
    250         m_methods.writeInClassFormat (out);
    251         m_attributes.writeInClassFormat (out);
    252     }
    253 
    254     public final long getDeclaredSUID ()
    255     {
    256         return m_declaredSUID;
    257     }
    258 
    259     /**
    260      * This follows the spec at http://java.sun.com/j2se/1.4.1/docs/guide/serialization/spec/class.doc6.html#4100
    261      * as well as undocumented hacks used by Sun's 1.4.2 J2SDK
    262      */
    263     public final long computeSUID (final boolean skipCLINIT)
    264     {
    265         long result = m_declaredSUID;
    266         if (result != 0L)
    267             return result;
    268         else
    269         {
    270             try
    271             {
    272                 final ByteArrayOStream bout = new ByteArrayOStream (1024); // TODO: reuse these
    273                 final DataOutputStream dout = new DataOutputStream (bout);
    274 
    275                 // (1) The class name written using UTF encoding:
    276 
    277                 dout.writeUTF (Types.vmNameToJavaName (getName ())); // [in Java format]
    278 
    279                 // (2) The class modifiers written as a 32-bit integer:
    280 
    281                 // ACC_STATIC is never written for nested classes/interfaces;
    282                 // however, ACC_SUPER must be ignored:
    283                 {
    284                     // this is tricky: for static/non-static nested classes that
    285                     // were declared protected in the source the usual access flags
    286                     // will have ACC_PUBLIC set; the only way to achieve J2SDK
    287                     // compatibility is to recover the source access flags
    288                     // from the InnerClasses attribute:
    289 
    290                     final int [] nestedAccessFlags = new int [1];
    291 
    292                     final int modifiers = (isNested (nestedAccessFlags)
    293                             ? nestedAccessFlags [0]
    294                             : getAccessFlags ())
    295                         & (ACC_PUBLIC | ACC_FINAL | ACC_INTERFACE | ACC_ABSTRACT);
    296 
    297                     // if/when emma decides to instrument interfaces for <clinit>
    298                     // coverage, compensate for javac bug in which ABSTRACT bit
    299                     // was set for an interface only if the interface declared methods
    300                     // [Sun's J2SDK]:
    301 
    302                     dout.writeInt (modifiers);
    303                 }
    304 
    305                 // not doing another J2SDK compensation for arrays, because
    306                 // we never load/instrument those
    307 
    308                 // (3) The name of each interface sorted by name written using UTF encoding
    309                 {
    310                     final IInterfaceCollection interfaces = getInterfaces ();
    311                     final String [] ifcs = new String [interfaces.size ()];
    312 
    313                     final int iLimit = ifcs.length;
    314                     for (int i = 0; i < iLimit; ++ i)
    315                     {
    316                         // [in Java format]
    317                         ifcs [i] = Types.vmNameToJavaName (((CONSTANT_Class_info) m_constants.get (interfaces.get (i))).getName (this));
    318                     }
    319 
    320                     Arrays.sort (ifcs);
    321                     for (int i = 0; i < iLimit; ++ i)
    322                     {
    323                         dout.writeUTF (ifcs [i]);
    324                     }
    325                 }
    326 
    327                 // (4) For each field of the class sorted by field name (except
    328                 // private static and private transient fields):
    329                 //      a. The name of the field in UTF encoding.
    330                 //      b. The modifiers of the field written as a 32-bit integer.
    331                 //      c. The descriptor of the field in UTF encoding
    332                 {
    333                     final IFieldCollection fields = getFields ();
    334                     final FieldDescriptor [] fds = new FieldDescriptor [fields.size ()];
    335 
    336                     int fcount = 0;
    337                     for (int f = 0, fLimit = fds.length; f < fLimit; ++ f)
    338                     {
    339                         final Field_info field = fields.get (f);
    340                         final int modifiers = field.getAccessFlags ();
    341 
    342                         if (((modifiers & ACC_PRIVATE) == 0) ||
    343                             ((modifiers & (ACC_STATIC | ACC_TRANSIENT)) == 0))
    344                             fds [fcount ++] = new FieldDescriptor (field.getName (this), modifiers, field.getDescriptor (this));
    345                     }
    346 
    347                     if (fcount > 0)
    348                     {
    349                         Arrays.sort (fds, 0, fcount);
    350                         for (int i = 0; i < fcount; ++ i)
    351                         {
    352                             final FieldDescriptor fd = fds [i];
    353 
    354                             dout.writeUTF (fd.m_name);
    355                             dout.writeInt (fd.m_modifiers);
    356                             dout.writeUTF (fd.m_descriptor);
    357                         }
    358                     }
    359                 }
    360 
    361                 // (5) If a class initializer exists, write out the following:
    362                 //      a. The name of the method, <clinit>, in UTF encoding.
    363                 //      b. The modifier of the method, ACC_STATIC, written as a 32-bit integer.
    364                 //      c. The descriptor of the method, ()V, in UTF encoding.
    365                 // (6) For each non-private constructor sorted by method name and signature:
    366                 //      a. The name of the method, <init>, in UTF encoding.
    367                 //      b. The modifiers of the method written as a 32-bit integer.
    368                 //      c. The descriptor of the method in UTF encoding.
    369                 // (7) For each non-private method sorted by method name and signature:
    370                 //      a. The name of the method in UTF encoding.
    371                 //      b. The modifiers of the method written as a 32-bit integer.
    372                 //      c. The descriptor of the method in UTF encoding.
    373 
    374                 // note: although this is not documented, J2SDK code uses '.''s as
    375                 // descriptor separators (this is done for methods only, not for fields)
    376                 {
    377                     final IMethodCollection methods = getMethods ();
    378 
    379                     boolean hasCLINIT = false;
    380                     final ConstructorDescriptor [] cds = new ConstructorDescriptor [methods.size ()];
    381                     final MethodDescriptor [] mds = new MethodDescriptor [cds.length];
    382 
    383                     int ccount = 0, mcount = 0;
    384 
    385                     for (int i = 0, iLimit = cds.length; i < iLimit; ++ i)
    386                     {
    387                         final Method_info method = methods.get (i);
    388 
    389                         final String name = method.getName (this);
    390 
    391                         if (! hasCLINIT && IClassDefConstants.CLINIT_NAME.equals (name))
    392                         {
    393                             hasCLINIT  = true;
    394                             continue;
    395                         }
    396                         else
    397                         {
    398                             final int modifiers = method.getAccessFlags ();
    399                             if ((modifiers & ACC_PRIVATE) == 0)
    400                             {
    401                                 if (IClassDefConstants.INIT_NAME.equals (name))
    402                                     cds [ccount ++] = new ConstructorDescriptor (modifiers, method.getDescriptor (this));
    403                                 else
    404                                     mds [mcount ++] = new MethodDescriptor (name, modifiers, method.getDescriptor (this));
    405                             }
    406                         }
    407                     }
    408 
    409                     if (hasCLINIT && ! skipCLINIT)
    410                     {
    411                         dout.writeUTF (IClassDefConstants.CLINIT_NAME);
    412                         dout.writeInt (ACC_STATIC);
    413                         dout.writeUTF (IClassDefConstants.CLINIT_DESCRIPTOR);
    414                     }
    415 
    416                     if (ccount > 0)
    417                     {
    418                         Arrays.sort (cds, 0, ccount);
    419 
    420                         for (int i = 0; i < ccount; ++ i)
    421                         {
    422                             final ConstructorDescriptor cd = cds [i];
    423 
    424                             dout.writeUTF (IClassDefConstants.INIT_NAME);
    425                             dout.writeInt (cd.m_modifiers);
    426                             dout.writeUTF (cd.m_descriptor.replace ('/', '.'));
    427                         }
    428                     }
    429 
    430                     if (mcount > 0)
    431                     {
    432                         Arrays.sort (mds, 0, mcount);
    433 
    434                         for (int i = 0; i < mcount; ++ i)
    435                         {
    436                             final MethodDescriptor md = mds [i];
    437 
    438                             dout.writeUTF (md.m_name);
    439                             dout.writeInt (md.m_modifiers);
    440                             dout.writeUTF (md.m_descriptor.replace ('/', '.'));
    441                         }
    442                     }
    443                 }
    444 
    445                 dout.flush();
    446 
    447 
    448                 if (DEBUG_SUID)
    449                 {
    450                     byte [] dump = bout.copyByteArray ();
    451                     for (int x = 0; x < dump.length; ++ x)
    452                     {
    453                         System.out.println ("DUMP[" + x + "] = " + dump [x] + "\t" + (char) dump[x]);
    454                     }
    455                 }
    456 
    457                 final MessageDigest md = MessageDigest.getInstance ("SHA");
    458 
    459                 md.update (bout.getByteArray (), 0, bout.size ());
    460                 final byte [] hash = md.digest ();
    461 
    462                 if (DEBUG_SUID)
    463                 {
    464                     for (int x = 0; x < hash.length; ++ x)
    465                     {
    466                         System.out.println ("HASH[" + x + "] = " + hash [x]);
    467                     }
    468                 }
    469 
    470 //                    final int hash0 = hash [0];
    471 //                    final int hash1 = hash [1];
    472 //                    result = ((hash0 >>> 24) & 0xFF) | ((hash0 >>> 16) & 0xFF) << 8 | ((hash0 >>> 8) & 0xFF) << 16 | ((hash0 >>> 0) & 0xFF) << 24 |
    473 //                             ((hash1 >>> 24) & 0xFF) << 32 | ((hash1 >>> 16) & 0xFF) << 40 | ((hash1 >>> 8) & 0xFF) << 48 | ((hash1 >>> 0) & 0xFF) << 56;
    474 
    475                 for (int i = Math.min (hash.length, 8) - 1; i >= 0; -- i)
    476                 {
    477                     result = (result << 8) | (hash [i] & 0xFF);
    478                 }
    479 
    480                 return result;
    481             }
    482             catch (IOException ioe)
    483             {
    484                 throw new Error (ioe.getMessage ());
    485             }
    486             catch (NoSuchAlgorithmException nsae)
    487             {
    488                 throw new SecurityException (nsae.getMessage());
    489             }
    490         }
    491     }
    492 
    493 
    494     public int addCONSTANT_Utf8 (final String value, final boolean keepUnique)
    495     {
    496         if (keepUnique)
    497         {
    498             final int existing = m_constants.findCONSTANT_Utf8 (value);
    499             if (existing > 0)
    500             {
    501                 return existing;
    502             }
    503 
    504             // [else fall through]
    505         }
    506 
    507         return m_constants.add (new CONSTANT_Utf8_info (value));
    508     }
    509 
    510     public int addStringConstant (final String value)
    511     {
    512         final int value_index = addCONSTANT_Utf8 (value, true);
    513 
    514         // TODO: const uniqueness
    515         return m_constants.add (new CONSTANT_String_info (value_index));
    516     }
    517 
    518     public int addNameType (final String name, final String typeDescriptor)
    519     {
    520         final int name_index = addCONSTANT_Utf8 (name, true);
    521         final int descriptor_index = addCONSTANT_Utf8 (typeDescriptor, true);
    522 
    523         return m_constants.add (new CONSTANT_NameAndType_info (name_index, descriptor_index));
    524     }
    525 
    526 
    527     public int addClassref (final String classJVMName)
    528     {
    529         final int name_index = addCONSTANT_Utf8 (classJVMName, true);
    530         // TODO: this should do uniqueness checking:
    531 
    532         return m_constants.add (new CONSTANT_Class_info (name_index));
    533     }
    534 
    535 
    536     /**
    537      * Adds a new declared field to this class [with no attributes]
    538      */
    539     public int addField (final String name, final String descriptor, final int access_flags)
    540     {
    541         // TODO: support Fields with initializer attributes?
    542         // TODO: no "already exists" check done here
    543 
    544         final int name_index = addCONSTANT_Utf8 (name, true);
    545         final int descriptor_index = addCONSTANT_Utf8 (descriptor, true);
    546 
    547         final Field_info field = new Field_info (access_flags, name_index, descriptor_index,
    548             ElementFactory.newAttributeCollection (0));
    549 
    550         return m_fields.add (field);
    551     }
    552 
    553     /**
    554      * Adds a new declared field to this class [with given attributes]
    555      */
    556     public int addField (final String name, final String descriptor, final int access_flags,
    557                          final IAttributeCollection attributes)
    558     {
    559         // TODO: support Fields with initializer attributes?
    560         // TODO: no "already exists" check done here
    561 
    562         final int name_index = addCONSTANT_Utf8 (name, true);
    563         final int descriptor_index = addCONSTANT_Utf8 (descriptor, true);
    564 
    565         final Field_info field = new Field_info (access_flags, name_index, descriptor_index, attributes);
    566 
    567         return m_fields.add (field);
    568     }
    569 
    570 
    571     // TODO: rework this API
    572 
    573     public Method_info newEmptyMethod (final String name, final String descriptor, final int access_flags)
    574     {
    575         // TODO: flag for making synthetic etc
    576         final int attribute_name_index = addCONSTANT_Utf8 (Attribute_info.ATTRIBUTE_CODE, true);
    577         final int name_index = addCONSTANT_Utf8 (name, true);
    578         final int descriptor_index = addCONSTANT_Utf8 (descriptor, true);
    579 
    580         final IAttributeCollection attributes = ElementFactory.newAttributeCollection (0);
    581         final CodeAttribute_info code = new CodeAttribute_info (attribute_name_index, 0, 0,
    582             CodeAttribute_info.EMPTY_BYTE_ARRAY,
    583             AttributeElementFactory.newExceptionHandlerTable (0),
    584             ElementFactory.newAttributeCollection (0));
    585 
    586         attributes.add (code);
    587 
    588         final Method_info method = new Method_info (access_flags, name_index, descriptor_index, attributes);
    589 
    590         return method;
    591     }
    592 
    593     public int addMethod (final Method_info method)
    594     {
    595         return m_methods.add (method);
    596     }
    597 
    598     /**
    599      * Adds a reference to a field declared by this class.
    600      *
    601      * @return constant pool index of the reference
    602      */
    603     public int addFieldref (final Field_info field)
    604     {
    605         // TODO: keepUnique flag
    606 
    607         final CONSTANT_NameAndType_info nametype = new CONSTANT_NameAndType_info (field.m_name_index, field.m_descriptor_index);
    608         final int nametype_index = m_constants.add (nametype); // TODO: unique logic
    609 
    610         return m_constants.add (new CONSTANT_Fieldref_info (m_this_class_index, nametype_index));
    611     }
    612 
    613     /**
    614      * Adds a reference to a field declared by this class.
    615      *
    616      * @return constant pool index of the reference
    617      */
    618     public int addFieldref (final int offset)
    619     {
    620         // TODO: keepUnique flag
    621 
    622         final Field_info field = m_fields.get (offset);
    623 
    624         final CONSTANT_NameAndType_info nametype = new CONSTANT_NameAndType_info (field.m_name_index, field.m_descriptor_index);
    625         final int nametype_index = m_constants.add (nametype); // TODO: unique logic
    626 
    627         return m_constants.add (new CONSTANT_Fieldref_info (m_this_class_index, nametype_index));
    628     }
    629 
    630     // protected: .............................................................
    631 
    632     // package: ...............................................................
    633 
    634     // private: ...............................................................
    635 
    636 
    637     private static final class FieldDescriptor implements Comparable
    638     {
    639         // Comparable:
    640 
    641         public final int compareTo (final Object obj)
    642         {
    643             return m_name.compareTo (((FieldDescriptor) obj).m_name);
    644         }
    645 
    646         FieldDescriptor (final String name, final int modifiers, final String descriptor)
    647         {
    648             m_name = name;
    649             m_modifiers = modifiers;
    650             m_descriptor = descriptor;
    651         }
    652 
    653 
    654         final String m_name;
    655         final int m_modifiers;
    656         final String m_descriptor;
    657 
    658     } // end of nested class
    659 
    660 
    661     private static final class ConstructorDescriptor implements Comparable
    662     {
    663         // Comparable:
    664 
    665         public final int compareTo (final Object obj)
    666         {
    667             return m_descriptor.compareTo (((ConstructorDescriptor) obj).m_descriptor);
    668         }
    669 
    670         ConstructorDescriptor (final int modifiers, final String descriptor)
    671         {
    672             m_modifiers = modifiers;
    673             m_descriptor = descriptor;
    674         }
    675 
    676 
    677         final int m_modifiers;
    678         final String m_descriptor;
    679 
    680     } // end of nested class
    681 
    682 
    683     private static final class MethodDescriptor implements Comparable
    684     {
    685         // Comparable:
    686 
    687         public final int compareTo (final Object obj)
    688         {
    689             final MethodDescriptor rhs = (MethodDescriptor) obj;
    690 
    691             int result = m_name.compareTo (rhs.m_name);
    692             if (result == 0)
    693                 result = m_descriptor.compareTo (rhs.m_descriptor);
    694 
    695             return result;
    696         }
    697 
    698         MethodDescriptor (final String name, final int modifiers, final String descriptor)
    699         {
    700             m_name = name;
    701             m_modifiers = modifiers;
    702             m_descriptor = descriptor;
    703         }
    704 
    705 
    706         final String m_name;
    707         final int m_modifiers;
    708         final String m_descriptor;
    709 
    710     } // end of nested class
    711 
    712 
    713     // TODO: final fields
    714 
    715     private long m_magic;
    716     private int [] /* major, minor */ m_version;
    717     private int m_access_flags;
    718 
    719     private int m_this_class_index, m_super_class_index;
    720 
    721     private IConstantCollection m_constants;
    722     private IInterfaceCollection m_interfaces;
    723     private IFieldCollection m_fields;
    724     private IMethodCollection m_methods;
    725     private IAttributeCollection m_attributes;
    726 
    727     private long m_declaredSUID;
    728 
    729     private static final boolean DEBUG_SUID = false;
    730 
    731 } // end of class
    732 // ----------------------------------------------------------------------------
    733