3d5ff58145eeaecb92e5d5c57b7a12baac959a94
[jpf-core.git] / src / main / gov / nasa / jpf / vm / ClassInfo.java
1 /*
2  * Copyright (C) 2014, United States Government, as represented by the
3  * Administrator of the National Aeronautics and Space Administration.
4  * All rights reserved.
5  *
6  * The Java Pathfinder core (jpf-core) platform is licensed under the
7  * Apache License, Version 2.0 (the "License"); you may not use this file except
8  * in compliance with the License. You may obtain a copy of the License at
9  * 
10  *        http://www.apache.org/licenses/LICENSE-2.0. 
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and 
16  * limitations under the License.
17  */
18 package gov.nasa.jpf.vm;
19
20 import gov.nasa.jpf.Config;
21 import gov.nasa.jpf.JPF;
22 import gov.nasa.jpf.JPFConfigException;
23 import gov.nasa.jpf.JPFListener;
24 import gov.nasa.jpf.util.ImmutableList;
25 import gov.nasa.jpf.util.JPFLogger;
26 import gov.nasa.jpf.util.LocationSpec;
27 import gov.nasa.jpf.util.MethodSpec;
28 import gov.nasa.jpf.util.Misc;
29 import gov.nasa.jpf.util.OATHash;
30 import gov.nasa.jpf.util.Source;
31
32 import java.io.File;
33 import java.lang.reflect.Modifier;
34 import java.util.ArrayList;
35 import java.util.Collections;
36 import java.util.HashMap;
37 import java.util.HashSet;
38 import java.util.Iterator;
39 import java.util.LinkedHashMap;
40 import java.util.List;
41 import java.util.Map;
42 import java.util.NoSuchElementException;
43 import java.util.Set;
44 import java.util.logging.Level;
45
46
47 /**
48  * Describes the VM's view of a java class.  Contains descriptions of the
49  * static and dynamic fields, declaredMethods, and information relevant to the
50  * class.
51  * 
52  * Note that ClassInfos / classes have three different construction/initialization steps:
53  * (1) construction : recursively via ClassLoaderInfo.getResolvedClassInfo -> ClassFileContainer.createClassInfo
54  *     -> ClassInfo ctor -> resolveClass
55  *     this only creates the ClassInfo object, but it is not visible/usable from SUT code yet and hence not
56  *     observable from classLoaded() listeners
57  * (2) registration : create StaticElementInfo and add it to the respective ClassLoaderInfo statics, then create
58  *     the java.lang.Class companion object in the SUT
59  *     this makes the ClassInfo usable from SUT code
60  * (3) initialization : execute clinit (if the class has one)
61  * 
62  * Note that id/uniqueId are NOT set before registration takes place, and registration is not automatically performed since
63  * listeners/peers might create ClassInfos internally (e.g. for inspection), which should not be visible from the SUT or observable
64  * by other listeners.
65  * 
66  * Automatic registration from the ClassInfo ctors would require to pass a ThreadInfo context throughout the whole ClassLoaderInfo/
67  * ClassFileContainer/ClassInfo chain and could lead to false positives for sharedness based POR, which would record this
68  * thread as referencing even if this is a listener/peer internal request
69  */
70 public class ClassInfo extends InfoObject implements Iterable<MethodInfo>, GenericSignatureHolder {
71
72   //--- ClassInfo states, in chronological order
73   // note the somewhat strange, decreasing values - >= 0 (=thread-id) means 
74   // we are in clinit
75   // ideally, we would have a separate RESOLVED state, but (a) this is somewhat
76   // orthogonal to REGISTERED, and - more importantly - (b) we need the
77   // superClass instance when initializing our Fields (instance field offsets).
78   // Doing the field initialization during resolveReferencedClass() seems awkward and
79   // error prone (there is not much you can do with an unresolved class then)
80   
81   // not registered or clinit'ed (but cached in loadedClasses)
82   public static final int UNINITIALIZED = -1;
83   // 'REGISTERED' simply means 'sei' is set (we have a StaticElementInfo)
84   // 'INITIALIZING' is any number >=0, which is the thread objRef that executes the clinit
85   public static final int INITIALIZED = -2;
86
87   protected static final String ID_FIELD = "nativeId"; 
88
89   protected static JPFLogger logger = JPF.getLogger("class");
90
91   protected static int nClassInfos; // for statistics
92   
93   protected static Config config;
94
95   /**
96    * ClassLoader that loaded this class.
97    */
98   protected static final ClassLoader thisClassLoader = ClassInfo.class.getClassLoader();  
99   
100   /**
101    * our abstract factory to createAndInitialize object and class fields
102    */
103   protected static FieldsFactory fieldsFactory;
104
105   
106   protected static final FieldInfo[] EMPTY_FIELDINFO_ARRAY = new FieldInfo[0];
107   protected static final String[] EMPTY_STRING_ARRAY = new String[0];
108   protected static final String UNINITIALIZED_STRING = "UNINITIALIZED"; 
109   protected static final Map<String,MethodInfo> NO_METHODS = Collections.emptyMap();
110   protected static final Set<ClassInfo> NO_INTERFACES = new HashSet<ClassInfo>();
111   
112   /**
113    * support to auto-load listeners from annotations
114    */
115   protected static HashSet<String> autoloadAnnotations;
116   protected static HashSet<String> autoloaded;
117
118   /**
119    * Name of the class. e.g. "java.lang.String"
120    * NOTE - this is the expanded name for builtin types, e.g. "int", but NOT
121    * for arrays, which are for some reason in Ldot notation, e.g. "[Ljava.lang.String;" or "[I"
122    */
123   protected String name;
124   
125   /** type erased signature of the class. e.g. "Ljava/lang/String;" */
126   protected String signature;
127
128   /** Generic type signatures of the class as per para. 4.4.4 of the revised VM spec */
129   protected String genericSignature;
130
131   /** The classloader that defined (directly loaded) this class */
132   protected ClassLoaderInfo classLoader;
133   
134   // various class attributes
135   protected boolean      isClass = true;
136   protected boolean      isWeakReference = false;
137   protected boolean      isObjectClassInfo = false;
138   protected boolean      isStringClassInfo = false;
139   protected boolean      isThreadClassInfo = false;
140   protected boolean      isRefClassInfo = false;
141   protected boolean      isArray = false;
142   protected boolean      isEnum = false;
143   protected boolean      isReferenceArray = false;
144   protected boolean      isAbstract = false;
145   protected boolean      isBuiltin = false;
146
147   // that's ultimately where we keep the attributes
148   // <2do> this is currently quite redundant, but these are used in reflection
149   protected int modifiers;
150
151   protected MethodInfo   finalizer = null;
152
153   /** type based object attributes (for GC, partial order reduction and
154    * property checks)
155    */
156   protected int elementInfoAttrs = 0;
157
158   /**
159    * all our declared declaredMethods (we don't flatten, this is not
160    * a high-performance VM)
161    */
162   protected Map<String, MethodInfo> methods;
163
164   /**
165    * our instance fields.
166    * Note these are NOT flattened, idx.e. only contain the declared ones
167    */
168   protected FieldInfo[] iFields;
169
170   /** the storage size of instances of this class (stored as an int[]) */
171   protected int instanceDataSize;
172
173   /** where in the instance data array (int[]) do our declared fields start */
174   protected int instanceDataOffset;
175
176   /** total number of instance fields (flattened, not only declared ones) */
177   protected int nInstanceFields;
178
179   /**
180    * our static fields. Again, not flattened
181    */
182   protected FieldInfo[] sFields;
183
184   /** the storage size of static fields of this class (stored as an int[]) */
185   protected int staticDataSize;
186
187   /**
188    * we only set the superClassName upon creation, it is instantiated into
189    * a ClassInfo by resolveReferencedClass(), which is required to be called before
190    * we can createAndInitialize objects of this type
191    */
192   protected ClassInfo  superClass;
193   protected String superClassName;
194
195   protected String enclosingClassName;
196   protected String enclosingMethodName;
197
198   protected String[] innerClassNames = EMPTY_STRING_ARRAY;
199   protected BootstrapMethodInfo[] bootstrapMethods;
200     
201   /** direct ifcs implemented by this class */
202   protected String[] interfaceNames;
203
204   protected Set<ClassInfo> interfaces = new HashSet<ClassInfo>();
205   
206   /** cache of all interfaceNames (parent interfaceNames and interface parents) - lazy eval */
207   protected Set<ClassInfo> allInterfaces;
208   
209   /** Name of the package. */
210   protected String packageName;
211
212   /** this is only set if the classfile has a SourceFile class attribute */
213   protected String sourceFileName;
214
215   /** 
216    * Uniform resource locater for the class file. NOTE: since for builtin classes
217    * there is no class file assigned is set to the typeName 
218    */ 
219   protected String classFileUrl;
220
221   /** from where the corresponding classfile was loaded (if this is not a builtin) */
222   protected gov.nasa.jpf.vm.ClassFileContainer container;
223
224   
225   /**
226    *  a search global numeric id that is only unique within this ClassLoader namespace. Ids are
227    *  computed by the ClassLoaderInfo/Statics implementation during ClassInfo registration
228    */
229   protected int  id = -1;
230
231   /**
232    * A search global unique id associate with this class, which is comprised of the classLoader id
233    * and the (loader-specific) ClassInfo id. This is just a quick way to do search global checks for equality
234    * 
235    * NOTE - since this is based on the classloader-specific id, it can't be used before the ClassInfo is registered
236    */
237   protected long uniqueId = -1;
238
239   /**
240    * this is the object we use to enter declaredMethods in the underlying VM
241    * (it replaces Reflection)
242    */
243   protected NativePeer nativePeer;
244
245   /** Source file associated with the class.*/
246   protected Source source;
247
248   protected boolean enableAssertions;
249
250   /** actions to be taken when an object of this type is gc'ed */
251   protected ImmutableList<ReleaseAction> releaseActions; 
252           
253   
254   static boolean init (Config config) {
255
256     ClassInfo.config = config;
257     
258     setSourceRoots(config);
259     //buildBCELModelClassPath(config);
260
261     fieldsFactory = config.getEssentialInstance("vm.fields_factory.class",
262                                                 FieldsFactory.class);
263
264     autoloadAnnotations = config.getNonEmptyStringSet("listener.autoload");
265     if (autoloadAnnotations != null) {
266       autoloaded = new HashSet<String>();
267
268       if (logger.isLoggable(Level.INFO)) {
269         for (String s : autoloadAnnotations){
270           logger.info("watching for autoload annotation @" + s);
271         }
272       }
273     }
274
275     return true;
276   }
277
278   public static boolean isObjectClassInfo (ClassInfo ci){
279     return ci.isObjectClassInfo();
280   }
281
282   public static boolean isStringClassInfo (ClassInfo ci){
283     return ci.isStringClassInfo();
284   }
285
286   
287    //--- initialization interface towards parsers (which might reside in other packages)
288     
289   protected void setClass(String clsName, String superClsName, int flags, int cpCount) throws ClassParseException {
290     String parsedName = Types.getClassNameFromTypeName(clsName);
291
292     if (name != null && !name.equals(parsedName)){
293       throw new ClassParseException("wrong class name (expected: " + name + ", found: " + parsedName + ')');
294     }
295     name = parsedName;
296     
297     // the enclosingClassName is set on demand since it requires loading enclosing class candidates
298     // to verify their innerClass attributes
299
300     int i = name.lastIndexOf('.');
301     packageName = (i > 0) ? name.substring(0, i) : "";
302
303     modifiers = flags;
304     
305     // annotations are interfaces too (not exposed by Modifier)
306     isClass = ((flags & Modifier.INTERFACE) == 0);
307
308     superClassName = superClsName;
309   }
310
311   public void setInnerClassNames(String[] clsNames) {
312     innerClassNames = clsNames;
313   }
314
315   public void setEnclosingClass (String clsName) {
316     enclosingClassName = clsName;
317   }
318   
319   public void setEnclosingMethod (String mthName){
320     enclosingMethodName = mthName;    
321   }
322
323   public void setInterfaceNames(String[] ifcNames) {
324     interfaceNames = ifcNames;
325   }
326   
327   public void setSourceFile (String fileName){
328     // prepend if we already know the package
329     if (packageName.length() > 0) {
330       // Source will take care of proper separator chars later
331       sourceFileName = packageName.replace('.', '/') + '/' + fileName;
332     } else {
333       sourceFileName = fileName;
334     }
335   }
336
337   public void setFields(FieldInfo[] fields) {
338     if (fields == null){
339       iFields = EMPTY_FIELDINFO_ARRAY;
340       sFields = EMPTY_FIELDINFO_ARRAY;
341       
342     } else { // there are fields, we have to tell them apart
343       int nInstance = 0, nStatic = 0;
344       for (int i = 0; i < fields.length; i++) {
345         if (fields[i].isStatic()) {
346           nStatic++;
347         } else {
348           nInstance++;
349         }
350       }
351
352       FieldInfo[] instanceFields = (nInstance > 0) ? new FieldInfo[nInstance] : EMPTY_FIELDINFO_ARRAY;
353       FieldInfo[] staticFields = (nStatic > 0) ? new FieldInfo[nStatic] : EMPTY_FIELDINFO_ARRAY;
354
355       int iInstance = 0;
356       int iStatic = 0;
357       for (int i = 0; i < fields.length; i++) {
358         FieldInfo fi = fields[i];
359
360         if (fi.isStatic()) {
361           staticFields[iStatic++] = fi;
362         } else {
363           instanceFields[iInstance++] = fi;
364         }
365         
366         processJPFAnnotations(fi);
367       }
368
369       iFields = instanceFields;
370       sFields = staticFields;
371
372       // we can't link the fields yet because we need the superclasses to be resolved
373     }
374   }
375
376   protected void setMethod (MethodInfo mi){
377     mi.linkToClass(this);
378     methods.put( mi.getUniqueName(), mi);
379     processJPFAnnotations(mi);
380   }
381   
382   public void setMethods (MethodInfo[] newMethods) {
383     if (newMethods != null && newMethods.length > 0) {
384       methods = new LinkedHashMap<String, MethodInfo>();
385
386       for (int i = 0; i < newMethods.length; i++) {
387         setMethod( newMethods[i]);
388       }
389     }
390   }
391  
392   protected void processJPFAttrAnnotation(InfoObject infoObj){
393     AnnotationInfo ai = infoObj.getAnnotation("gov.nasa.jpf.annotation.JPFAttribute");
394     if (ai != null){
395       String[] attrTypes = ai.getValueAsStringArray();
396       if (attrTypes != null){
397         ClassLoader loader = config.getClassLoader();
398
399         for (String clsName : attrTypes){
400           try {
401             Class<?> attrCls = loader.loadClass(clsName);
402             Object attr = attrCls.newInstance(); // needs to have a default ctor
403             infoObj.addAttr(attr);
404             
405           } catch (ClassNotFoundException cnfx){
406             logger.warning("attribute class not found: " + clsName);
407             
408           } catch (IllegalAccessException iax){
409             logger.warning("attribute class has no public default ctor: " + clsName);            
410             
411           } catch (InstantiationException ix){
412             logger.warning("attribute class has no default ctor: " + clsName);            
413           }
414         }
415       }
416     }    
417   }
418
419   protected void processNoJPFExecutionAnnotation(InfoObject infoObj) {
420     AnnotationInfo ai = infoObj.getAnnotation("gov.nasa.jpf.annotation.NoJPFExecution");
421     if (ai != null) {
422       infoObj.addAttr(NoJPFExec.SINGLETON);
423     }
424   }
425
426   protected void processJPFAnnotations(InfoObject infoObj) {
427     processJPFAttrAnnotation(infoObj);
428     processNoJPFExecutionAnnotation(infoObj);
429   }
430
431     public AnnotationInfo getResolvedAnnotationInfo (String typeName){
432     return classLoader.getResolvedAnnotationInfo( typeName);
433   }
434   
435   @Override
436   public void setAnnotations(AnnotationInfo[] annotations) {
437     this.annotations = annotations;
438   }
439   
440   //--- end initialization interface
441  
442   //--- the overridden annotation accessors (we need these because of inherited superclass annotations)
443   // note that we don't flatten annotations anymore, assuming the prevalent query will be getAnnotation(name)
444   
445   @Override
446   public boolean hasAnnotations(){
447     if (annotations.length > 0){
448       return true;
449     }
450     
451     for (ClassInfo ci = superClass; ci != null; ci = ci.superClass){
452       AnnotationInfo[] a = ci.annotations;
453       for (int j=0; j<a.length; j++){
454         if (a[j].isInherited()){
455           return true;
456         }
457       }
458     }
459     
460     return false;
461   }
462   
463   /**
464    * return all annotations, which includes the ones inherited from our superclasses
465    * NOTE - this is not very efficient
466    */
467   @Override
468   public AnnotationInfo[] getAnnotations() {
469     int nAnnotations = annotations.length;
470     for (ClassInfo ci = superClass; ci != null; ci = ci.superClass){
471       AnnotationInfo[] a = ci.annotations;
472       for (int i=0; i<a.length; i++){
473         if (a[i].isInherited()){
474           nAnnotations++;
475         }
476       }
477     }
478     
479     AnnotationInfo[] allAnnotations = new AnnotationInfo[nAnnotations];
480     System.arraycopy(annotations, 0, allAnnotations, 0, annotations.length);
481     int idx=annotations.length;
482     for (ClassInfo ci = superClass; ci != null; ci = ci.superClass){
483       AnnotationInfo[] a = ci.annotations;
484       for (int i=0; i<a.length; i++){
485         if (a[i].isInherited()){
486           allAnnotations[idx++] = a[i];
487         }
488       }
489     }
490     
491     return allAnnotations;
492   }
493     
494   @Override
495   public AnnotationInfo getAnnotation (String annotationName){
496     AnnotationInfo[] a = annotations;
497     for (int i=0; i<a.length; i++){
498       if (a[i].getName().equals(annotationName)){
499         return a[i];
500       }
501     }
502     
503     for (ClassInfo ci = superClass; ci != null; ci = ci.superClass){
504       a = ci.annotations;
505       for (int i=0; i<a.length; i++){
506         AnnotationInfo ai = a[i];
507         if (ai.getName().equals(annotationName) && ai.isInherited()){
508           return ai;
509         }
510       }
511     }
512     
513     return null;
514   }
515   
516   protected ClassInfo (String name, ClassLoaderInfo cli, String classFileUrl){
517     nClassInfos++;
518     
519     this.name = name;
520     this.classLoader = cli;
521     this.classFileUrl = classFileUrl;
522     
523     this.methods = NO_METHODS;  // yet
524
525     // rest has to be initialized by concrete ctor, which should call resolveAndLink(parser)
526   }
527   
528   /**
529    * the initialization part that has to happen once we have super, fields, methods and annotations
530    * NOTE - this has to be called by concrete ctors after parsing class files
531    */
532   protected void resolveAndLink () throws ClassParseException {
533     
534     //--- these might get streamlined
535     isStringClassInfo = isStringClassInfo0();
536     isThreadClassInfo = isThreadClassInfo0();
537     isObjectClassInfo = isObjectClassInfo0();
538     isRefClassInfo = isRefClassInfo0();
539    // isWeakReference = isWeakReference0();
540     isAbstract = (modifiers & Modifier.ABSTRACT) != 0;
541    // isEnum = isEnum0();
542     
543     finalizer = getFinalizer0();
544
545     resolveClass(); // takes care of super classes and interfaces
546
547     // Used to enter native methods (in the host VM).
548     // This needs to be initialized AFTER we get our  MethodInfos, since it does a reverse lookup to determine which
549     // ones are handled by the peer (by means of setting MethodInfo attributes)
550     nativePeer = loadNativePeer();
551     checkUnresolvedNativeMethods();
552
553     linkFields(); // computes field offsets
554     
555     setAssertionStatus();
556     processJPFConfigAnnotation();
557     processJPFAnnotations(this);
558     loadAnnotationListeners();    
559   }
560   
561   protected ClassInfo(){
562     nClassInfos++;
563     
564     // for explicit subclass initialization
565   }
566   
567   /**
568    * ClassInfo ctor used for builtin types (arrays and primitive types)
569    * idx.e. classes we don't have class files for
570    */
571   protected ClassInfo (String builtinClassName, ClassLoaderInfo classLoader) {
572     nClassInfos++;
573
574     this.classLoader = classLoader;
575
576     isArray = (builtinClassName.charAt(0) == '[');
577     isReferenceArray = isArray && (builtinClassName.endsWith(";") || builtinClassName.charAt(1) == '[');
578     isBuiltin = true;
579
580     name = builtinClassName;
581
582     logger.log(Level.FINE, "generating builtin class: %1$s", name);
583
584     packageName = ""; // builtin classes don't reside in java.lang !
585     sourceFileName = null;
586     source = null;
587     genericSignature = "";
588
589     // no fields
590     iFields = EMPTY_FIELDINFO_ARRAY;
591     sFields = EMPTY_FIELDINFO_ARRAY;
592
593     if (isArray) {
594       if(classLoader.isSystemClassLoader()) {
595         superClass = ((SystemClassLoaderInfo)classLoader).getObjectClassInfo();
596       } else {
597         superClass = ClassLoaderInfo.getCurrentSystemClassLoader().getObjectClassInfo();
598       }
599       interfaceNames = loadArrayInterfaces();
600       methods = loadArrayMethods();
601     } else {
602       superClass = null; // strange, but true, a 'no object' class
603       interfaceNames = loadBuiltinInterfaces(name);
604       methods = loadBuiltinMethods(name);
605     }
606
607     enableAssertions = true; // doesn't really matter - no code associated
608
609     classFileUrl = name;
610     
611     // no fields or declaredMethods, so we don't have to link/resolve anything
612   }
613   
614   public static int getNumberOfLoadedClasses(){
615     return nClassInfos;
616   }
617   
618   //--- the VM type specific methods
619   // <2do> those should be abstract
620   
621   protected void setAnnotationValueGetterCode (MethodInfo pmi, FieldInfo fi){
622     // to be overridden by VM specific class
623   }
624   
625   protected void setDirectCallCode (MethodInfo miCallee, MethodInfo miStub){
626     // to be overridden by VM specific class
627   }
628   
629   protected void setLambdaDirectCallCode (MethodInfo miDirectCall, BootstrapMethodInfo bootstrapMethod){
630     // to be overridden by VM specific class
631   }
632   
633   protected void setNativeCallCode (NativeMethodInfo miNative){
634     // to be overridden by VM specific class
635   }
636   
637   protected void setRunStartCode (MethodInfo miStub, MethodInfo miRun){
638     // to be overridden by VM specific class
639   }
640   
641   /**
642    * createAndInitialize a fully synthetic implementation of an Annotation proxy
643    */
644   protected ClassInfo (ClassInfo annotationCls, String name, ClassLoaderInfo classLoader, String url) {
645     this.classLoader = classLoader;
646     
647     this.name = name;
648     isClass = true;
649
650     //superClass = objectClassInfo;
651     superClass = ClassLoaderInfo.getSystemResolvedClassInfo("gov.nasa.jpf.AnnotationProxyBase");
652
653     interfaceNames = new String[]{ annotationCls.name };    
654     packageName = annotationCls.packageName;
655     sourceFileName = annotationCls.sourceFileName;
656     genericSignature = annotationCls.genericSignature;
657
658     sFields = new FieldInfo[0]; // none
659     staticDataSize = 0;
660
661     methods = new HashMap<String, MethodInfo>();
662     iFields = new FieldInfo[annotationCls.methods.size()];
663     nInstanceFields = iFields.length;
664
665     // all accessor declaredMethods of ours make it into iField/method combinations
666     int idx = 0;
667     int off = 0;  // no super class
668     for (MethodInfo mi : annotationCls.getDeclaredMethodInfos()) {
669       String mname = mi.getName();
670       String mtype = mi.getReturnType();
671       String genericSignature = mi.getGenericSignature();
672
673       // create and initialize an instance field for it
674       FieldInfo fi = FieldInfo.create(mname, mtype, 0);
675       fi.linkToClass(this, idx, off);
676       fi.setGenericSignature(genericSignature);
677       iFields[idx++] = fi;
678       off += fi.getStorageSize();
679
680       MethodInfo pmi = new MethodInfo(this, mname, mi.getSignature(), Modifier.PUBLIC, 1, 2);
681       pmi.setGenericSignature(genericSignature);
682       
683       setAnnotationValueGetterCode( pmi, fi);
684       methods.put(pmi.getUniqueName(), pmi);
685     }
686
687     instanceDataSize = computeInstanceDataSize();
688     instanceDataOffset = 0;
689
690     classFileUrl = url;
691     linkFields();
692   }
693   
694   
695   //used to create synthetic classes that implement functional interfaces
696   protected ClassInfo createFuncObjClassInfo (BootstrapMethodInfo bootstrapMethod, String name, String samUniqueName, String[] fieldTypesName) {
697    return null;
698  }
699  
700  protected ClassInfo (ClassInfo funcInterface, BootstrapMethodInfo bootstrapMethod, String name, String[] fieldTypesName) {
701    ClassInfo enclosingClass = bootstrapMethod.enclosingClass;
702    this.classLoader = enclosingClass.classLoader;
703
704    this.name = name;
705    isClass = true;
706
707    superClassName = "java.lang.Object";
708
709    interfaceNames = new String[]{ funcInterface.name };    
710    packageName = enclosingClass.getPackageName();
711
712    // creating fields used to capture free variables
713    int n = fieldTypesName.length;
714    
715    iFields = new FieldInfo[n];
716    nInstanceFields = n;
717    
718    sFields = new FieldInfo[0];
719    staticDataSize = 0;
720    
721    int idx = 0;
722    int off = 0;  // no super class
723    
724    int i = 0;
725    for(String type: fieldTypesName) {
726      FieldInfo fi = FieldInfo.create("arg" + i++, type, 0);
727      fi.linkToClass(this, idx, off);
728      iFields[idx++] = fi;
729      off += fi.getStorageSize();
730    }
731    
732    linkFields();
733  }
734   
735   // since id and hence uniqueId are not set before this class is registered, we can't use them
736   
737   @Override
738   public int hashCode() {
739     return OATHash.hash(name.hashCode(), classLoader.hashCode());
740   }
741   
742   @Override
743   public boolean equals (Object o) {
744     if (o instanceof ClassInfo) {
745       ClassInfo other = (ClassInfo)o;
746       if (classLoader == other.classLoader) {
747         // beware of ClassInfos that are not registered yet - in this case we have to equals names
748         if (name.equals(other.name)) {
749           return true;
750         }
751       }
752     }
753     
754     return false;
755   }
756
757   protected String computeSourceFileName(){
758     return name.replace('.', '/') + ".java";
759   }
760
761   protected void checkUnresolvedNativeMethods(){
762     for (MethodInfo mi : methods.values()){
763       if (mi.isUnresolvedNativeMethod()){
764         NativeMethodInfo nmi = new NativeMethodInfo(mi, null, nativePeer);
765         nmi.replace(mi);
766       }
767     }
768   }
769
770   protected void processJPFConfigAnnotation() {
771     AnnotationInfo ai = getAnnotation("gov.nasa.jpf.annotation.JPFConfig");
772     if (ai != null) {
773       for (String s : ai.getValueAsStringArray()) {
774         config.parse(s);
775       }
776     }
777   }
778
779   protected void loadAnnotationListeners () {
780     if (autoloadAnnotations != null) {
781       autoloadListeners(annotations); // class annotations
782
783       for (int i=0; i<sFields.length; i++) {
784         autoloadListeners(sFields[i].getAnnotations());
785       }
786
787       for (int i=0; i<iFields.length; i++) {
788         autoloadListeners(iFields[i].getAnnotations());
789       }
790
791       // method annotations are checked during method loading
792       // (to avoid extra iteration)
793     }
794   }
795
796   void autoloadListeners(AnnotationInfo[] annos) {
797     if ((annos != null) && (autoloadAnnotations != null)) {
798       for (AnnotationInfo ai : annos) {
799         String aName = ai.getName();
800         if (autoloadAnnotations.contains(aName)) {
801           if (!autoloaded.contains(aName)) {
802             autoloaded.add(aName);
803             String key = "listener." + aName;
804             String defClsName = aName + "Checker";
805             try {
806               JPFListener listener = config.getInstance(key, JPFListener.class, defClsName);
807               
808               JPF jpf = VM.getVM().getJPF(); // <2do> that's a BAD access path
809               jpf.addUniqueTypeListener(listener);
810
811               if (logger.isLoggable(Level.INFO)){
812                 logger.info("autoload annotation listener: @", aName, " => ", listener.getClass().getName());
813               }
814
815             } catch (JPFConfigException cx) {
816               logger.warning("no autoload listener class for annotation " + aName +
817                              " : " + cx.getMessage());
818               autoloadAnnotations.remove(aName);
819             }
820           }
821         }
822       }
823
824       if (autoloadAnnotations.isEmpty()) {
825         autoloadAnnotations = null;
826       }
827     }
828   }
829
830   protected NativePeer loadNativePeer(){
831     return NativePeer.getNativePeer(this);
832   }
833   
834   /**
835    * Returns the class loader that 
836    */
837   public ClassLoaderInfo getClassLoaderInfo() {
838     return classLoader;
839   }
840
841   /**
842    * the container this is stored in
843    */
844   public Statics getStatics() {
845     return classLoader.getStatics();
846   }
847   
848   /**
849    * required by InfoObject interface
850    */
851   public ClassInfo getClassInfo() {
852     return this;
853   }
854
855   protected void setAssertionStatus() {
856     if(isInitialized()) {
857       return;
858     } else {
859       enableAssertions = classLoader.desiredAssertionStatus(name);
860     }
861   }
862
863   boolean getAssertionStatus () {
864     return enableAssertions;
865   }
866
867   public boolean desiredAssertionStatus() {
868     return classLoader.desiredAssertionStatus(name);
869   }
870
871   @Override
872   public String getGenericSignature() {
873     return genericSignature;
874   }
875
876   @Override
877   public void setGenericSignature(String sig){
878     genericSignature = sig;
879   }
880   
881   public boolean isArray () {
882     return isArray;
883   }
884
885   public boolean isEnum () {
886     return isEnum;
887   }
888
889   public boolean isAbstract() {
890     return isAbstract;
891   }
892
893   public boolean isBuiltin(){
894     return isBuiltin;
895   }
896   
897   public boolean isInterface() {
898     return ((modifiers & Modifier.INTERFACE) != 0);
899   }
900
901   public boolean isReferenceArray () {
902     return isReferenceArray;
903   }
904
905   public boolean isObjectClassInfo() {
906     return isObjectClassInfo;
907   }
908
909   public boolean isStringClassInfo() {
910     return isStringClassInfo;
911   }
912
913   public boolean isThreadClassInfo() {
914     return isThreadClassInfo;
915   }
916
917   protected void checkNoClinitInitialization(){
918     if (!isInitialized()){
919       ThreadInfo ti = ThreadInfo.getCurrentThread();
920       registerClass(ti);
921       setInitialized(); // we might want to check if there is a clinit
922     }
923   }
924   
925   protected ClassInfo createAnnotationProxy (String proxyName){
926     // to be overridden by VM specific ClassInfos
927     return null;
928   }
929   
930   public ClassInfo getAnnotationProxy (){
931     // <2do> test if this is a annotation ClassInfo
932     
933     checkNoClinitInitialization(); // annotation classes don't have clinits
934     
935     ClassInfo ciProxy = classLoader.getResolvedAnnotationProxy(this);
936     ciProxy.checkNoClinitInitialization();
937     
938     return ciProxy;
939   }
940   
941 /**
942   public static ClassInfo getAnnotationProxy (ClassInfo ciAnnotation){
943     ThreadInfo ti = ThreadInfo.getCurrentThread();
944
945     // make sure the annotationCls is initialized (no code there)
946     if (!ciAnnotation.isInitialized()) {
947       ciAnnotation.registerClass(ti);
948       ciAnnotation.setInitialized(); // no clinit
949     }
950
951     String url = computeProxyUrl(ciAnnotation);
952     ClassInfo ci = null; // getOriginalClassInfo(url);
953
954     if (ci == null){
955       String cname = ciAnnotation.getName() + "$Proxy";
956       ci = new ClassInfo(ciAnnotation, cname, ciAnnotation.classLoader, url);
957       ciAnnotation.classLoader.addResolvedClass(ci);
958       if (!ci.isInitialized()){
959         ci.registerClass(ti);
960         ci.setInitialized();
961       }
962     }
963
964     return ci;
965   }
966 **/
967
968   public boolean areAssertionsEnabled() {
969     return enableAssertions;
970   }
971
972   public boolean hasInstanceFields () {
973     return (instanceDataSize > 0);
974   }
975
976   public ElementInfo getClassObject(){
977     StaticElementInfo sei = getStaticElementInfo();
978     
979     if (sei != null){
980       int objref = sei.getClassObjectRef();
981       return VM.getVM().getElementInfo(objref);
982     }
983
984     return null;
985   }
986   
987   public ElementInfo getModifiableClassObject(){
988     StaticElementInfo sei = getStaticElementInfo();
989     
990     if (sei != null){
991       int objref = sei.getClassObjectRef();
992       return VM.getVM().getModifiableElementInfo(objref);
993     }
994
995     return null;
996   }
997   
998
999   public int getClassObjectRef () {
1000     StaticElementInfo sei = getStaticElementInfo();    
1001     return (sei != null) ? sei.getClassObjectRef() : MJIEnv.NULL;
1002   }
1003
1004   public gov.nasa.jpf.vm.ClassFileContainer getContainer(){
1005     return container;
1006   }
1007   
1008   public String getClassFileUrl (){
1009     return classFileUrl;
1010   }
1011
1012   //--- type based object release actions
1013   
1014   public boolean hasReleaseAction (ReleaseAction action){
1015     return (releaseActions != null) && releaseActions.contains(action);
1016   }
1017   
1018   /**
1019    * NOTE - this can only be set *before* subclasses are loaded (e.g. from classLoaded() notification) 
1020    */
1021   public void addReleaseAction (ReleaseAction action){
1022     // flattened in ctor to super releaseActions
1023     releaseActions = new ImmutableList<ReleaseAction>( action, releaseActions);
1024   }
1025   
1026   /**
1027    * recursively process release actions registered for this type or any of
1028    * its super types (only classes). The releaseAction list is flattened during
1029    * ClassInfo initialization, to reduce runtime overhead during GC sweep
1030    */
1031   public void processReleaseActions (ElementInfo ei){
1032     if (superClass != null){
1033       superClass.processReleaseActions(ei);
1034     }
1035     
1036     if (releaseActions != null) {
1037       for (ReleaseAction action : releaseActions) {
1038         action.release(ei);
1039       }
1040     }
1041   }
1042   
1043   public int getModifiers() {
1044     return modifiers;
1045   }
1046
1047   /**
1048    * Note that 'uniqueName' is the name plus the argument type part of the
1049    * signature, idx.e. everything that's relevant for overloading
1050    * (besides saving some const space, we also ease reverse lookup
1051    * of natives that way).
1052    * Note also that we don't have to make any difference between
1053    * class and instance declaredMethods, because that just matters in the
1054    * INVOKExx instruction, when looking up the relevant ClassInfo to start
1055    * searching in (either by means of the object type, or by means of the
1056    * constpool classname entry).
1057    */
1058   public MethodInfo getMethod (String uniqueName, boolean isRecursiveLookup) {
1059     MethodInfo mi = methods.get(uniqueName);
1060
1061     if ((mi == null) && isRecursiveLookup && (superClass != null)) {
1062       mi = superClass.getMethod(uniqueName, true);
1063     }
1064
1065     return mi;
1066   }
1067
1068   /**
1069    * if we don't know the return type
1070    * signature is in paren/dot notation
1071    */
1072   public MethodInfo getMethod (String name, String signature, boolean isRecursiveLookup) {
1073     MethodInfo mi = null;
1074     String matchName = name + signature;
1075
1076     for (Map.Entry<String, MethodInfo>e : methods.entrySet()) {
1077       if (e.getKey().startsWith(matchName)){
1078         mi = e.getValue();
1079         break;
1080       }
1081     }
1082
1083     if ((mi == null) && isRecursiveLookup && (superClass != null)) {
1084       mi = superClass.getMethod(name, signature, true);
1085     }
1086
1087     return mi;
1088   }
1089
1090   
1091   public MethodInfo getDefaultMethod (String uniqueName) {
1092     MethodInfo mi = null;
1093     
1094     for (ClassInfo ciIfc : this.getAllInterfaces()){
1095       MethodInfo miIfc = ciIfc.getMethod(uniqueName, false);
1096       if (miIfc != null && !miIfc.isAbstract() && !miIfc.isPrivate() && !miIfc.isStatic()){
1097         if (mi != null && !mi.equals(miIfc)){
1098           if(miIfc.getClassInfo().isSubInterfaceOf(mi.getClassInfo())) {
1099             mi = miIfc;
1100           } else if(mi.getClassInfo().isSubInterfaceOf(miIfc.getClassInfo())) {
1101             continue;
1102           } else {
1103             // this has to throw a IncompatibleClassChangeError in the client since Java prohibits ambiguous default methods
1104             String msg = "Conflicting default methods: " + mi.getFullName() + ", " + miIfc.getFullName();
1105             throw new ClassChangeException(msg);
1106           }
1107         } else {
1108           mi = miIfc;
1109         }
1110       }
1111     }
1112     
1113     return mi;
1114   }
1115   
1116   private boolean isSubInterfaceOf(ClassInfo classInfo) {
1117     assert this.isInterface() && classInfo.isInterface();
1118     return this == classInfo || this.getAllInterfaces().contains(classInfo);
1119   }
1120
1121   /**
1122    * This retrieves the SAM from this functional interface. Note that this is only
1123    * called on functional interface expecting to have a SAM. This shouldn't expect 
1124    * this interface to have only one method which is abstract, since:
1125    *    1. functional interface can declare the abstract methods from the java.lang.Object 
1126    *       class.
1127    *    2. functional interface can extend another interface which is functional, but it 
1128    *       should not declare any new abstract methods.
1129    *    3. functional interface can have one abstract method and any number of default
1130    *       methods.
1131    * 
1132    * To retrieve the SAM, this method iterates over the methods of this interface and its 
1133    * superinterfaces, and it returns the first method which is abstract and it does not 
1134    * declare a method in java.lang.Object.
1135    */
1136   public MethodInfo getInterfaceAbstractMethod () {
1137     ClassInfo objCi = ClassLoaderInfo.getCurrentResolvedClassInfo("java.lang.Object");
1138     
1139     for(MethodInfo mi: this.methods.values()) {
1140       if(mi.isAbstract() && objCi.getMethod(mi.getUniqueName(), false)==null) {
1141         return mi;
1142       }
1143     }
1144     
1145     for (ClassInfo ifc : this.interfaces){
1146       MethodInfo mi = ifc.getInterfaceAbstractMethod();
1147       if(mi!=null) {
1148         return mi;
1149       }
1150     }
1151     
1152     return null;
1153   }
1154
1155   /**
1156    * method lookup for use by reflection methods (java.lang.Class.getXMethod)
1157    * 
1158    * note this doesn't specify the return type, which means covariant return 
1159    * types are not allowed in reflection lookup.
1160    * 
1161    * note also this includes interface methods, but only after the inheritance
1162    * hierarchy has been searched
1163    */
1164   public MethodInfo getReflectionMethod (String fullName, boolean isRecursiveLookup) {
1165         
1166     // first look for methods within the class hierarchy
1167     for (ClassInfo ci = this; ci != null; ci = ci.superClass){
1168       for (Map.Entry<String, MethodInfo>e : ci.methods.entrySet()) {
1169         String name = e.getKey();
1170         if (name.startsWith(fullName)) {
1171           return e.getValue();
1172         }
1173       }
1174       if (!isRecursiveLookup){
1175         return null;
1176       }
1177     }
1178
1179     // this is the recursive case - if none found, look for interface methods
1180     for (ClassInfo ci : getAllInterfaces() ){
1181       for (Map.Entry<String, MethodInfo>e : ci.methods.entrySet()) {
1182         String name = e.getKey();
1183         if (name.startsWith(fullName)) {
1184           return e.getValue();
1185         }
1186       }      
1187     }    
1188
1189     return null;
1190   }
1191   
1192   /**
1193    * iterate over all declaredMethods of this class (and it's superclasses), until
1194    * the provided MethodLocator tells us it's done
1195    */
1196   public void matchMethods (MethodLocator loc) {
1197     for (MethodInfo mi : methods.values()) {
1198       if (loc.match(mi)) {
1199         return;
1200       }
1201     }
1202     if (superClass != null) {
1203       superClass.matchMethods(loc);
1204     }
1205   }
1206
1207   /**
1208    * iterate over all declaredMethods declared in this class, until the provided
1209    * MethodLocator tells us it's done
1210    */
1211   public void matchDeclaredMethods (MethodLocator loc) {
1212     for (MethodInfo mi : methods.values()) {
1213       if (loc.match(mi)) {
1214         return;
1215       }
1216     }
1217   }
1218
1219   @Override
1220   public Iterator<MethodInfo> iterator() {
1221     return new Iterator<MethodInfo>() {
1222       ClassInfo ci = ClassInfo.this;
1223       Iterator<MethodInfo> it = ci.methods.values().iterator();
1224
1225       @Override
1226         public boolean hasNext() {
1227         if (it.hasNext()) {
1228           return true;
1229         } else {
1230           if (ci.superClass != null) {
1231             ci = ci.superClass;
1232             it = ci.methods.values().iterator();
1233             return it.hasNext();
1234           } else {
1235             return false;
1236           }
1237         }
1238       }
1239
1240       @Override
1241         public MethodInfo next() {
1242         if (hasNext()) {
1243           return it.next();
1244         } else {
1245           throw new NoSuchElementException();
1246         }
1247       }
1248
1249       @Override
1250         public void remove() {
1251         // not supported
1252         throw new UnsupportedOperationException("can't remove methods");
1253       }
1254     };
1255   }
1256   
1257   public Iterator<MethodInfo> declaredMethodIterator() {
1258     return methods.values().iterator();
1259   }
1260
1261   /**
1262    * Search up the class hierarchy to find a static field
1263    * @param fName name of field
1264    * @return null if field name not found (not declared)
1265    */
1266   public FieldInfo getStaticField (String fName) {
1267     FieldInfo fi;
1268     ClassInfo c = this;
1269
1270     while (c != null) {
1271       fi = c.getDeclaredStaticField(fName);
1272       if (fi != null) {
1273         return fi;
1274       }
1275       c = c.superClass;
1276     }
1277
1278     //interfaceNames can have static fields too
1279     // <2do> why would that not be already resolved here ?
1280     for (ClassInfo ci : getAllInterfaces()) {
1281       fi = ci.getDeclaredStaticField(fName);
1282       if (fi != null) {
1283         return fi;
1284       }
1285     }
1286
1287     return null;
1288   }
1289
1290   public Object getStaticFieldValueObject (String id){
1291     ClassInfo c = this;
1292     Object v;
1293
1294     while (c != null){
1295       ElementInfo sei = c.getStaticElementInfo();
1296       v = sei.getFieldValueObject(id);
1297       if (v != null){
1298         return v;
1299       }
1300       c = c.getSuperClass();
1301     }
1302
1303     return null;
1304   }
1305
1306   public FieldInfo[] getDeclaredStaticFields() {
1307     return sFields;
1308   }
1309
1310   public FieldInfo[] getDeclaredInstanceFields() {
1311     return iFields;
1312   }
1313
1314   /**
1315    * FieldInfo lookup in the static fields that are declared in this class
1316    * <2do> pcm - should employ a map at some point, but it's usually not that
1317    * important since we can cash the returned FieldInfo in the PUT/GET_STATIC insns
1318    */
1319   public FieldInfo getDeclaredStaticField (String fName) {
1320     for (int i=0; i<sFields.length; i++) {
1321       if (sFields[i].getName().equals(fName)) return sFields[i];
1322     }
1323
1324     return null;
1325   }
1326
1327   /**
1328    * base relative FieldInfo lookup - the workhorse
1329    * <2do> again, should eventually use Maps
1330    * @param fName the field name
1331    */
1332   public FieldInfo getInstanceField (String fName) {
1333     FieldInfo fi;
1334     ClassInfo c = this;
1335
1336     while (c != null) {
1337       fi = c.getDeclaredInstanceField(fName);
1338       if (fi != null) return fi;
1339       c = c.superClass;
1340     }
1341
1342     return null;
1343   }
1344
1345   /**
1346    * FieldInfo lookup in the fields that are declared in this class
1347    */
1348   public FieldInfo getDeclaredInstanceField (String fName) {
1349     for (int i=0; i<iFields.length; i++) {
1350       if (iFields[i].getName().equals(fName)) return iFields[i];
1351     }
1352
1353     return null;
1354   }
1355   
1356   public String getSignature() {
1357     if (signature == null) {
1358       signature = Types.getTypeSignature(name, false);
1359     }
1360     
1361     return signature;     
1362   }
1363
1364   /**
1365    * Returns the name of the class.  e.g. "java.lang.String".  similar to
1366    * java.lang.Class.getName().
1367    */
1368   public String getName () {
1369     return name;
1370   }
1371
1372   public String getSimpleName () {
1373     int i;
1374     String enclosingClassName = getEnclosingClassName();
1375     
1376     if(enclosingClassName!=null){
1377       i = enclosingClassName.length();      
1378     } else{
1379       i = name.lastIndexOf('.');
1380     }
1381     
1382     return name.substring(i+1);
1383   }
1384
1385   public String getPackageName () {
1386     return packageName;
1387   }
1388
1389   public int getId() {
1390     return id;
1391   }
1392
1393   public long getUniqueId() {
1394     return uniqueId;
1395   }
1396
1397   public int getFieldAttrs (int fieldIndex) {
1398     fieldIndex = 0; // Get rid of IDE warning
1399      
1400     return 0;
1401   }
1402
1403   public void setElementInfoAttrs (int attrs){
1404     elementInfoAttrs = attrs;
1405   }
1406
1407   public void addElementInfoAttr (int attr){
1408     elementInfoAttrs |= attr;
1409   }
1410
1411   public int getElementInfoAttrs () {
1412     return elementInfoAttrs;
1413   }
1414
1415   public Source getSource () {
1416     if (source == null) {
1417       source = loadSource();
1418     }
1419
1420     return source;
1421   }
1422
1423   public String getSourceFileName () {
1424     return sourceFileName;
1425   }
1426
1427   /**
1428    * Returns the information about a static field.
1429    */
1430   public FieldInfo getStaticField (int index) {
1431     return sFields[index];
1432   }
1433
1434   /**
1435    * Returns the name of a static field.
1436    */
1437   public String getStaticFieldName (int index) {
1438     return getStaticField(index).getName();
1439   }
1440
1441   /**
1442    * Checks if a static method call is deterministic, but only for
1443    * abtraction based determinism, due to Bandera.choose() calls
1444    */
1445   public boolean isStaticMethodAbstractionDeterministic (ThreadInfo th,
1446                                                          MethodInfo mi) {
1447     //    Reflection r = reflection.instantiate();
1448     //    return r.isStaticMethodAbstractionDeterministic(th, mi);
1449     // <2do> - still has to be implemented
1450      
1451     th = null;  // Get rid of IDE warning
1452     mi = null;
1453      
1454     return true;
1455   }
1456
1457   public String getSuperClassName() {
1458     return superClassName;
1459   }
1460
1461   /**
1462    * Return the super class.
1463    */
1464   public ClassInfo getSuperClass () {
1465     return superClass;
1466   }
1467
1468   /**
1469    * return the ClassInfo for the provided superclass name. If this is equals
1470    * to ourself, return this (a little bit strange if we hit it in the first place)
1471    */
1472   public ClassInfo getSuperClass (String clsName) {
1473     if (clsName.equals(name)) return this;
1474
1475     if (superClass != null) {
1476       return superClass.getSuperClass(clsName);
1477     } else {
1478       return null;
1479     }
1480   }
1481
1482   public int getNumberOfSuperClasses(){
1483     int n = 0;
1484     for (ClassInfo ci = superClass; ci != null; ci = ci.superClass){
1485       n++;
1486     }
1487     return n;
1488   }
1489   
1490   /**
1491    * beware - this loads (but not yet registers) the enclosing class
1492    */
1493   public String getEnclosingClassName(){
1494     return enclosingClassName;
1495   }
1496   
1497   /**
1498    * beware - this loads (but not yet registers) the enclosing class
1499    */
1500   public ClassInfo getEnclosingClassInfo() {
1501     String enclName = getEnclosingClassName();
1502     return (enclName == null ? null : classLoader.getResolvedClassInfo(enclName)); // ? is this supposed to use the same classloader
1503   }
1504
1505   public String getEnclosingMethodName(){
1506     return enclosingMethodName;
1507   }
1508
1509   /**
1510    * same restriction as getEnclosingClassInfo() - might not be registered/initialized
1511    */
1512   public MethodInfo getEnclosingMethodInfo(){
1513     MethodInfo miEncl = null;
1514     
1515     if (enclosingMethodName != null){
1516       ClassInfo ciIncl = getEnclosingClassInfo();
1517       miEncl = ciIncl.getMethod( enclosingMethodName, false);
1518     }
1519     
1520     return miEncl;
1521   }
1522   
1523   /**
1524    * Returns true if the class is a system class.
1525    */
1526   public boolean isSystemClass () {
1527     return name.startsWith("java.") || name.startsWith("javax.");
1528   }
1529
1530   /**
1531    * <2do> that's stupid - we should use subclasses for builtin and box types
1532    */
1533   public boolean isBoxClass () {
1534     if (name.startsWith("java.lang.")) {
1535       String rawType = name.substring(10);
1536       if (rawType.startsWith("Boolean") ||
1537           rawType.startsWith("Byte") ||
1538           rawType.startsWith("Character") ||
1539           rawType.startsWith("Integer") ||
1540           rawType.startsWith("Float") ||
1541           rawType.startsWith("Long") ||
1542           rawType.startsWith("Double")) {
1543         return true;
1544       }
1545     }
1546     return false;
1547   }
1548
1549   /**
1550    * Returns the type of a class.
1551    */
1552   public String getType () {
1553     if (!isArray) {
1554       return "L" + name.replace('.', '/') + ";";
1555     } else {
1556       return name;
1557     }
1558   }
1559
1560   /**
1561    * is this a (subclass of) WeakReference? this must be efficient, since it's
1562    * called in the mark phase on all live objects
1563    */
1564   public boolean isWeakReference () {
1565     return isWeakReference;
1566   }
1567
1568   /**
1569    * note this only returns true is this is really the java.lang.ref.Reference classInfo
1570    */
1571   public boolean isReferenceClassInfo () {
1572     return isRefClassInfo;
1573   }
1574
1575   /**
1576    * whether this refers to a primitive type.
1577    */
1578   public boolean isPrimitive() {
1579     return superClass == null && !isObjectClassInfo();
1580   }
1581
1582
1583   boolean hasRefField (int ref, Fields fv) {
1584     ClassInfo c = this;
1585
1586     do {
1587       FieldInfo[] fia = c.iFields;
1588       for (int i=0; i<fia.length; i++) {
1589         FieldInfo fi = c.iFields[i];
1590         if (fi.isReference() && (fv.getIntValue( fi.getStorageOffset()) == ref)) return true;
1591       }
1592       c = c.superClass;
1593     } while (c != null);
1594
1595     return false;
1596   }
1597
1598   boolean hasImmutableInstances () {
1599     return ((elementInfoAttrs & ElementInfo.ATTR_IMMUTABLE) != 0);
1600   }
1601
1602   public boolean hasInstanceFieldInfoAttr (Class<?> type){
1603     for (int i=0; i<nInstanceFields; i++){
1604       if (getInstanceField(i).hasAttr(type)){
1605         return true;
1606       }
1607     }
1608     
1609     return false;
1610   }
1611   
1612   public NativePeer getNativePeer () {
1613     return nativePeer;
1614   }
1615   
1616   /**
1617    * Returns true if the given class is an instance of the class
1618    * or interface specified.
1619    */
1620   public boolean isInstanceOf (String cname) {
1621     if (isPrimitive()) {
1622       return Types.getJNITypeCode(name).equals(cname);
1623
1624     } else {
1625       cname = Types.getClassNameFromTypeName(cname);
1626       ClassInfo ci = this.classLoader.getResolvedClassInfo(cname);
1627       return isInstanceOf(ci);
1628     }
1629   }
1630
1631   /**
1632    * Returns true if the given class is an instance of the class
1633    * or interface specified.
1634    */
1635   public boolean isInstanceOf (ClassInfo ci) {
1636     if (isPrimitive()) { // no inheritance for builtin types
1637       return (this==ci);
1638     } else {
1639       for (ClassInfo c = this; c != null; c = c.superClass) {
1640         if (c==ci) {
1641           return true;
1642         }
1643       }
1644
1645       return getAllInterfaces().contains(ci);
1646     }
1647   }
1648
1649   public boolean isInnerClassOf (String enclosingName){
1650     // don't register or initialize yet
1651     ClassInfo ciEncl = classLoader.tryGetResolvedClassInfo( enclosingName);
1652     if (ciEncl != null){
1653       return ciEncl.hasInnerClass(name);
1654     } else {
1655       return false;
1656     }
1657   }
1658   
1659   public boolean hasInnerClass (String innerName){
1660     for (int i=0; i<innerClassNames.length; i++){
1661       if (innerClassNames[i].equals(innerName)){
1662         return true;
1663       }
1664     }
1665     
1666     return false;
1667   }
1668
1669
1670   public static String makeModelClassPath (Config config) {
1671     StringBuilder buf = new StringBuilder(256);
1672     String ps = File.pathSeparator;
1673     String v;
1674
1675     for (File f : config.getPathArray("boot_classpath")){
1676       buf.append(f.getAbsolutePath());
1677       buf.append(ps);
1678     }
1679
1680     for (File f : config.getPathArray("classpath")){
1681       buf.append(f.getAbsolutePath());
1682       buf.append(ps);
1683     }
1684
1685     // finally, we load from the standard Java libraries
1686     v = System.getProperty("sun.boot.class.path");
1687     if (v != null) {
1688       buf.append(v);
1689     }
1690     
1691     return buf.toString();
1692   }
1693   
1694   protected static String[] loadArrayInterfaces () {
1695     return new String[] {"java.lang.Cloneable", "java.io.Serializable"};
1696   }
1697
1698   protected static String[] loadBuiltinInterfaces (String type) {
1699     return EMPTY_STRING_ARRAY;
1700   }
1701
1702
1703   /**
1704    * Loads the ClassInfo for named class.
1705    */
1706   void loadInterfaceRec (Set<ClassInfo> set, String[] interfaces) throws ClassInfoException {
1707     if (interfaces != null) {
1708       for (String iname : interfaces) {
1709
1710         ClassInfo ci = classLoader.getResolvedClassInfo(iname);
1711
1712         if (set != null){
1713           set.add(ci);
1714         }
1715
1716         loadInterfaceRec(set, ci.interfaceNames);
1717       }
1718     }
1719   }
1720
1721   int computeInstanceDataOffset () {
1722     if (superClass == null) {
1723       return 0;
1724     } else {
1725       return superClass.getInstanceDataSize();
1726     }
1727   }
1728
1729   int getInstanceDataOffset () {
1730     return instanceDataOffset;
1731   }
1732
1733   ClassInfo getClassBase (String clsBase) {
1734     if ((clsBase == null) || (name.equals(clsBase))) return this;
1735
1736     if (superClass != null) {
1737       return superClass.getClassBase(clsBase);
1738     }
1739
1740     return null; // Eeek - somebody asked for a class that isn't in the base list
1741   }
1742
1743   int computeInstanceDataSize () {
1744     int n = getDataSize( iFields);
1745
1746     for (ClassInfo c=superClass; c!= null; c=c.superClass) {
1747       n += c.getDataSize(c.iFields);
1748     }
1749
1750     return n;
1751   }
1752
1753   public int getInstanceDataSize () {
1754     return instanceDataSize;
1755   }
1756
1757   int getDataSize (FieldInfo[] fields) {
1758     int n=0;
1759     for (int i=0; i<fields.length; i++) {
1760       n += fields[i].getStorageSize();
1761     }
1762
1763     return n;
1764   }
1765
1766   public int getNumberOfDeclaredInstanceFields () {
1767     return iFields.length;
1768   }
1769
1770   public FieldInfo getDeclaredInstanceField (int i) {
1771     return iFields[i];
1772   }
1773
1774   public int getNumberOfInstanceFields () {
1775     return nInstanceFields;
1776   }
1777
1778   public FieldInfo getInstanceField (int i) {
1779     int idx = i - (nInstanceFields - iFields.length);
1780     if (idx >= 0) {
1781       return ((idx < iFields.length) ? iFields[idx] : null);
1782     } else {
1783       return ((superClass != null) ? superClass.getInstanceField(i) : null);
1784     }
1785   }
1786
1787   public FieldInfo[] getInstanceFields(){
1788     FieldInfo[] fields = new FieldInfo[nInstanceFields];
1789     
1790     for (int i=0; i<fields.length; i++){
1791       fields[i] = getInstanceField(i);
1792     }
1793     
1794     return fields;
1795   }
1796
1797   public int getStaticDataSize () {
1798     return staticDataSize;
1799   }
1800
1801   int computeStaticDataSize () {
1802     return getDataSize(sFields);
1803   }
1804
1805   public int getNumberOfStaticFields () {
1806     return sFields.length;
1807   }
1808
1809   protected Source loadSource () {
1810     return Source.getSource(sourceFileName);
1811   }
1812
1813   public static boolean isBuiltinClass (String cname) {
1814     char c = cname.charAt(0);
1815
1816     // array class
1817     if ((c == '[') || cname.endsWith("[]")) {
1818       return true;
1819     }
1820
1821     // primitive type class
1822     if (Character.isLowerCase(c)) {
1823       if ("int".equals(cname) || "byte".equals(cname) ||
1824           "boolean".equals(cname) || "double".equals(cname) ||
1825           "long".equals(cname) || "char".equals(cname) ||
1826           "short".equals(cname) || "float".equals(cname) || "void".equals(cname)) {
1827         return true;
1828       }
1829     }
1830
1831     return false;
1832   }
1833
1834   /**
1835    * set the locations where we look up sources
1836    */
1837   static void setSourceRoots (Config config) {
1838     Source.init(config);
1839   }
1840
1841   /**
1842    * get names of all interfaceNames (transitive, idx.e. incl. bases and super-interfaceNames)
1843    * @return a Set of String interface names
1844    */
1845   public Set<ClassInfo> getAllInterfaces () {
1846     if (allInterfaces == null) {
1847       HashSet<ClassInfo> set = new HashSet<ClassInfo>();
1848
1849       for (ClassInfo ci=this; ci != null; ci=ci.superClass) {
1850         loadInterfaceRec(set, ci.interfaceNames);
1851       }
1852
1853       allInterfaces = Collections.unmodifiableSet(set);
1854     }
1855
1856     return allInterfaces;
1857   }
1858
1859   /**
1860    * get names of directly implemented interfaceNames
1861    */
1862   public String[] getDirectInterfaceNames () {
1863     return interfaceNames;
1864   }
1865
1866   public Set<ClassInfo> getInterfaceClassInfos() {
1867     return interfaces;
1868   }
1869
1870   public Set<ClassInfo> getAllInterfaceClassInfos() {
1871     return getAllInterfaces();
1872   }
1873
1874   
1875   /**
1876    * get names of direct inner classes
1877    */
1878   public String[] getInnerClasses(){
1879     return innerClassNames;
1880   }
1881   
1882   public ClassInfo[] getInnerClassInfos(){
1883     ClassInfo[] innerClassInfos = new ClassInfo[innerClassNames.length];
1884     
1885     for (int i=0; i< innerClassNames.length; i++){
1886       innerClassInfos[i] = classLoader.getResolvedClassInfo(innerClassNames[i]); // ? is this supposed to use the same classloader
1887     }
1888     
1889     return innerClassInfos;
1890   }
1891   
1892   public BootstrapMethodInfo getBootstrapMethodInfo(int index) {
1893     return bootstrapMethods[index];
1894   }
1895
1896   public ClassInfo getComponentClassInfo () {
1897     if (isArray()) {
1898       String cn = name.substring(1);
1899
1900       if (cn.charAt(0) != '[') {
1901         cn = Types.getTypeName(cn);
1902       }
1903
1904       ClassInfo cci = classLoader.getResolvedClassInfo(cn);
1905
1906       return cci;
1907     }
1908
1909     return null;
1910   }
1911
1912   /**
1913    * most definitely not a public method, but handy for the NativePeer
1914    */
1915   protected Map<String, MethodInfo> getDeclaredMethods () {
1916     return methods;
1917   }
1918
1919   /**
1920    * be careful, this replaces or adds MethodInfos dynamically
1921    */
1922   public MethodInfo putDeclaredMethod (MethodInfo mi){
1923     return methods.put(mi.getUniqueName(), mi);
1924   }
1925
1926   public MethodInfo[] getDeclaredMethodInfos() {
1927     MethodInfo[] a = new MethodInfo[methods.size()];
1928     methods.values().toArray(a);
1929     return a;
1930   }
1931
1932   public Instruction[] getMatchingInstructions (LocationSpec lspec){
1933     Instruction[] insns = null;
1934
1935     if (lspec.matchesFile(sourceFileName)){
1936       for (MethodInfo mi : methods.values()) {
1937         Instruction[] a = mi.getMatchingInstructions(lspec);
1938         if (a != null){
1939           if (insns != null) {
1940             // not very efficient but probably rare
1941             insns = Misc.appendArray(insns, a);
1942           } else {
1943             insns = a;
1944           }
1945
1946           // little optimization
1947           if (!lspec.isLineInterval()) {
1948             break;
1949           }
1950         }
1951       }
1952     }
1953
1954     return insns;
1955   }
1956
1957   public List<MethodInfo> getMatchingMethodInfos (MethodSpec mspec){
1958     ArrayList<MethodInfo> list = null;
1959     if (mspec.matchesClass(name)) {
1960       for (MethodInfo mi : methods.values()) {
1961         if (mspec.matches(mi)) {
1962           if (list == null) {
1963             list = new ArrayList<MethodInfo>();
1964           }
1965           list.add(mi);
1966         }
1967       }
1968     }
1969     return list;
1970   }
1971
1972   public MethodInfo getFinalizer () {
1973     return finalizer;
1974   }
1975
1976   public MethodInfo getClinit() {
1977     // <2do> braindead - cache
1978     for (MethodInfo mi : methods.values()) {
1979       if ("<clinit>".equals(mi.getName())) {
1980         return mi;
1981       }
1982     }
1983     return null;
1984   }
1985
1986   public boolean hasCtors() {
1987     // <2do> braindead - cache
1988     for (MethodInfo mi : methods.values()) {
1989       if ("<init>".equals(mi.getName())) {
1990         return true;
1991       }
1992     }
1993     return false;
1994   }
1995
1996   /**
1997    * see getInitializedClassInfo() for restrictions.
1998    */
1999   public static ClassInfo getInitializedSystemClassInfo (String clsName, ThreadInfo ti){
2000     ClassLoaderInfo systemLoader = ClassLoaderInfo.getCurrentSystemClassLoader();
2001     ClassInfo ci = systemLoader.getResolvedClassInfo(clsName);
2002     ci.initializeClassAtomic(ti);
2003
2004     return ci;
2005   }
2006
2007   /**
2008    * this one is for clients that need to synchronously get an initialized classinfo.
2009    * NOTE: we don't handle clinits here. If there is one, this will throw
2010    * an exception. NO STATIC BLOCKS / FIELDS ALLOWED
2011    */
2012   public static ClassInfo getInitializedClassInfo (String clsName, ThreadInfo ti){
2013     ClassLoaderInfo cl = ClassLoaderInfo.getCurrentClassLoader();
2014     ClassInfo ci = cl.getResolvedClassInfo(clsName);
2015     ci.initializeClassAtomic(ti);
2016
2017     return ci;
2018   }
2019
2020   public boolean isRegistered () {
2021     //return (id != -1);
2022     return getStaticElementInfo() != null;
2023   }
2024   
2025   /**
2026    * this registers a ClassInfo in the corresponding ClassLoader statics so that we can cross-link from
2027    * SUT code and access static fields.
2028    */
2029   public StaticElementInfo registerClass (ThreadInfo ti){
2030     StaticElementInfo sei = getStaticElementInfo();
2031     
2032     if (sei == null) {
2033       // do this recursively for superclasses and interfaceNames
2034       // respective classes might be defined by another classloader, so we have to call their ClassInfo.registerClass()
2035       
2036       if (superClass != null) {
2037         superClass.registerClass(ti);
2038       }
2039
2040       for (ClassInfo ifc : interfaces) {
2041         ifc.registerClass(ti);
2042       }
2043       
2044       ClassInfo.logger.finer("registering class: ", name);
2045       
2046       ElementInfo ei = createClassObject( ti);
2047       sei = createAndLinkStaticElementInfo( ti, ei);
2048       
2049       // SUT class is fully resolved and registered (but not necessarily initialized), notify listeners
2050       ti.getVM().notifyClassLoaded(this);
2051     }
2052     
2053     return sei;
2054   }
2055
2056   ElementInfo createClassObject (ThreadInfo ti){
2057     Heap heap = VM.getVM().getHeap(); // ti can be null (during main thread initialization)
2058
2059     int anchor = name.hashCode(); // 2do - this should also take the ClassLoader ref into account
2060
2061     SystemClassLoaderInfo systemClassLoader = ti.getSystemClassLoaderInfo();
2062
2063     ClassInfo classClassInfo = systemClassLoader.getClassClassInfo();    
2064     ElementInfo ei = heap.newSystemObject(classClassInfo, ti, anchor);
2065     int clsObjRef = ei.getObjectRef();
2066     
2067     ElementInfo eiClsName = heap.newSystemString(name, ti, clsObjRef);
2068     ei.setReferenceField("name", eiClsName.getObjectRef());
2069
2070     ei.setBooleanField("isPrimitive", isPrimitive());
2071     
2072     // setting the ID_FIELD is done in registerClass once we have a StaticElementInfo
2073
2074     // link the SUT class object to the classloader 
2075     ei.setReferenceField("classLoader", classLoader.getClassLoaderObjectRef());
2076     
2077     return ei;
2078   }
2079   
2080   StaticElementInfo createAndLinkStaticElementInfo (ThreadInfo ti, ElementInfo eiClsObj) {
2081     Statics statics = classLoader.getStatics();
2082     StaticElementInfo sei = statics.newClass(this, ti, eiClsObj);
2083     
2084     id = sei.getObjectRef();  // kind of a misnomer, it's really an id    
2085     uniqueId = ((long)classLoader.getId() << 32) | id;
2086     
2087     eiClsObj.setIntField( ID_FIELD, id);      
2088     
2089     return sei;
2090   }
2091
2092   
2093   // for startup classes, the order of initialization is reversed since we can't create
2094   // heap objects before we have a minimal set of registered classes
2095   
2096   void registerStartupClass(ThreadInfo ti, List<ClassInfo> list) {
2097     if (!isRegistered()) {
2098       // do this recursively for superclasses and interfaceNames
2099       // respective classes might be defined by another classloader, so we have
2100       // to call their ClassInfo.registerClass()
2101
2102       if (superClass != null) {
2103         superClass.registerStartupClass(ti, list);
2104       }
2105
2106       for (ClassInfo ifc : interfaces) {
2107         ifc.registerStartupClass(ti, list);
2108       }
2109     }
2110
2111     if (!list.contains(this)) {
2112       list.add(this);
2113       ClassInfo.logger.finer("registering startup class: ", name);
2114       createStartupStaticElementInfo(ti);
2115     }
2116     
2117       // SUT class is fully resolved and registered (but not necessarily initialized), notify listeners
2118       ti.getVM().notifyClassLoaded(this);
2119   }
2120   
2121   StaticElementInfo createStartupStaticElementInfo (ThreadInfo ti) {
2122     Statics statics = classLoader.getStatics();
2123     StaticElementInfo sei = statics.newStartupClass(this, ti);
2124     
2125     id = sei.getObjectRef();  // kind of a misnomer, it's really an id    
2126     uniqueId = ((long)classLoader.getId() << 32) | id;
2127     
2128     return sei;
2129   }
2130   
2131   ElementInfo createAndLinkStartupClassObject (ThreadInfo ti) {
2132     StaticElementInfo sei = getStaticElementInfo();
2133     ElementInfo ei = createClassObject(ti);
2134     
2135     sei.setClassObjectRef(ei.getObjectRef());
2136     ei.setIntField( ID_FIELD, id);      
2137     
2138     return ei;
2139   }
2140   
2141   boolean checkIfValidClassClassInfo() {
2142     return getDeclaredInstanceField( ID_FIELD) != null;
2143   }
2144   
2145   public boolean isInitializing () {
2146     StaticElementInfo sei = getStaticElementInfo();
2147     return ((sei != null) && (sei.getStatus() >= 0));
2148   }
2149
2150   /**
2151    * note - this works recursively upwards since there might
2152    * be a superclass with a clinit that is still executing
2153    */
2154   public boolean isInitialized () {
2155     for (ClassInfo ci = this; ci != null; ci = ci.superClass){
2156       StaticElementInfo sei = ci.getStaticElementInfo();
2157       if (sei == null || sei.getStatus() != INITIALIZED){
2158         return false;
2159       }
2160     }
2161     
2162     return true;
2163   }
2164
2165   public boolean isResolved () {
2166     return (!isObjectClassInfo() && superClass != null);
2167   }
2168
2169   public boolean needsInitialization (ThreadInfo ti){
2170     StaticElementInfo sei = getStaticElementInfo();
2171     if (sei != null){
2172       int status = sei.getStatus();
2173       if (status == INITIALIZED || status == ti.getId()){
2174         return false;
2175       }
2176     }
2177
2178     return true;
2179   }
2180
2181   public void setInitializing(ThreadInfo ti) {
2182     StaticElementInfo sei = getModifiableStaticElementInfo();
2183     sei.setStatus(ti.getId());
2184   }
2185   
2186   /**
2187    * initialize this class and its superclasses (but not interfaces)
2188    * this will cause execution of clinits of not-yet-initialized classes in this hierarchy
2189    *
2190    * note - we don't treat registration/initialization of a class as
2191    * a sharedness-changing operation since it is done automatically by
2192    * the VM and the triggering action in the SUT (e.g. static field access or method call)
2193    * is the one that should update sharedness and/or break the transition accordingly
2194    *
2195    * @return true - if initialization pushed DirectCallStackFrames and caller has to re-execute
2196    */
2197   public boolean initializeClass(ThreadInfo ti){
2198     int pushedFrames = 0;
2199
2200     // push clinits of class hierarchy (upwards, since call stack is LIFO)
2201     for (ClassInfo ci = this; ci != null; ci = ci.getSuperClass()) {
2202       StaticElementInfo sei = ci.getStaticElementInfo();
2203       if (sei == null){
2204         sei = ci.registerClass(ti);
2205       }
2206
2207       int status = sei.getStatus();
2208       if (status != INITIALIZED){
2209         // we can't do setInitializing() yet because there is no global lock that
2210         // covers the whole clinit chain, and we might have a context switch before executing
2211         // a already pushed subclass clinit - there can be races as to which thread
2212         // does the static init first. Note this case is checked in INVOKECLINIT
2213         // (which is one of the reasons why we have it).
2214
2215         if (status != ti.getId()) {
2216           // even if it is already initializing - if it does not happen in the current thread
2217           // we have to sync, which we do by calling clinit
2218           MethodInfo mi = ci.getMethod("<clinit>()V", false);
2219           if (mi != null) {
2220             DirectCallStackFrame frame = ci.createDirectCallStackFrame(ti, mi, 0);
2221             ti.pushFrame( frame);
2222             pushedFrames++;
2223
2224           } else {
2225             // it has no clinit, we can set it initialized
2226             ci.setInitialized();
2227           }
2228         } else {
2229           // ignore if it's already being initialized  by our own thread (recursive request)
2230         }
2231       } else {
2232         break; // if this class is initialized, so are its superclasses
2233       }
2234     }
2235
2236     return (pushedFrames > 0);
2237   }
2238
2239   /**
2240    * use this with care since it will throw a JPFException if we encounter a choice point
2241    * during execution of clinits
2242    * Use this mostly for wrapper exceptions and other system classes that are guaranteed to load
2243    */
2244   public void initializeClassAtomic (ThreadInfo ti){
2245     for (ClassInfo ci = this; ci != null; ci = ci.getSuperClass()) {
2246       StaticElementInfo sei = ci.getStaticElementInfo();
2247       if (sei == null){
2248         sei = ci.registerClass(ti);
2249       }
2250
2251       int status = sei.getStatus();
2252       if (status != INITIALIZED && status != ti.getId()){
2253           MethodInfo mi = ci.getMethod("<clinit>()V", false);
2254           if (mi != null) {
2255             DirectCallStackFrame frame = ci.createDirectCallStackFrame(ti, mi, 0);
2256             ti.executeMethodAtomic(frame);
2257           } else {
2258             ci.setInitialized();
2259           }
2260       } else {
2261         break; // if this class is initialized, so are its superclasses
2262       }
2263     }
2264   }
2265
2266   public void setInitialized() {
2267     StaticElementInfo sei = getStaticElementInfo();
2268     if (sei != null && sei.getStatus() != INITIALIZED){
2269       sei = getModifiableStaticElementInfo();
2270       sei.setStatus(INITIALIZED);
2271
2272       // we don't emit classLoaded() notifications for non-builtin classes
2273       // here anymore because it would be confusing to get instructionExecuted()
2274       // notifications from the <clinit> execution before the classLoaded()
2275     }
2276   }
2277
2278   public StaticElementInfo getStaticElementInfo() {
2279     if (id != -1) {
2280       return classLoader.getStatics().get( id);
2281     } else {
2282       return null;
2283     }
2284   }
2285
2286   public StaticElementInfo getModifiableStaticElementInfo() {
2287     if (id != -1) {
2288       return classLoader.getStatics().getModifiable( id);
2289     } else {
2290       return null;      
2291     }
2292   }
2293
2294   Fields createArrayFields (String type, int nElements, int typeSize, boolean isReferenceArray) {
2295     return fieldsFactory.createArrayFields( type, this,
2296                                             nElements, typeSize, isReferenceArray);
2297   }
2298
2299   /**
2300    * Creates the fields for a class.  This gets called during registration of a ClassInfo
2301    */
2302   Fields createStaticFields () {
2303     return fieldsFactory.createStaticFields(this);
2304   }
2305
2306   void initializeStaticData (ElementInfo ei, ThreadInfo ti) {
2307     for (int i=0; i<sFields.length; i++) {
2308       FieldInfo fi = sFields[i];
2309       fi.initialize(ei, ti);
2310     }
2311   }
2312
2313   /**
2314    * Creates the fields for an object.
2315    */
2316   public Fields createInstanceFields () {
2317     return fieldsFactory.createInstanceFields(this);
2318   }
2319
2320   void initializeInstanceData (ElementInfo ei, ThreadInfo ti) {
2321     // Note this is only used for field inits, and array elements are not fields!
2322     // Since Java has only limited element init requirements (either 0 or null),
2323     // we do this ad hoc in the ArrayFields ctor
2324
2325     // the order of inits should not matter, since this is only
2326     // for constant inits. In case of a "class X { int a=42; int b=a; ..}"
2327     // we have a explicit "GETFIELD a, PUTFIELD b" in the ctor, but to play it
2328     // safely we init top down
2329
2330     if (superClass != null) { // do superclasses first
2331       superClass.initializeInstanceData(ei, ti);
2332     }
2333
2334     for (int i=0; i<iFields.length; i++) {
2335       FieldInfo fi = iFields[i];
2336       fi.initialize(ei, ti);
2337     }
2338   }
2339
2340   Map<String, MethodInfo> loadArrayMethods () {
2341     return new HashMap<String, MethodInfo>(0);
2342   }
2343
2344   Map<String, MethodInfo> loadBuiltinMethods (String type) {
2345     type = null;  // Get rid of IDE warning 
2346      
2347     return new HashMap<String, MethodInfo>(0);
2348   }
2349
2350   protected ClassInfo loadSuperClass (String superName) throws ClassInfoException {
2351     if (isObjectClassInfo()) {
2352       return null;
2353     }
2354
2355     logger.finer("resolving superclass: ", superName, " of ", name);
2356
2357     // resolve the superclass
2358     ClassInfo sci = resolveReferencedClass(superName);
2359
2360     return sci;
2361   }
2362
2363   protected Set<ClassInfo> loadInterfaces (String[] ifcNames) throws ClassInfoException {
2364     if (ifcNames == null || ifcNames.length == 0){
2365       return NO_INTERFACES;
2366       
2367     } else {
2368       Set<ClassInfo> set = new HashSet<ClassInfo>();
2369
2370       for (String ifcName : ifcNames) {
2371         ClassInfo.logger.finer("resolving interface: ", ifcName, " of ", name);
2372         ClassInfo ifc = resolveReferencedClass(ifcName);
2373         set.add(ifc);
2374       }
2375
2376       return set;
2377     }
2378   }
2379   
2380   /**
2381    * loads superclass and direct interfaces, and computes information
2382    * that depends on them
2383    */
2384   protected void resolveClass() {
2385     if (!isObjectClassInfo){
2386       superClass = loadSuperClass(superClassName);
2387       releaseActions = superClass.releaseActions;
2388     }
2389     interfaces = loadInterfaces(interfaceNames);
2390
2391     //computeInheritedAnnotations(superClass);
2392
2393     isWeakReference = isWeakReference0();
2394     isEnum = isEnum0();
2395   }
2396
2397   /**
2398    * get a ClassInfo for a referenced type that is resolved with the same classLoader, but make
2399    * sure we only do this once per path
2400    * 
2401    * This method is called by the following bytecode instructions:
2402    * anewarray, checkcast, getstatic, instanceof, invokespecial, 
2403    * invokestatic, ldc, ldc_w, multianewarray, new, and putstatic
2404    * 
2405    * It loads the class referenced by these instructions and adds it to the 
2406    * resolvedClasses map of the classLoader
2407    */
2408   public ClassInfo resolveReferencedClass(String cname) {
2409     if(name.equals(cname)) {
2410       return this;
2411     }
2412
2413     // if the class has been already resolved just return it
2414     ClassInfo ci = classLoader.getAlreadyResolvedClassInfo(cname);
2415     if(ci != null) {
2416       return ci;
2417     }
2418  
2419     // The defining class loader of the class initiate the load of referenced classes
2420     ci = classLoader.loadClass(cname);
2421     classLoader.addResolvedClass(ci);
2422
2423     return ci;
2424   }
2425
2426   protected int linkFields (FieldInfo[] fields, int idx, int off){
2427     for (FieldInfo fi: fields) {      
2428       fi.linkToClass(this, idx, off);
2429       
2430       int storageSize = fi.getStorageSize();      
2431       off += storageSize;
2432       idx++;
2433     }
2434     
2435     return off;
2436   }
2437   
2438   protected void linkFields() {
2439     //--- instance fields
2440     if(superClass != null) {
2441       int superDataSize = superClass.instanceDataSize;
2442       instanceDataSize = linkFields( iFields,  superClass.nInstanceFields, superDataSize);
2443       nInstanceFields = superClass.nInstanceFields + iFields.length;
2444       instanceDataOffset = superClass.instanceDataSize;
2445       
2446     } else {
2447       instanceDataSize = linkFields( iFields, 0, 0);
2448       nInstanceFields = iFields.length;
2449       instanceDataOffset = 0;
2450     }
2451     
2452     //--- static fields
2453     staticDataSize = linkFields( sFields, 0, 0);
2454   }
2455
2456   // this resolves all annotations in this class hierarchy, which sets inherited attributes
2457   protected void checkInheritedAnnotations (){
2458     
2459   }
2460   
2461   @Override
2462   public String toString() {
2463     return "ClassInfo[name=" + name + "]";
2464   }
2465
2466   protected MethodInfo getFinalizer0 () {
2467     MethodInfo mi = getMethod("finalize()V", true);
2468
2469     // we are only interested in non-empty method bodies, Object.finalize()
2470     // is a dummy
2471     if ((mi != null) && (!mi.getClassInfo().isObjectClassInfo())) {
2472       return mi;
2473     }
2474
2475     return null;
2476   }
2477
2478   protected boolean isObjectClassInfo0 () {
2479         if (name.equals("java.lang.Object")) {
2480           return true;
2481         }
2482         return false;
2483   }
2484
2485   protected boolean isStringClassInfo0 () {
2486     if(name.equals("java.lang.String")) {
2487       return true;
2488     }
2489     return false;
2490   }
2491
2492   protected boolean isRefClassInfo0 () {
2493     if(name.equals("java.lang.ref.Reference")) {
2494       return true;
2495     }
2496     return false;
2497   }
2498
2499   protected boolean isWeakReference0 () {
2500         if(name.equals("java.lang.ref.WeakReference")) {
2501       return true;
2502         }
2503
2504     for (ClassInfo ci = this; !ci.isObjectClassInfo(); ci = ci.superClass) {
2505       if (ci.isWeakReference()) {
2506         return true;
2507       }
2508     }
2509
2510     return false;
2511   }
2512
2513   protected boolean isEnum0 () {
2514         if(name.equals("java.lang.Enum")) {
2515       return true;
2516         }
2517
2518     for (ClassInfo ci = this; !ci.isObjectClassInfo(); ci = ci.superClass) {
2519       if (ci.isEnum()) {
2520         return true;
2521       }
2522     }
2523
2524     return false;
2525   }
2526
2527   protected boolean isThreadClassInfo0 () {
2528     if(name.equals("java.lang.Thread")) {
2529       return true;
2530     }
2531     return false;
2532   }
2533
2534
2535   /**
2536    * It creates an instance from a original ClassInfo instance. It doesn't copy sei & 
2537    * uniqueId.
2538    * 
2539    * It is used for the cases where cl tries to load a class that the original version 
2540    * of which has been loaded by some other classloader.
2541    */
2542   public ClassInfo cloneFor (ClassLoaderInfo cl) {
2543     ClassInfo ci;
2544
2545     try {
2546       ci = (ClassInfo)clone();
2547
2548       ci.classLoader = cl;
2549       ci.interfaces = new HashSet<ClassInfo>();
2550       ci.resolveClass();
2551
2552       ci.id = -1;
2553       ci.uniqueId = -1;
2554
2555       if (methods != Collections.EMPTY_MAP){
2556         ci.methods = (Map<String, MethodInfo>)((HashMap<String, MethodInfo>) methods).clone();
2557       }
2558
2559       for(Map.Entry<String, MethodInfo> e: ci.methods.entrySet()) {
2560         MethodInfo mi = e.getValue();
2561         e.setValue(mi.getInstanceFor(ci));
2562       }
2563
2564       ci.iFields = new FieldInfo[iFields.length];
2565       for(int i=0; i<iFields.length; i++) {
2566         ci.iFields[i] = iFields[i].getInstanceFor(ci);
2567       }
2568
2569       ci.sFields = new FieldInfo[sFields.length];
2570       for(int i=0; i<sFields.length; i++) {
2571         ci.sFields[i] = sFields[i].getInstanceFor(ci);
2572       }
2573
2574       if(nativePeer != null) {
2575         ci.nativePeer = NativePeer.getNativePeer(ci);
2576       }
2577
2578       ci.setAssertionStatus();
2579
2580     } catch (CloneNotSupportedException cnsx){
2581       cnsx.printStackTrace();
2582       return null;
2583     }
2584
2585     VM.getVM().notifyClassLoaded(ci);
2586     return ci;
2587   }
2588   
2589   // <2do> should be abstract
2590   public StackFrame createStackFrame (ThreadInfo ti, MethodInfo callee){
2591     return null;
2592   }
2593   
2594   public DirectCallStackFrame createDirectCallStackFrame (ThreadInfo ti, MethodInfo callee, int nLocalSlots){
2595     return null;
2596   }
2597   
2598   public DirectCallStackFrame createRunStartStackFrame (ThreadInfo ti, MethodInfo miRun){
2599     return null;
2600   }
2601
2602   // TODO: Fix for Groovy's model-checking
2603   public String[] getGenericTypeVariableNames () {
2604     // To accommodate methods that do not have generic types
2605     if (genericSignature == null || genericSignature.equals(""))
2606       return new String[0];
2607     return Types.getGenericTypeVariableNames(genericSignature);
2608   }
2609 }
2610
2611