• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ClassDef()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 
accept(final IClassDefVisitor visitor, final Object ctx)63     public void accept (final IClassDefVisitor visitor, final Object ctx)
64     {
65         visitor.visit (this, ctx);
66     }
67 
68 
getMagic()69     public long getMagic ()
70     {
71         return m_magic;
72     }
73 
setMagic(final long magic)74     public void setMagic (final long magic)
75     {
76         m_magic = magic;
77     }
78 
79 
getVersion()80     public int [] getVersion ()
81     {
82         return m_version;
83     }
84 
setVersion(final int [] version)85     public void setVersion (final int [] version)
86     {
87         m_version [0] = version [0];
88         m_version [1] = version [1];
89     }
90 
setDeclaredSUID(final long suid)91     public final void setDeclaredSUID (final long suid)
92     {
93         m_declaredSUID = suid;
94     }
95 
96 
getThisClassIndex()97     public int getThisClassIndex ()
98     {
99         return m_this_class_index;
100     }
101 
setThisClassIndex(final int this_class_index)102     public void setThisClassIndex (final int this_class_index)
103     {
104         m_this_class_index = this_class_index;
105     }
106 
getThisClass()107     public CONSTANT_Class_info getThisClass ()
108     {
109         return (CONSTANT_Class_info) m_constants.get (m_this_class_index);
110     }
111 
getSuperClass()112     public CONSTANT_Class_info getSuperClass ()
113     {
114         return (CONSTANT_Class_info) m_constants.get (m_super_class_index);
115     }
116 
getName()117     public String getName ()
118     {
119         return getThisClass ().getName (this);
120     }
121 
122 
getSuperClassIndex()123     public int getSuperClassIndex ()
124     {
125         return m_super_class_index;
126     }
127 
setSuperClassIndex(final int super_class_index)128     public void setSuperClassIndex (final int super_class_index)
129     {
130         m_super_class_index = super_class_index;
131     }
132 
133     // IAccessFlags:
134 
getAccessFlags()135     public final int getAccessFlags ()
136     {
137         return m_access_flags;
138     }
139 
setAccessFlags(final int flags)140     public final void setAccessFlags (final int flags)
141     {
142         m_access_flags = flags;
143     }
144 
isInterface()145     public boolean isInterface ()
146     {
147         return (m_access_flags & ACC_INTERFACE) != 0;
148     }
149 
isSynthetic()150     public boolean isSynthetic ()
151     {
152         return m_attributes.hasSynthetic ();
153     }
154 
isNested(final int [] nestedAccessFlags)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 
getConstants()167     public IConstantCollection getConstants ()
168     {
169         return m_constants;
170     }
171 
getInterfaces()172     public IInterfaceCollection getInterfaces ()
173     {
174         return m_interfaces;
175     }
176 
getFields()177     public IFieldCollection getFields ()
178     {
179         return m_fields;
180     }
181 
getMethods()182     public IMethodCollection getMethods ()
183     {
184         return m_methods;
185     }
186 
getAttributes()187     public IAttributeCollection getAttributes ()
188     {
189         return m_attributes;
190     }
191 
getFields(final String name)192     public int [] getFields (final String name)
193     {
194         return m_fields.get (this, name);
195     }
196 
getMethods(final String name)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      */
clone()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 
writeInClassFormat(final UDataOutputStream out)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 
getDeclaredSUID()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      */
computeSUID(final boolean skipCLINIT)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 
addCONSTANT_Utf8(final String value, final boolean keepUnique)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 
addStringConstant(final String value)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 
addNameType(final String name, final String typeDescriptor)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 
addClassref(final String classJVMName)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      */
addField(final String name, final String descriptor, final int access_flags)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      */
addField(final String name, final String descriptor, final int access_flags, final IAttributeCollection attributes)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 
newEmptyMethod(final String name, final String descriptor, final int access_flags)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 
addMethod(final Method_info method)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      */
addFieldref(final Field_info field)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      */
addFieldref(final int offset)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 
compareTo(final Object obj)641         public final int compareTo (final Object obj)
642         {
643             return m_name.compareTo (((FieldDescriptor) obj).m_name);
644         }
645 
FieldDescriptor(final String name, final int modifiers, final String descriptor)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 
compareTo(final Object obj)665         public final int compareTo (final Object obj)
666         {
667             return m_descriptor.compareTo (((ConstructorDescriptor) obj).m_descriptor);
668         }
669 
ConstructorDescriptor(final int modifiers, final String descriptor)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 
compareTo(final Object obj)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 
MethodDescriptor(final String name, final int modifiers, final String descriptor)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