2 * Copyright (C) 2014, United States Government, as represented by the
3 * Administrator of the National Aeronautics and Space Administration.
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
10 * http://www.apache.org/licenses/LICENSE-2.0.
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.
18 package gov.nasa.jpf.vm;
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;
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;
42 import java.util.NoSuchElementException;
44 import java.util.logging.Level;
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
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)
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
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
70 public class ClassInfo extends InfoObject implements Iterable<MethodInfo>, GenericSignatureHolder {
72 //--- ClassInfo states, in chronological order
73 // note the somewhat strange, decreasing values - >= 0 (=thread-id) means
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)
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;
87 protected static final String ID_FIELD = "nativeId";
89 protected static JPFLogger logger = JPF.getLogger("class");
91 protected static int nClassInfos; // for statistics
93 protected static Config config;
96 * ClassLoader that loaded this class.
98 protected static final ClassLoader thisClassLoader = ClassInfo.class.getClassLoader();
101 * our abstract factory to createAndInitialize object and class fields
103 protected static FieldsFactory fieldsFactory;
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>();
113 * support to auto-load listeners from annotations
115 protected static HashSet<String> autoloadAnnotations;
116 protected static HashSet<String> autoloaded;
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"
123 protected String name;
125 /** type erased signature of the class. e.g. "Ljava/lang/String;" */
126 protected String signature;
128 /** Generic type signatures of the class as per para. 4.4.4 of the revised VM spec */
129 protected String genericSignature;
131 /** The classloader that defined (directly loaded) this class */
132 protected ClassLoaderInfo classLoader;
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;
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;
151 protected MethodInfo finalizer = null;
153 /** type based object attributes (for GC, partial order reduction and
156 protected int elementInfoAttrs = 0;
159 * all our declared declaredMethods (we don't flatten, this is not
160 * a high-performance VM)
162 protected Map<String, MethodInfo> methods;
165 * our instance fields.
166 * Note these are NOT flattened, idx.e. only contain the declared ones
168 protected FieldInfo[] iFields;
170 /** the storage size of instances of this class (stored as an int[]) */
171 protected int instanceDataSize;
173 /** where in the instance data array (int[]) do our declared fields start */
174 protected int instanceDataOffset;
176 /** total number of instance fields (flattened, not only declared ones) */
177 protected int nInstanceFields;
180 * our static fields. Again, not flattened
182 protected FieldInfo[] sFields;
184 /** the storage size of static fields of this class (stored as an int[]) */
185 protected int staticDataSize;
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
192 protected ClassInfo superClass;
193 protected String superClassName;
195 protected String enclosingClassName;
196 protected String enclosingMethodName;
198 protected String[] innerClassNames = EMPTY_STRING_ARRAY;
199 protected BootstrapMethodInfo[] bootstrapMethods;
201 /** direct ifcs implemented by this class */
202 protected String[] interfaceNames;
204 protected Set<ClassInfo> interfaces = new HashSet<ClassInfo>();
206 /** cache of all interfaceNames (parent interfaceNames and interface parents) - lazy eval */
207 protected Set<ClassInfo> allInterfaces;
209 /** Name of the package. */
210 protected String packageName;
212 /** this is only set if the classfile has a SourceFile class attribute */
213 protected String sourceFileName;
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
219 protected String classFileUrl;
221 /** from where the corresponding classfile was loaded (if this is not a builtin) */
222 protected gov.nasa.jpf.vm.ClassFileContainer container;
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
229 protected int id = -1;
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
235 * NOTE - since this is based on the classloader-specific id, it can't be used before the ClassInfo is registered
237 protected long uniqueId = -1;
240 * this is the object we use to enter declaredMethods in the underlying VM
241 * (it replaces Reflection)
243 protected NativePeer nativePeer;
245 /** Source file associated with the class.*/
246 protected Source source;
248 protected boolean enableAssertions;
250 /** actions to be taken when an object of this type is gc'ed */
251 protected ImmutableList<ReleaseAction> releaseActions;
254 static boolean init (Config config) {
256 ClassInfo.config = config;
258 setSourceRoots(config);
259 //buildBCELModelClassPath(config);
261 fieldsFactory = config.getEssentialInstance("vm.fields_factory.class",
262 FieldsFactory.class);
264 autoloadAnnotations = config.getNonEmptyStringSet("listener.autoload");
265 if (autoloadAnnotations != null) {
266 autoloaded = new HashSet<String>();
268 if (logger.isLoggable(Level.INFO)) {
269 for (String s : autoloadAnnotations){
270 logger.info("watching for autoload annotation @" + s);
278 public static boolean isObjectClassInfo (ClassInfo ci){
279 return ci.isObjectClassInfo();
282 public static boolean isStringClassInfo (ClassInfo ci){
283 return ci.isStringClassInfo();
287 //--- initialization interface towards parsers (which might reside in other packages)
289 protected void setClass(String clsName, String superClsName, int flags, int cpCount) throws ClassParseException {
290 String parsedName = Types.getClassNameFromTypeName(clsName);
292 if (name != null && !name.equals(parsedName)){
293 throw new ClassParseException("wrong class name (expected: " + name + ", found: " + parsedName + ')');
297 // the enclosingClassName is set on demand since it requires loading enclosing class candidates
298 // to verify their innerClass attributes
300 int i = name.lastIndexOf('.');
301 packageName = (i > 0) ? name.substring(0, i) : "";
305 // annotations are interfaces too (not exposed by Modifier)
306 isClass = ((flags & Modifier.INTERFACE) == 0);
308 superClassName = superClsName;
311 public void setInnerClassNames(String[] clsNames) {
312 innerClassNames = clsNames;
315 public void setEnclosingClass (String clsName) {
316 enclosingClassName = clsName;
319 public void setEnclosingMethod (String mthName){
320 enclosingMethodName = mthName;
323 public void setInterfaceNames(String[] ifcNames) {
324 interfaceNames = ifcNames;
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;
333 sourceFileName = fileName;
337 public void setFields(FieldInfo[] fields) {
339 iFields = EMPTY_FIELDINFO_ARRAY;
340 sFields = EMPTY_FIELDINFO_ARRAY;
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()) {
352 FieldInfo[] instanceFields = (nInstance > 0) ? new FieldInfo[nInstance] : EMPTY_FIELDINFO_ARRAY;
353 FieldInfo[] staticFields = (nStatic > 0) ? new FieldInfo[nStatic] : EMPTY_FIELDINFO_ARRAY;
357 for (int i = 0; i < fields.length; i++) {
358 FieldInfo fi = fields[i];
361 staticFields[iStatic++] = fi;
363 instanceFields[iInstance++] = fi;
366 processJPFAnnotations(fi);
369 iFields = instanceFields;
370 sFields = staticFields;
372 // we can't link the fields yet because we need the superclasses to be resolved
376 protected void setMethod (MethodInfo mi){
377 mi.linkToClass(this);
378 methods.put( mi.getUniqueName(), mi);
379 processJPFAnnotations(mi);
382 public void setMethods (MethodInfo[] newMethods) {
383 if (newMethods != null && newMethods.length > 0) {
384 methods = new LinkedHashMap<String, MethodInfo>();
386 for (int i = 0; i < newMethods.length; i++) {
387 setMethod( newMethods[i]);
392 protected void processJPFAttrAnnotation(InfoObject infoObj){
393 AnnotationInfo ai = infoObj.getAnnotation("gov.nasa.jpf.annotation.JPFAttribute");
395 String[] attrTypes = ai.getValueAsStringArray();
396 if (attrTypes != null){
397 ClassLoader loader = config.getClassLoader();
399 for (String clsName : attrTypes){
401 Class<?> attrCls = loader.loadClass(clsName);
402 Object attr = attrCls.newInstance(); // needs to have a default ctor
403 infoObj.addAttr(attr);
405 } catch (ClassNotFoundException cnfx){
406 logger.warning("attribute class not found: " + clsName);
408 } catch (IllegalAccessException iax){
409 logger.warning("attribute class has no public default ctor: " + clsName);
411 } catch (InstantiationException ix){
412 logger.warning("attribute class has no default ctor: " + clsName);
419 protected void processNoJPFExecutionAnnotation(InfoObject infoObj) {
420 AnnotationInfo ai = infoObj.getAnnotation("gov.nasa.jpf.annotation.NoJPFExecution");
422 infoObj.addAttr(NoJPFExec.SINGLETON);
426 protected void processJPFAnnotations(InfoObject infoObj) {
427 processJPFAttrAnnotation(infoObj);
428 processNoJPFExecutionAnnotation(infoObj);
431 public AnnotationInfo getResolvedAnnotationInfo (String typeName){
432 return classLoader.getResolvedAnnotationInfo( typeName);
436 public void setAnnotations(AnnotationInfo[] annotations) {
437 this.annotations = annotations;
440 //--- end initialization interface
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)
446 public boolean hasAnnotations(){
447 if (annotations.length > 0){
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()){
464 * return all annotations, which includes the ones inherited from our superclasses
465 * NOTE - this is not very efficient
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()){
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];
491 return allAnnotations;
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)){
503 for (ClassInfo ci = superClass; ci != null; ci = ci.superClass){
505 for (int i=0; i<a.length; i++){
506 AnnotationInfo ai = a[i];
507 if (ai.getName().equals(annotationName) && ai.isInherited()){
516 protected ClassInfo (String name, ClassLoaderInfo cli, String classFileUrl){
520 this.classLoader = cli;
521 this.classFileUrl = classFileUrl;
523 this.methods = NO_METHODS; // yet
525 // rest has to be initialized by concrete ctor, which should call resolveAndLink(parser)
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
532 protected void resolveAndLink () throws ClassParseException {
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();
543 finalizer = getFinalizer0();
545 resolveClass(); // takes care of super classes and interfaces
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();
553 linkFields(); // computes field offsets
555 setAssertionStatus();
556 processJPFConfigAnnotation();
557 processJPFAnnotations(this);
558 loadAnnotationListeners();
561 protected ClassInfo(){
564 // for explicit subclass initialization
568 * ClassInfo ctor used for builtin types (arrays and primitive types)
569 * idx.e. classes we don't have class files for
571 protected ClassInfo (String builtinClassName, ClassLoaderInfo classLoader) {
574 this.classLoader = classLoader;
576 isArray = (builtinClassName.charAt(0) == '[');
577 isReferenceArray = isArray && (builtinClassName.endsWith(";") || builtinClassName.charAt(1) == '[');
580 name = builtinClassName;
582 logger.log(Level.FINE, "generating builtin class: %1$s", name);
584 packageName = ""; // builtin classes don't reside in java.lang !
585 sourceFileName = null;
587 genericSignature = "";
590 iFields = EMPTY_FIELDINFO_ARRAY;
591 sFields = EMPTY_FIELDINFO_ARRAY;
594 if(classLoader.isSystemClassLoader()) {
595 superClass = ((SystemClassLoaderInfo)classLoader).getObjectClassInfo();
597 superClass = ClassLoaderInfo.getCurrentSystemClassLoader().getObjectClassInfo();
599 interfaceNames = loadArrayInterfaces();
600 methods = loadArrayMethods();
602 superClass = null; // strange, but true, a 'no object' class
603 interfaceNames = loadBuiltinInterfaces(name);
604 methods = loadBuiltinMethods(name);
607 enableAssertions = true; // doesn't really matter - no code associated
611 // no fields or declaredMethods, so we don't have to link/resolve anything
614 public static int getNumberOfLoadedClasses(){
618 //--- the VM type specific methods
619 // <2do> those should be abstract
621 protected void setAnnotationValueGetterCode (MethodInfo pmi, FieldInfo fi){
622 // to be overridden by VM specific class
625 protected void setDirectCallCode (MethodInfo miCallee, MethodInfo miStub){
626 // to be overridden by VM specific class
629 protected void setLambdaDirectCallCode (MethodInfo miDirectCall, BootstrapMethodInfo bootstrapMethod){
630 // to be overridden by VM specific class
633 protected void setNativeCallCode (NativeMethodInfo miNative){
634 // to be overridden by VM specific class
637 protected void setRunStartCode (MethodInfo miStub, MethodInfo miRun){
638 // to be overridden by VM specific class
642 * createAndInitialize a fully synthetic implementation of an Annotation proxy
644 protected ClassInfo (ClassInfo annotationCls, String name, ClassLoaderInfo classLoader, String url) {
645 this.classLoader = classLoader;
650 //superClass = objectClassInfo;
651 superClass = ClassLoaderInfo.getSystemResolvedClassInfo("gov.nasa.jpf.AnnotationProxyBase");
653 interfaceNames = new String[]{ annotationCls.name };
654 packageName = annotationCls.packageName;
655 sourceFileName = annotationCls.sourceFileName;
656 genericSignature = annotationCls.genericSignature;
658 sFields = new FieldInfo[0]; // none
661 methods = new HashMap<String, MethodInfo>();
662 iFields = new FieldInfo[annotationCls.methods.size()];
663 nInstanceFields = iFields.length;
665 // all accessor declaredMethods of ours make it into iField/method combinations
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();
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);
678 off += fi.getStorageSize();
680 MethodInfo pmi = new MethodInfo(this, mname, mi.getSignature(), Modifier.PUBLIC, 1, 2);
681 pmi.setGenericSignature(genericSignature);
683 setAnnotationValueGetterCode( pmi, fi);
684 methods.put(pmi.getUniqueName(), pmi);
687 instanceDataSize = computeInstanceDataSize();
688 instanceDataOffset = 0;
695 //used to create synthetic classes that implement functional interfaces
696 protected ClassInfo createFuncObjClassInfo (BootstrapMethodInfo bootstrapMethod, String name, String samUniqueName, String[] fieldTypesName) {
700 protected ClassInfo (ClassInfo funcInterface, BootstrapMethodInfo bootstrapMethod, String name, String[] fieldTypesName) {
701 ClassInfo enclosingClass = bootstrapMethod.enclosingClass;
702 this.classLoader = enclosingClass.classLoader;
707 superClassName = "java.lang.Object";
709 interfaceNames = new String[]{ funcInterface.name };
710 packageName = enclosingClass.getPackageName();
712 // creating fields used to capture free variables
713 int n = fieldTypesName.length;
715 iFields = new FieldInfo[n];
718 sFields = new FieldInfo[0];
722 int off = 0; // no super class
725 for(String type: fieldTypesName) {
726 FieldInfo fi = FieldInfo.create("arg" + i++, type, 0);
727 fi.linkToClass(this, idx, off);
729 off += fi.getStorageSize();
735 // since id and hence uniqueId are not set before this class is registered, we can't use them
738 public int hashCode() {
739 return OATHash.hash(name.hashCode(), classLoader.hashCode());
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)) {
757 protected String computeSourceFileName(){
758 return name.replace('.', '/') + ".java";
761 protected void checkUnresolvedNativeMethods(){
762 for (MethodInfo mi : methods.values()){
763 if (mi.isUnresolvedNativeMethod()){
764 NativeMethodInfo nmi = new NativeMethodInfo(mi, null, nativePeer);
770 protected void processJPFConfigAnnotation() {
771 AnnotationInfo ai = getAnnotation("gov.nasa.jpf.annotation.JPFConfig");
773 for (String s : ai.getValueAsStringArray()) {
779 protected void loadAnnotationListeners () {
780 if (autoloadAnnotations != null) {
781 autoloadListeners(annotations); // class annotations
783 for (int i=0; i<sFields.length; i++) {
784 autoloadListeners(sFields[i].getAnnotations());
787 for (int i=0; i<iFields.length; i++) {
788 autoloadListeners(iFields[i].getAnnotations());
791 // method annotations are checked during method loading
792 // (to avoid extra iteration)
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";
806 JPFListener listener = config.getInstance(key, JPFListener.class, defClsName);
808 JPF jpf = VM.getVM().getJPF(); // <2do> that's a BAD access path
809 jpf.addUniqueTypeListener(listener);
811 if (logger.isLoggable(Level.INFO)){
812 logger.info("autoload annotation listener: @", aName, " => ", listener.getClass().getName());
815 } catch (JPFConfigException cx) {
816 logger.warning("no autoload listener class for annotation " + aName +
817 " : " + cx.getMessage());
818 autoloadAnnotations.remove(aName);
824 if (autoloadAnnotations.isEmpty()) {
825 autoloadAnnotations = null;
830 protected NativePeer loadNativePeer(){
831 return NativePeer.getNativePeer(this);
835 * Returns the class loader that
837 public ClassLoaderInfo getClassLoaderInfo() {
842 * the container this is stored in
844 public Statics getStatics() {
845 return classLoader.getStatics();
849 * required by InfoObject interface
851 public ClassInfo getClassInfo() {
855 protected void setAssertionStatus() {
856 if(isInitialized()) {
859 enableAssertions = classLoader.desiredAssertionStatus(name);
863 boolean getAssertionStatus () {
864 return enableAssertions;
867 public boolean desiredAssertionStatus() {
868 return classLoader.desiredAssertionStatus(name);
872 public String getGenericSignature() {
873 return genericSignature;
877 public void setGenericSignature(String sig){
878 genericSignature = sig;
881 public boolean isArray () {
885 public boolean isEnum () {
889 public boolean isAbstract() {
893 public boolean isBuiltin(){
897 public boolean isInterface() {
898 return ((modifiers & Modifier.INTERFACE) != 0);
901 public boolean isReferenceArray () {
902 return isReferenceArray;
905 public boolean isObjectClassInfo() {
906 return isObjectClassInfo;
909 public boolean isStringClassInfo() {
910 return isStringClassInfo;
913 public boolean isThreadClassInfo() {
914 return isThreadClassInfo;
917 protected void checkNoClinitInitialization(){
918 if (!isInitialized()){
919 ThreadInfo ti = ThreadInfo.getCurrentThread();
921 setInitialized(); // we might want to check if there is a clinit
925 protected ClassInfo createAnnotationProxy (String proxyName){
926 // to be overridden by VM specific ClassInfos
930 public ClassInfo getAnnotationProxy (){
931 // <2do> test if this is a annotation ClassInfo
933 checkNoClinitInitialization(); // annotation classes don't have clinits
935 ClassInfo ciProxy = classLoader.getResolvedAnnotationProxy(this);
936 ciProxy.checkNoClinitInitialization();
942 public static ClassInfo getAnnotationProxy (ClassInfo ciAnnotation){
943 ThreadInfo ti = ThreadInfo.getCurrentThread();
945 // make sure the annotationCls is initialized (no code there)
946 if (!ciAnnotation.isInitialized()) {
947 ciAnnotation.registerClass(ti);
948 ciAnnotation.setInitialized(); // no clinit
951 String url = computeProxyUrl(ciAnnotation);
952 ClassInfo ci = null; // getOriginalClassInfo(url);
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);
968 public boolean areAssertionsEnabled() {
969 return enableAssertions;
972 public boolean hasInstanceFields () {
973 return (instanceDataSize > 0);
976 public ElementInfo getClassObject(){
977 StaticElementInfo sei = getStaticElementInfo();
980 int objref = sei.getClassObjectRef();
981 return VM.getVM().getElementInfo(objref);
987 public ElementInfo getModifiableClassObject(){
988 StaticElementInfo sei = getStaticElementInfo();
991 int objref = sei.getClassObjectRef();
992 return VM.getVM().getModifiableElementInfo(objref);
999 public int getClassObjectRef () {
1000 StaticElementInfo sei = getStaticElementInfo();
1001 return (sei != null) ? sei.getClassObjectRef() : MJIEnv.NULL;
1004 public gov.nasa.jpf.vm.ClassFileContainer getContainer(){
1008 public String getClassFileUrl (){
1009 return classFileUrl;
1012 //--- type based object release actions
1014 public boolean hasReleaseAction (ReleaseAction action){
1015 return (releaseActions != null) && releaseActions.contains(action);
1019 * NOTE - this can only be set *before* subclasses are loaded (e.g. from classLoaded() notification)
1021 public void addReleaseAction (ReleaseAction action){
1022 // flattened in ctor to super releaseActions
1023 releaseActions = new ImmutableList<ReleaseAction>( action, releaseActions);
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
1031 public void processReleaseActions (ElementInfo ei){
1032 if (superClass != null){
1033 superClass.processReleaseActions(ei);
1036 if (releaseActions != null) {
1037 for (ReleaseAction action : releaseActions) {
1043 public int getModifiers() {
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).
1058 public MethodInfo getMethod (String uniqueName, boolean isRecursiveLookup) {
1059 MethodInfo mi = methods.get(uniqueName);
1061 if ((mi == null) && isRecursiveLookup && (superClass != null)) {
1062 mi = superClass.getMethod(uniqueName, true);
1069 * if we don't know the return type
1070 * signature is in paren/dot notation
1072 public MethodInfo getMethod (String name, String signature, boolean isRecursiveLookup) {
1073 MethodInfo mi = null;
1074 String matchName = name + signature;
1076 for (Map.Entry<String, MethodInfo>e : methods.entrySet()) {
1077 if (e.getKey().startsWith(matchName)){
1083 if ((mi == null) && isRecursiveLookup && (superClass != null)) {
1084 mi = superClass.getMethod(name, signature, true);
1091 public MethodInfo getDefaultMethod (String uniqueName) {
1092 MethodInfo mi = null;
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())) {
1100 } else if(mi.getClassInfo().isSubInterfaceOf(miIfc.getClassInfo())) {
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);
1116 private boolean isSubInterfaceOf(ClassInfo classInfo) {
1117 assert this.isInterface() && classInfo.isInterface();
1118 return this == classInfo || this.getAllInterfaces().contains(classInfo);
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
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
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.
1136 public MethodInfo getInterfaceAbstractMethod () {
1137 ClassInfo objCi = ClassLoaderInfo.getCurrentResolvedClassInfo("java.lang.Object");
1139 for(MethodInfo mi: this.methods.values()) {
1140 if(mi.isAbstract() && objCi.getMethod(mi.getUniqueName(), false)==null) {
1145 for (ClassInfo ifc : this.interfaces){
1146 MethodInfo mi = ifc.getInterfaceAbstractMethod();
1156 * method lookup for use by reflection methods (java.lang.Class.getXMethod)
1158 * note this doesn't specify the return type, which means covariant return
1159 * types are not allowed in reflection lookup.
1161 * note also this includes interface methods, but only after the inheritance
1162 * hierarchy has been searched
1164 public MethodInfo getReflectionMethod (String fullName, boolean isRecursiveLookup) {
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();
1174 if (!isRecursiveLookup){
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();
1193 * iterate over all declaredMethods of this class (and it's superclasses), until
1194 * the provided MethodLocator tells us it's done
1196 public void matchMethods (MethodLocator loc) {
1197 for (MethodInfo mi : methods.values()) {
1198 if (loc.match(mi)) {
1202 if (superClass != null) {
1203 superClass.matchMethods(loc);
1208 * iterate over all declaredMethods declared in this class, until the provided
1209 * MethodLocator tells us it's done
1211 public void matchDeclaredMethods (MethodLocator loc) {
1212 for (MethodInfo mi : methods.values()) {
1213 if (loc.match(mi)) {
1220 public Iterator<MethodInfo> iterator() {
1221 return new Iterator<MethodInfo>() {
1222 ClassInfo ci = ClassInfo.this;
1223 Iterator<MethodInfo> it = ci.methods.values().iterator();
1226 public boolean hasNext() {
1230 if (ci.superClass != null) {
1232 it = ci.methods.values().iterator();
1233 return it.hasNext();
1241 public MethodInfo next() {
1245 throw new NoSuchElementException();
1250 public void remove() {
1252 throw new UnsupportedOperationException("can't remove methods");
1257 public Iterator<MethodInfo> declaredMethodIterator() {
1258 return methods.values().iterator();
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)
1266 public FieldInfo getStaticField (String fName) {
1271 fi = c.getDeclaredStaticField(fName);
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);
1290 public Object getStaticFieldValueObject (String id){
1295 ElementInfo sei = c.getStaticElementInfo();
1296 v = sei.getFieldValueObject(id);
1300 c = c.getSuperClass();
1306 public FieldInfo[] getDeclaredStaticFields() {
1310 public FieldInfo[] getDeclaredInstanceFields() {
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
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];
1328 * base relative FieldInfo lookup - the workhorse
1329 * <2do> again, should eventually use Maps
1330 * @param fName the field name
1332 public FieldInfo getInstanceField (String fName) {
1337 fi = c.getDeclaredInstanceField(fName);
1338 if (fi != null) return fi;
1346 * FieldInfo lookup in the fields that are declared in this class
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];
1356 public String getSignature() {
1357 if (signature == null) {
1358 signature = Types.getTypeSignature(name, false);
1365 * Returns the name of the class. e.g. "java.lang.String". similar to
1366 * java.lang.Class.getName().
1368 public String getName () {
1372 public String getSimpleName () {
1374 String enclosingClassName = getEnclosingClassName();
1376 if(enclosingClassName!=null){
1377 i = enclosingClassName.length();
1379 i = name.lastIndexOf('.');
1382 return name.substring(i+1);
1385 public String getPackageName () {
1389 public int getId() {
1393 public long getUniqueId() {
1397 public int getFieldAttrs (int fieldIndex) {
1398 fieldIndex = 0; // Get rid of IDE warning
1403 public void setElementInfoAttrs (int attrs){
1404 elementInfoAttrs = attrs;
1407 public void addElementInfoAttr (int attr){
1408 elementInfoAttrs |= attr;
1411 public int getElementInfoAttrs () {
1412 return elementInfoAttrs;
1415 public Source getSource () {
1416 if (source == null) {
1417 source = loadSource();
1423 public String getSourceFileName () {
1424 return sourceFileName;
1428 * Returns the information about a static field.
1430 public FieldInfo getStaticField (int index) {
1431 return sFields[index];
1435 * Returns the name of a static field.
1437 public String getStaticFieldName (int index) {
1438 return getStaticField(index).getName();
1442 * Checks if a static method call is deterministic, but only for
1443 * abtraction based determinism, due to Bandera.choose() calls
1445 public boolean isStaticMethodAbstractionDeterministic (ThreadInfo th,
1447 // Reflection r = reflection.instantiate();
1448 // return r.isStaticMethodAbstractionDeterministic(th, mi);
1449 // <2do> - still has to be implemented
1451 th = null; // Get rid of IDE warning
1457 public String getSuperClassName() {
1458 return superClassName;
1462 * Return the super class.
1464 public ClassInfo getSuperClass () {
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)
1472 public ClassInfo getSuperClass (String clsName) {
1473 if (clsName.equals(name)) return this;
1475 if (superClass != null) {
1476 return superClass.getSuperClass(clsName);
1482 public int getNumberOfSuperClasses(){
1484 for (ClassInfo ci = superClass; ci != null; ci = ci.superClass){
1491 * beware - this loads (but not yet registers) the enclosing class
1493 public String getEnclosingClassName(){
1494 return enclosingClassName;
1498 * beware - this loads (but not yet registers) the enclosing class
1500 public ClassInfo getEnclosingClassInfo() {
1501 String enclName = getEnclosingClassName();
1502 return (enclName == null ? null : classLoader.getResolvedClassInfo(enclName)); // ? is this supposed to use the same classloader
1505 public String getEnclosingMethodName(){
1506 return enclosingMethodName;
1510 * same restriction as getEnclosingClassInfo() - might not be registered/initialized
1512 public MethodInfo getEnclosingMethodInfo(){
1513 MethodInfo miEncl = null;
1515 if (enclosingMethodName != null){
1516 ClassInfo ciIncl = getEnclosingClassInfo();
1517 miEncl = ciIncl.getMethod( enclosingMethodName, false);
1524 * Returns true if the class is a system class.
1526 public boolean isSystemClass () {
1527 return name.startsWith("java.") || name.startsWith("javax.");
1531 * <2do> that's stupid - we should use subclasses for builtin and box types
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")) {
1550 * Returns the type of a class.
1552 public String getType () {
1554 return "L" + name.replace('.', '/') + ";";
1561 * is this a (subclass of) WeakReference? this must be efficient, since it's
1562 * called in the mark phase on all live objects
1564 public boolean isWeakReference () {
1565 return isWeakReference;
1569 * note this only returns true is this is really the java.lang.ref.Reference classInfo
1571 public boolean isReferenceClassInfo () {
1572 return isRefClassInfo;
1576 * whether this refers to a primitive type.
1578 public boolean isPrimitive() {
1579 return superClass == null && !isObjectClassInfo();
1583 boolean hasRefField (int ref, Fields fv) {
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;
1593 } while (c != null);
1598 boolean hasImmutableInstances () {
1599 return ((elementInfoAttrs & ElementInfo.ATTR_IMMUTABLE) != 0);
1602 public boolean hasInstanceFieldInfoAttr (Class<?> type){
1603 for (int i=0; i<nInstanceFields; i++){
1604 if (getInstanceField(i).hasAttr(type)){
1612 public NativePeer getNativePeer () {
1617 * Returns true if the given class is an instance of the class
1618 * or interface specified.
1620 public boolean isInstanceOf (String cname) {
1621 if (isPrimitive()) {
1622 return Types.getJNITypeCode(name).equals(cname);
1625 cname = Types.getClassNameFromTypeName(cname);
1626 ClassInfo ci = this.classLoader.getResolvedClassInfo(cname);
1627 return isInstanceOf(ci);
1632 * Returns true if the given class is an instance of the class
1633 * or interface specified.
1635 public boolean isInstanceOf (ClassInfo ci) {
1636 if (isPrimitive()) { // no inheritance for builtin types
1639 for (ClassInfo c = this; c != null; c = c.superClass) {
1645 return getAllInterfaces().contains(ci);
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);
1659 public boolean hasInnerClass (String innerName){
1660 for (int i=0; i<innerClassNames.length; i++){
1661 if (innerClassNames[i].equals(innerName)){
1670 public static String makeModelClassPath (Config config) {
1671 StringBuilder buf = new StringBuilder(256);
1672 String ps = File.pathSeparator;
1675 for (File f : config.getPathArray("boot_classpath")){
1676 buf.append(f.getAbsolutePath());
1680 for (File f : config.getPathArray("classpath")){
1681 buf.append(f.getAbsolutePath());
1685 // finally, we load from the standard Java libraries
1686 v = System.getProperty("sun.boot.class.path");
1691 return buf.toString();
1694 protected static String[] loadArrayInterfaces () {
1695 return new String[] {"java.lang.Cloneable", "java.io.Serializable"};
1698 protected static String[] loadBuiltinInterfaces (String type) {
1699 return EMPTY_STRING_ARRAY;
1704 * Loads the ClassInfo for named class.
1706 void loadInterfaceRec (Set<ClassInfo> set, String[] interfaces) throws ClassInfoException {
1707 if (interfaces != null) {
1708 for (String iname : interfaces) {
1710 ClassInfo ci = classLoader.getResolvedClassInfo(iname);
1716 loadInterfaceRec(set, ci.interfaceNames);
1721 int computeInstanceDataOffset () {
1722 if (superClass == null) {
1725 return superClass.getInstanceDataSize();
1729 int getInstanceDataOffset () {
1730 return instanceDataOffset;
1733 ClassInfo getClassBase (String clsBase) {
1734 if ((clsBase == null) || (name.equals(clsBase))) return this;
1736 if (superClass != null) {
1737 return superClass.getClassBase(clsBase);
1740 return null; // Eeek - somebody asked for a class that isn't in the base list
1743 int computeInstanceDataSize () {
1744 int n = getDataSize( iFields);
1746 for (ClassInfo c=superClass; c!= null; c=c.superClass) {
1747 n += c.getDataSize(c.iFields);
1753 public int getInstanceDataSize () {
1754 return instanceDataSize;
1757 int getDataSize (FieldInfo[] fields) {
1759 for (int i=0; i<fields.length; i++) {
1760 n += fields[i].getStorageSize();
1766 public int getNumberOfDeclaredInstanceFields () {
1767 return iFields.length;
1770 public FieldInfo getDeclaredInstanceField (int i) {
1774 public int getNumberOfInstanceFields () {
1775 return nInstanceFields;
1778 public FieldInfo getInstanceField (int i) {
1779 int idx = i - (nInstanceFields - iFields.length);
1781 return ((idx < iFields.length) ? iFields[idx] : null);
1783 return ((superClass != null) ? superClass.getInstanceField(i) : null);
1787 public FieldInfo[] getInstanceFields(){
1788 FieldInfo[] fields = new FieldInfo[nInstanceFields];
1790 for (int i=0; i<fields.length; i++){
1791 fields[i] = getInstanceField(i);
1797 public int getStaticDataSize () {
1798 return staticDataSize;
1801 int computeStaticDataSize () {
1802 return getDataSize(sFields);
1805 public int getNumberOfStaticFields () {
1806 return sFields.length;
1809 protected Source loadSource () {
1810 return Source.getSource(sourceFileName);
1813 public static boolean isBuiltinClass (String cname) {
1814 char c = cname.charAt(0);
1817 if ((c == '[') || cname.endsWith("[]")) {
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)) {
1835 * set the locations where we look up sources
1837 static void setSourceRoots (Config config) {
1838 Source.init(config);
1842 * get names of all interfaceNames (transitive, idx.e. incl. bases and super-interfaceNames)
1843 * @return a Set of String interface names
1845 public Set<ClassInfo> getAllInterfaces () {
1846 if (allInterfaces == null) {
1847 HashSet<ClassInfo> set = new HashSet<ClassInfo>();
1849 for (ClassInfo ci=this; ci != null; ci=ci.superClass) {
1850 loadInterfaceRec(set, ci.interfaceNames);
1853 allInterfaces = Collections.unmodifiableSet(set);
1856 return allInterfaces;
1860 * get names of directly implemented interfaceNames
1862 public String[] getDirectInterfaceNames () {
1863 return interfaceNames;
1866 public Set<ClassInfo> getInterfaceClassInfos() {
1870 public Set<ClassInfo> getAllInterfaceClassInfos() {
1871 return getAllInterfaces();
1876 * get names of direct inner classes
1878 public String[] getInnerClasses(){
1879 return innerClassNames;
1882 public ClassInfo[] getInnerClassInfos(){
1883 ClassInfo[] innerClassInfos = new ClassInfo[innerClassNames.length];
1885 for (int i=0; i< innerClassNames.length; i++){
1886 innerClassInfos[i] = classLoader.getResolvedClassInfo(innerClassNames[i]); // ? is this supposed to use the same classloader
1889 return innerClassInfos;
1892 public BootstrapMethodInfo getBootstrapMethodInfo(int index) {
1893 return bootstrapMethods[index];
1896 public ClassInfo getComponentClassInfo () {
1898 String cn = name.substring(1);
1900 if (cn.charAt(0) != '[') {
1901 cn = Types.getTypeName(cn);
1904 ClassInfo cci = classLoader.getResolvedClassInfo(cn);
1913 * most definitely not a public method, but handy for the NativePeer
1915 protected Map<String, MethodInfo> getDeclaredMethods () {
1920 * be careful, this replaces or adds MethodInfos dynamically
1922 public MethodInfo putDeclaredMethod (MethodInfo mi){
1923 return methods.put(mi.getUniqueName(), mi);
1926 public MethodInfo[] getDeclaredMethodInfos() {
1927 MethodInfo[] a = new MethodInfo[methods.size()];
1928 methods.values().toArray(a);
1932 public Instruction[] getMatchingInstructions (LocationSpec lspec){
1933 Instruction[] insns = null;
1935 if (lspec.matchesFile(sourceFileName)){
1936 for (MethodInfo mi : methods.values()) {
1937 Instruction[] a = mi.getMatchingInstructions(lspec);
1939 if (insns != null) {
1940 // not very efficient but probably rare
1941 insns = Misc.appendArray(insns, a);
1946 // little optimization
1947 if (!lspec.isLineInterval()) {
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)) {
1963 list = new ArrayList<MethodInfo>();
1972 public MethodInfo getFinalizer () {
1976 public MethodInfo getClinit() {
1977 // <2do> braindead - cache
1978 for (MethodInfo mi : methods.values()) {
1979 if ("<clinit>".equals(mi.getName())) {
1986 public boolean hasCtors() {
1987 // <2do> braindead - cache
1988 for (MethodInfo mi : methods.values()) {
1989 if ("<init>".equals(mi.getName())) {
1997 * see getInitializedClassInfo() for restrictions.
1999 public static ClassInfo getInitializedSystemClassInfo (String clsName, ThreadInfo ti){
2000 ClassLoaderInfo systemLoader = ClassLoaderInfo.getCurrentSystemClassLoader();
2001 ClassInfo ci = systemLoader.getResolvedClassInfo(clsName);
2002 ci.initializeClassAtomic(ti);
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
2012 public static ClassInfo getInitializedClassInfo (String clsName, ThreadInfo ti){
2013 ClassLoaderInfo cl = ClassLoaderInfo.getCurrentClassLoader();
2014 ClassInfo ci = cl.getResolvedClassInfo(clsName);
2015 ci.initializeClassAtomic(ti);
2020 public boolean isRegistered () {
2021 //return (id != -1);
2022 return getStaticElementInfo() != null;
2026 * this registers a ClassInfo in the corresponding ClassLoader statics so that we can cross-link from
2027 * SUT code and access static fields.
2029 public StaticElementInfo registerClass (ThreadInfo ti){
2030 StaticElementInfo sei = getStaticElementInfo();
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()
2036 if (superClass != null) {
2037 superClass.registerClass(ti);
2040 for (ClassInfo ifc : interfaces) {
2041 ifc.registerClass(ti);
2044 ClassInfo.logger.finer("registering class: ", name);
2046 ElementInfo ei = createClassObject( ti);
2047 sei = createAndLinkStaticElementInfo( ti, ei);
2049 // SUT class is fully resolved and registered (but not necessarily initialized), notify listeners
2050 ti.getVM().notifyClassLoaded(this);
2056 ElementInfo createClassObject (ThreadInfo ti){
2057 Heap heap = VM.getVM().getHeap(); // ti can be null (during main thread initialization)
2059 int anchor = name.hashCode(); // 2do - this should also take the ClassLoader ref into account
2061 SystemClassLoaderInfo systemClassLoader = ti.getSystemClassLoaderInfo();
2063 ClassInfo classClassInfo = systemClassLoader.getClassClassInfo();
2064 ElementInfo ei = heap.newSystemObject(classClassInfo, ti, anchor);
2065 int clsObjRef = ei.getObjectRef();
2067 ElementInfo eiClsName = heap.newSystemString(name, ti, clsObjRef);
2068 ei.setReferenceField("name", eiClsName.getObjectRef());
2070 ei.setBooleanField("isPrimitive", isPrimitive());
2072 // setting the ID_FIELD is done in registerClass once we have a StaticElementInfo
2074 // link the SUT class object to the classloader
2075 ei.setReferenceField("classLoader", classLoader.getClassLoaderObjectRef());
2080 StaticElementInfo createAndLinkStaticElementInfo (ThreadInfo ti, ElementInfo eiClsObj) {
2081 Statics statics = classLoader.getStatics();
2082 StaticElementInfo sei = statics.newClass(this, ti, eiClsObj);
2084 id = sei.getObjectRef(); // kind of a misnomer, it's really an id
2085 uniqueId = ((long)classLoader.getId() << 32) | id;
2087 eiClsObj.setIntField( ID_FIELD, id);
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
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()
2102 if (superClass != null) {
2103 superClass.registerStartupClass(ti, list);
2106 for (ClassInfo ifc : interfaces) {
2107 ifc.registerStartupClass(ti, list);
2111 if (!list.contains(this)) {
2113 ClassInfo.logger.finer("registering startup class: ", name);
2114 createStartupStaticElementInfo(ti);
2117 // SUT class is fully resolved and registered (but not necessarily initialized), notify listeners
2118 ti.getVM().notifyClassLoaded(this);
2121 StaticElementInfo createStartupStaticElementInfo (ThreadInfo ti) {
2122 Statics statics = classLoader.getStatics();
2123 StaticElementInfo sei = statics.newStartupClass(this, ti);
2125 id = sei.getObjectRef(); // kind of a misnomer, it's really an id
2126 uniqueId = ((long)classLoader.getId() << 32) | id;
2131 ElementInfo createAndLinkStartupClassObject (ThreadInfo ti) {
2132 StaticElementInfo sei = getStaticElementInfo();
2133 ElementInfo ei = createClassObject(ti);
2135 sei.setClassObjectRef(ei.getObjectRef());
2136 ei.setIntField( ID_FIELD, id);
2141 boolean checkIfValidClassClassInfo() {
2142 return getDeclaredInstanceField( ID_FIELD) != null;
2145 public boolean isInitializing () {
2146 StaticElementInfo sei = getStaticElementInfo();
2147 return ((sei != null) && (sei.getStatus() >= 0));
2151 * note - this works recursively upwards since there might
2152 * be a superclass with a clinit that is still executing
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){
2165 public boolean isResolved () {
2166 return (!isObjectClassInfo() && superClass != null);
2169 public boolean needsInitialization (ThreadInfo ti){
2170 StaticElementInfo sei = getStaticElementInfo();
2172 int status = sei.getStatus();
2173 if (status == INITIALIZED || status == ti.getId()){
2181 public void setInitializing(ThreadInfo ti) {
2182 StaticElementInfo sei = getModifiableStaticElementInfo();
2183 sei.setStatus(ti.getId());
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
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
2195 * @return true - if initialization pushed DirectCallStackFrames and caller has to re-execute
2197 public boolean initializeClass(ThreadInfo ti){
2198 int pushedFrames = 0;
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();
2204 sei = ci.registerClass(ti);
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).
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);
2220 DirectCallStackFrame frame = ci.createDirectCallStackFrame(ti, mi, 0);
2221 ti.pushFrame( frame);
2225 // it has no clinit, we can set it initialized
2226 ci.setInitialized();
2229 // ignore if it's already being initialized by our own thread (recursive request)
2232 break; // if this class is initialized, so are its superclasses
2236 return (pushedFrames > 0);
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
2244 public void initializeClassAtomic (ThreadInfo ti){
2245 for (ClassInfo ci = this; ci != null; ci = ci.getSuperClass()) {
2246 StaticElementInfo sei = ci.getStaticElementInfo();
2248 sei = ci.registerClass(ti);
2251 int status = sei.getStatus();
2252 if (status != INITIALIZED && status != ti.getId()){
2253 MethodInfo mi = ci.getMethod("<clinit>()V", false);
2255 DirectCallStackFrame frame = ci.createDirectCallStackFrame(ti, mi, 0);
2256 ti.executeMethodAtomic(frame);
2258 ci.setInitialized();
2261 break; // if this class is initialized, so are its superclasses
2266 public void setInitialized() {
2267 StaticElementInfo sei = getStaticElementInfo();
2268 if (sei != null && sei.getStatus() != INITIALIZED){
2269 sei = getModifiableStaticElementInfo();
2270 sei.setStatus(INITIALIZED);
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()
2278 public StaticElementInfo getStaticElementInfo() {
2280 return classLoader.getStatics().get( id);
2286 public StaticElementInfo getModifiableStaticElementInfo() {
2288 return classLoader.getStatics().getModifiable( id);
2294 Fields createArrayFields (String type, int nElements, int typeSize, boolean isReferenceArray) {
2295 return fieldsFactory.createArrayFields( type, this,
2296 nElements, typeSize, isReferenceArray);
2300 * Creates the fields for a class. This gets called during registration of a ClassInfo
2302 Fields createStaticFields () {
2303 return fieldsFactory.createStaticFields(this);
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);
2314 * Creates the fields for an object.
2316 public Fields createInstanceFields () {
2317 return fieldsFactory.createInstanceFields(this);
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
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
2330 if (superClass != null) { // do superclasses first
2331 superClass.initializeInstanceData(ei, ti);
2334 for (int i=0; i<iFields.length; i++) {
2335 FieldInfo fi = iFields[i];
2336 fi.initialize(ei, ti);
2340 Map<String, MethodInfo> loadArrayMethods () {
2341 return new HashMap<String, MethodInfo>(0);
2344 Map<String, MethodInfo> loadBuiltinMethods (String type) {
2345 type = null; // Get rid of IDE warning
2347 return new HashMap<String, MethodInfo>(0);
2350 protected ClassInfo loadSuperClass (String superName) throws ClassInfoException {
2351 if (isObjectClassInfo()) {
2355 logger.finer("resolving superclass: ", superName, " of ", name);
2357 // resolve the superclass
2358 ClassInfo sci = resolveReferencedClass(superName);
2363 protected Set<ClassInfo> loadInterfaces (String[] ifcNames) throws ClassInfoException {
2364 if (ifcNames == null || ifcNames.length == 0){
2365 return NO_INTERFACES;
2368 Set<ClassInfo> set = new HashSet<ClassInfo>();
2370 for (String ifcName : ifcNames) {
2371 ClassInfo.logger.finer("resolving interface: ", ifcName, " of ", name);
2372 ClassInfo ifc = resolveReferencedClass(ifcName);
2381 * loads superclass and direct interfaces, and computes information
2382 * that depends on them
2384 protected void resolveClass() {
2385 if (!isObjectClassInfo){
2386 superClass = loadSuperClass(superClassName);
2387 releaseActions = superClass.releaseActions;
2389 interfaces = loadInterfaces(interfaceNames);
2391 //computeInheritedAnnotations(superClass);
2393 isWeakReference = isWeakReference0();
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
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
2405 * It loads the class referenced by these instructions and adds it to the
2406 * resolvedClasses map of the classLoader
2408 public ClassInfo resolveReferencedClass(String cname) {
2409 if(name.equals(cname)) {
2413 // if the class has been already resolved just return it
2414 ClassInfo ci = classLoader.getAlreadyResolvedClassInfo(cname);
2419 // The defining class loader of the class initiate the load of referenced classes
2420 ci = classLoader.loadClass(cname);
2421 classLoader.addResolvedClass(ci);
2426 protected int linkFields (FieldInfo[] fields, int idx, int off){
2427 for (FieldInfo fi: fields) {
2428 fi.linkToClass(this, idx, off);
2430 int storageSize = fi.getStorageSize();
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;
2447 instanceDataSize = linkFields( iFields, 0, 0);
2448 nInstanceFields = iFields.length;
2449 instanceDataOffset = 0;
2453 staticDataSize = linkFields( sFields, 0, 0);
2456 // this resolves all annotations in this class hierarchy, which sets inherited attributes
2457 protected void checkInheritedAnnotations (){
2462 public String toString() {
2463 return "ClassInfo[name=" + name + "]";
2466 protected MethodInfo getFinalizer0 () {
2467 MethodInfo mi = getMethod("finalize()V", true);
2469 // we are only interested in non-empty method bodies, Object.finalize()
2471 if ((mi != null) && (!mi.getClassInfo().isObjectClassInfo())) {
2478 protected boolean isObjectClassInfo0 () {
2479 if (name.equals("java.lang.Object")) {
2485 protected boolean isStringClassInfo0 () {
2486 if(name.equals("java.lang.String")) {
2492 protected boolean isRefClassInfo0 () {
2493 if(name.equals("java.lang.ref.Reference")) {
2499 protected boolean isWeakReference0 () {
2500 if(name.equals("java.lang.ref.WeakReference")) {
2504 for (ClassInfo ci = this; !ci.isObjectClassInfo(); ci = ci.superClass) {
2505 if (ci.isWeakReference()) {
2513 protected boolean isEnum0 () {
2514 if(name.equals("java.lang.Enum")) {
2518 for (ClassInfo ci = this; !ci.isObjectClassInfo(); ci = ci.superClass) {
2527 protected boolean isThreadClassInfo0 () {
2528 if(name.equals("java.lang.Thread")) {
2536 * It creates an instance from a original ClassInfo instance. It doesn't copy sei &
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.
2542 public ClassInfo cloneFor (ClassLoaderInfo cl) {
2546 ci = (ClassInfo)clone();
2548 ci.classLoader = cl;
2549 ci.interfaces = new HashSet<ClassInfo>();
2555 if (methods != Collections.EMPTY_MAP){
2556 ci.methods = (Map<String, MethodInfo>)((HashMap<String, MethodInfo>) methods).clone();
2559 for(Map.Entry<String, MethodInfo> e: ci.methods.entrySet()) {
2560 MethodInfo mi = e.getValue();
2561 e.setValue(mi.getInstanceFor(ci));
2564 ci.iFields = new FieldInfo[iFields.length];
2565 for(int i=0; i<iFields.length; i++) {
2566 ci.iFields[i] = iFields[i].getInstanceFor(ci);
2569 ci.sFields = new FieldInfo[sFields.length];
2570 for(int i=0; i<sFields.length; i++) {
2571 ci.sFields[i] = sFields[i].getInstanceFor(ci);
2574 if(nativePeer != null) {
2575 ci.nativePeer = NativePeer.getNativePeer(ci);
2578 ci.setAssertionStatus();
2580 } catch (CloneNotSupportedException cnsx){
2581 cnsx.printStackTrace();
2585 VM.getVM().notifyClassLoaded(ci);
2589 // <2do> should be abstract
2590 public StackFrame createStackFrame (ThreadInfo ti, MethodInfo callee){
2594 public DirectCallStackFrame createDirectCallStackFrame (ThreadInfo ti, MethodInfo callee, int nLocalSlots){
2598 public DirectCallStackFrame createRunStartStackFrame (ThreadInfo ti, MethodInfo miRun){
2602 // TODO: Fix for Groovy's model-checking
2603 public String[] getGenericTypeVariableNames () {
2604 if (genericSignature == null || genericSignature.equals(""))
2605 return new String[0];
2606 if (!genericSignature.contains(":"))
2607 return new String[0];
2608 return Types.getGenericTypeVariableNames(genericSignature);