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 ci = this; ci != null; ci = ci.superClass){
1095 for (ClassInfo ciIfc : ci.interfaces){
1096 MethodInfo miIfc = ciIfc.getMethod(uniqueName, true);
1097 if (miIfc != null && !miIfc.isAbstract()){
1098 if (mi != null && !mi.equals(miIfc)){
1099 // this has to throw a IncompatibleClassChangeError in the client since Java prohibits ambiguous default methods
1100 String msg = "Conflicting default methods: " + mi.getFullName() + ", " + miIfc.getFullName();
1101 throw new ClassChangeException(msg);
1113 * This retrieves the SAM from this functional interface. Note that this is only
1114 * called on functional interface expecting to have a SAM. This shouldn't expect
1115 * this interface to have only one method which is abstract, since:
1116 * 1. functional interface can declare the abstract methods from the java.lang.Object
1118 * 2. functional interface can extend another interface which is functional, but it
1119 * should not declare any new abstract methods.
1120 * 3. functional interface can have one abstract method and any number of default
1123 * To retrieve the SAM, this method iterates over the methods of this interface and its
1124 * superinterfaces, and it returns the first method which is abstract and it does not
1125 * declare a method in java.lang.Object.
1127 public MethodInfo getInterfaceAbstractMethod () {
1128 ClassInfo objCi = ClassLoaderInfo.getCurrentResolvedClassInfo("java.lang.Object");
1130 for(MethodInfo mi: this.methods.values()) {
1131 if(mi.isAbstract() && objCi.getMethod(mi.getUniqueName(), false)==null) {
1136 for (ClassInfo ifc : this.interfaces){
1137 MethodInfo mi = ifc.getInterfaceAbstractMethod();
1147 * method lookup for use by reflection methods (java.lang.Class.getXMethod)
1149 * note this doesn't specify the return type, which means covariant return
1150 * types are not allowed in reflection lookup.
1152 * note also this includes interface methods, but only after the inheritance
1153 * hierarchy has been searched
1155 public MethodInfo getReflectionMethod (String fullName, boolean isRecursiveLookup) {
1157 // first look for methods within the class hierarchy
1158 for (ClassInfo ci = this; ci != null; ci = ci.superClass){
1159 for (Map.Entry<String, MethodInfo>e : ci.methods.entrySet()) {
1160 String name = e.getKey();
1161 if (name.startsWith(fullName)) {
1162 return e.getValue();
1165 if (!isRecursiveLookup){
1170 // this is the recursive case - if none found, look for interface methods
1171 for (ClassInfo ci : getAllInterfaces() ){
1172 for (Map.Entry<String, MethodInfo>e : ci.methods.entrySet()) {
1173 String name = e.getKey();
1174 if (name.startsWith(fullName)) {
1175 return e.getValue();
1184 * iterate over all declaredMethods of this class (and it's superclasses), until
1185 * the provided MethodLocator tells us it's done
1187 public void matchMethods (MethodLocator loc) {
1188 for (MethodInfo mi : methods.values()) {
1189 if (loc.match(mi)) {
1193 if (superClass != null) {
1194 superClass.matchMethods(loc);
1199 * iterate over all declaredMethods declared in this class, until the provided
1200 * MethodLocator tells us it's done
1202 public void matchDeclaredMethods (MethodLocator loc) {
1203 for (MethodInfo mi : methods.values()) {
1204 if (loc.match(mi)) {
1211 public Iterator<MethodInfo> iterator() {
1212 return new Iterator<MethodInfo>() {
1213 ClassInfo ci = ClassInfo.this;
1214 Iterator<MethodInfo> it = ci.methods.values().iterator();
1217 public boolean hasNext() {
1221 if (ci.superClass != null) {
1223 it = ci.methods.values().iterator();
1224 return it.hasNext();
1232 public MethodInfo next() {
1236 throw new NoSuchElementException();
1241 public void remove() {
1243 throw new UnsupportedOperationException("can't remove methods");
1248 public Iterator<MethodInfo> declaredMethodIterator() {
1249 return methods.values().iterator();
1253 * Search up the class hierarchy to find a static field
1254 * @param fName name of field
1255 * @return null if field name not found (not declared)
1257 public FieldInfo getStaticField (String fName) {
1262 fi = c.getDeclaredStaticField(fName);
1269 //interfaceNames can have static fields too
1270 // <2do> why would that not be already resolved here ?
1271 for (ClassInfo ci : getAllInterfaces()) {
1272 fi = ci.getDeclaredStaticField(fName);
1281 public Object getStaticFieldValueObject (String id){
1286 ElementInfo sei = c.getStaticElementInfo();
1287 v = sei.getFieldValueObject(id);
1291 c = c.getSuperClass();
1297 public FieldInfo[] getDeclaredStaticFields() {
1301 public FieldInfo[] getDeclaredInstanceFields() {
1306 * FieldInfo lookup in the static fields that are declared in this class
1307 * <2do> pcm - should employ a map at some point, but it's usually not that
1308 * important since we can cash the returned FieldInfo in the PUT/GET_STATIC insns
1310 public FieldInfo getDeclaredStaticField (String fName) {
1311 for (int i=0; i<sFields.length; i++) {
1312 if (sFields[i].getName().equals(fName)) return sFields[i];
1319 * base relative FieldInfo lookup - the workhorse
1320 * <2do> again, should eventually use Maps
1321 * @param fName the field name
1323 public FieldInfo getInstanceField (String fName) {
1328 fi = c.getDeclaredInstanceField(fName);
1329 if (fi != null) return fi;
1337 * FieldInfo lookup in the fields that are declared in this class
1339 public FieldInfo getDeclaredInstanceField (String fName) {
1340 for (int i=0; i<iFields.length; i++) {
1341 if (iFields[i].getName().equals(fName)) return iFields[i];
1347 public String getSignature() {
1348 if (signature == null) {
1349 signature = Types.getTypeSignature(name, false);
1356 * Returns the name of the class. e.g. "java.lang.String". similar to
1357 * java.lang.Class.getName().
1359 public String getName () {
1363 public String getSimpleName () {
1365 String enclosingClassName = getEnclosingClassName();
1367 if(enclosingClassName!=null){
1368 i = enclosingClassName.length();
1370 i = name.lastIndexOf('.');
1373 return name.substring(i+1);
1376 public String getPackageName () {
1380 public int getId() {
1384 public long getUniqueId() {
1388 public int getFieldAttrs (int fieldIndex) {
1389 fieldIndex = 0; // Get rid of IDE warning
1394 public void setElementInfoAttrs (int attrs){
1395 elementInfoAttrs = attrs;
1398 public void addElementInfoAttr (int attr){
1399 elementInfoAttrs |= attr;
1402 public int getElementInfoAttrs () {
1403 return elementInfoAttrs;
1406 public Source getSource () {
1407 if (source == null) {
1408 source = loadSource();
1414 public String getSourceFileName () {
1415 return sourceFileName;
1419 * Returns the information about a static field.
1421 public FieldInfo getStaticField (int index) {
1422 return sFields[index];
1426 * Returns the name of a static field.
1428 public String getStaticFieldName (int index) {
1429 return getStaticField(index).getName();
1433 * Checks if a static method call is deterministic, but only for
1434 * abtraction based determinism, due to Bandera.choose() calls
1436 public boolean isStaticMethodAbstractionDeterministic (ThreadInfo th,
1438 // Reflection r = reflection.instantiate();
1439 // return r.isStaticMethodAbstractionDeterministic(th, mi);
1440 // <2do> - still has to be implemented
1442 th = null; // Get rid of IDE warning
1448 public String getSuperClassName() {
1449 return superClassName;
1453 * Return the super class.
1455 public ClassInfo getSuperClass () {
1460 * return the ClassInfo for the provided superclass name. If this is equals
1461 * to ourself, return this (a little bit strange if we hit it in the first place)
1463 public ClassInfo getSuperClass (String clsName) {
1464 if (clsName.equals(name)) return this;
1466 if (superClass != null) {
1467 return superClass.getSuperClass(clsName);
1473 public int getNumberOfSuperClasses(){
1475 for (ClassInfo ci = superClass; ci != null; ci = ci.superClass){
1482 * beware - this loads (but not yet registers) the enclosing class
1484 public String getEnclosingClassName(){
1485 return enclosingClassName;
1489 * beware - this loads (but not yet registers) the enclosing class
1491 public ClassInfo getEnclosingClassInfo() {
1492 String enclName = getEnclosingClassName();
1493 return (enclName == null ? null : classLoader.getResolvedClassInfo(enclName)); // ? is this supposed to use the same classloader
1496 public String getEnclosingMethodName(){
1497 return enclosingMethodName;
1501 * same restriction as getEnclosingClassInfo() - might not be registered/initialized
1503 public MethodInfo getEnclosingMethodInfo(){
1504 MethodInfo miEncl = null;
1506 if (enclosingMethodName != null){
1507 ClassInfo ciIncl = getEnclosingClassInfo();
1508 miEncl = ciIncl.getMethod( enclosingMethodName, false);
1515 * Returns true if the class is a system class.
1517 public boolean isSystemClass () {
1518 return name.startsWith("java.") || name.startsWith("javax.");
1522 * <2do> that's stupid - we should use subclasses for builtin and box types
1524 public boolean isBoxClass () {
1525 if (name.startsWith("java.lang.")) {
1526 String rawType = name.substring(10);
1527 if (rawType.startsWith("Boolean") ||
1528 rawType.startsWith("Byte") ||
1529 rawType.startsWith("Character") ||
1530 rawType.startsWith("Integer") ||
1531 rawType.startsWith("Float") ||
1532 rawType.startsWith("Long") ||
1533 rawType.startsWith("Double")) {
1541 * Returns the type of a class.
1543 public String getType () {
1545 return "L" + name.replace('.', '/') + ";";
1552 * is this a (subclass of) WeakReference? this must be efficient, since it's
1553 * called in the mark phase on all live objects
1555 public boolean isWeakReference () {
1556 return isWeakReference;
1560 * note this only returns true is this is really the java.lang.ref.Reference classInfo
1562 public boolean isReferenceClassInfo () {
1563 return isRefClassInfo;
1567 * whether this refers to a primitive type.
1569 public boolean isPrimitive() {
1570 return superClass == null && !isObjectClassInfo();
1574 boolean hasRefField (int ref, Fields fv) {
1578 FieldInfo[] fia = c.iFields;
1579 for (int i=0; i<fia.length; i++) {
1580 FieldInfo fi = c.iFields[i];
1581 if (fi.isReference() && (fv.getIntValue( fi.getStorageOffset()) == ref)) return true;
1584 } while (c != null);
1589 boolean hasImmutableInstances () {
1590 return ((elementInfoAttrs & ElementInfo.ATTR_IMMUTABLE) != 0);
1593 public boolean hasInstanceFieldInfoAttr (Class<?> type){
1594 for (int i=0; i<nInstanceFields; i++){
1595 if (getInstanceField(i).hasAttr(type)){
1603 public NativePeer getNativePeer () {
1608 * Returns true if the given class is an instance of the class
1609 * or interface specified.
1611 public boolean isInstanceOf (String cname) {
1612 if (isPrimitive()) {
1613 return Types.getJNITypeCode(name).equals(cname);
1616 cname = Types.getClassNameFromTypeName(cname);
1617 ClassInfo ci = this.classLoader.getResolvedClassInfo(cname);
1618 return isInstanceOf(ci);
1623 * Returns true if the given class is an instance of the class
1624 * or interface specified.
1626 public boolean isInstanceOf (ClassInfo ci) {
1627 if (isPrimitive()) { // no inheritance for builtin types
1630 for (ClassInfo c = this; c != null; c = c.superClass) {
1636 return getAllInterfaces().contains(ci);
1640 public boolean isInnerClassOf (String enclosingName){
1641 // don't register or initialize yet
1642 ClassInfo ciEncl = classLoader.tryGetResolvedClassInfo( enclosingName);
1643 if (ciEncl != null){
1644 return ciEncl.hasInnerClass(name);
1650 public boolean hasInnerClass (String innerName){
1651 for (int i=0; i<innerClassNames.length; i++){
1652 if (innerClassNames[i].equals(innerName)){
1661 public static String makeModelClassPath (Config config) {
1662 StringBuilder buf = new StringBuilder(256);
1663 String ps = File.pathSeparator;
1666 for (File f : config.getPathArray("boot_classpath")){
1667 buf.append(f.getAbsolutePath());
1671 for (File f : config.getPathArray("classpath")){
1672 buf.append(f.getAbsolutePath());
1676 // finally, we load from the standard Java libraries
1677 v = System.getProperty("sun.boot.class.path");
1682 return buf.toString();
1685 protected static String[] loadArrayInterfaces () {
1686 return new String[] {"java.lang.Cloneable", "java.io.Serializable"};
1689 protected static String[] loadBuiltinInterfaces (String type) {
1690 return EMPTY_STRING_ARRAY;
1695 * Loads the ClassInfo for named class.
1697 void loadInterfaceRec (Set<ClassInfo> set, String[] interfaces) throws ClassInfoException {
1698 if (interfaces != null) {
1699 for (String iname : interfaces) {
1701 ClassInfo ci = classLoader.getResolvedClassInfo(iname);
1707 loadInterfaceRec(set, ci.interfaceNames);
1712 int computeInstanceDataOffset () {
1713 if (superClass == null) {
1716 return superClass.getInstanceDataSize();
1720 int getInstanceDataOffset () {
1721 return instanceDataOffset;
1724 ClassInfo getClassBase (String clsBase) {
1725 if ((clsBase == null) || (name.equals(clsBase))) return this;
1727 if (superClass != null) {
1728 return superClass.getClassBase(clsBase);
1731 return null; // Eeek - somebody asked for a class that isn't in the base list
1734 int computeInstanceDataSize () {
1735 int n = getDataSize( iFields);
1737 for (ClassInfo c=superClass; c!= null; c=c.superClass) {
1738 n += c.getDataSize(c.iFields);
1744 public int getInstanceDataSize () {
1745 return instanceDataSize;
1748 int getDataSize (FieldInfo[] fields) {
1750 for (int i=0; i<fields.length; i++) {
1751 n += fields[i].getStorageSize();
1757 public int getNumberOfDeclaredInstanceFields () {
1758 return iFields.length;
1761 public FieldInfo getDeclaredInstanceField (int i) {
1765 public int getNumberOfInstanceFields () {
1766 return nInstanceFields;
1769 public FieldInfo getInstanceField (int i) {
1770 int idx = i - (nInstanceFields - iFields.length);
1772 return ((idx < iFields.length) ? iFields[idx] : null);
1774 return ((superClass != null) ? superClass.getInstanceField(i) : null);
1778 public FieldInfo[] getInstanceFields(){
1779 FieldInfo[] fields = new FieldInfo[nInstanceFields];
1781 for (int i=0; i<fields.length; i++){
1782 fields[i] = getInstanceField(i);
1788 public int getStaticDataSize () {
1789 return staticDataSize;
1792 int computeStaticDataSize () {
1793 return getDataSize(sFields);
1796 public int getNumberOfStaticFields () {
1797 return sFields.length;
1800 protected Source loadSource () {
1801 return Source.getSource(sourceFileName);
1804 public static boolean isBuiltinClass (String cname) {
1805 char c = cname.charAt(0);
1808 if ((c == '[') || cname.endsWith("[]")) {
1812 // primitive type class
1813 if (Character.isLowerCase(c)) {
1814 if ("int".equals(cname) || "byte".equals(cname) ||
1815 "boolean".equals(cname) || "double".equals(cname) ||
1816 "long".equals(cname) || "char".equals(cname) ||
1817 "short".equals(cname) || "float".equals(cname) || "void".equals(cname)) {
1826 * set the locations where we look up sources
1828 static void setSourceRoots (Config config) {
1829 Source.init(config);
1833 * get names of all interfaceNames (transitive, idx.e. incl. bases and super-interfaceNames)
1834 * @return a Set of String interface names
1836 public Set<ClassInfo> getAllInterfaces () {
1837 if (allInterfaces == null) {
1838 HashSet<ClassInfo> set = new HashSet<ClassInfo>();
1840 for (ClassInfo ci=this; ci != null; ci=ci.superClass) {
1841 loadInterfaceRec(set, ci.interfaceNames);
1844 allInterfaces = Collections.unmodifiableSet(set);
1847 return allInterfaces;
1851 * get names of directly implemented interfaceNames
1853 public String[] getDirectInterfaceNames () {
1854 return interfaceNames;
1857 public Set<ClassInfo> getInterfaceClassInfos() {
1861 public Set<ClassInfo> getAllInterfaceClassInfos() {
1862 return getAllInterfaces();
1867 * get names of direct inner classes
1869 public String[] getInnerClasses(){
1870 return innerClassNames;
1873 public ClassInfo[] getInnerClassInfos(){
1874 ClassInfo[] innerClassInfos = new ClassInfo[innerClassNames.length];
1876 for (int i=0; i< innerClassNames.length; i++){
1877 innerClassInfos[i] = classLoader.getResolvedClassInfo(innerClassNames[i]); // ? is this supposed to use the same classloader
1880 return innerClassInfos;
1883 public BootstrapMethodInfo getBootstrapMethodInfo(int index) {
1884 return bootstrapMethods[index];
1887 public ClassInfo getComponentClassInfo () {
1889 String cn = name.substring(1);
1891 if (cn.charAt(0) != '[') {
1892 cn = Types.getTypeName(cn);
1895 ClassInfo cci = classLoader.getResolvedClassInfo(cn);
1904 * most definitely not a public method, but handy for the NativePeer
1906 protected Map<String, MethodInfo> getDeclaredMethods () {
1911 * be careful, this replaces or adds MethodInfos dynamically
1913 public MethodInfo putDeclaredMethod (MethodInfo mi){
1914 return methods.put(mi.getUniqueName(), mi);
1917 public MethodInfo[] getDeclaredMethodInfos() {
1918 MethodInfo[] a = new MethodInfo[methods.size()];
1919 methods.values().toArray(a);
1923 public Instruction[] getMatchingInstructions (LocationSpec lspec){
1924 Instruction[] insns = null;
1926 if (lspec.matchesFile(sourceFileName)){
1927 for (MethodInfo mi : methods.values()) {
1928 Instruction[] a = mi.getMatchingInstructions(lspec);
1930 if (insns != null) {
1931 // not very efficient but probably rare
1932 insns = Misc.appendArray(insns, a);
1937 // little optimization
1938 if (!lspec.isLineInterval()) {
1948 public List<MethodInfo> getMatchingMethodInfos (MethodSpec mspec){
1949 ArrayList<MethodInfo> list = null;
1950 if (mspec.matchesClass(name)) {
1951 for (MethodInfo mi : methods.values()) {
1952 if (mspec.matches(mi)) {
1954 list = new ArrayList<MethodInfo>();
1963 public MethodInfo getFinalizer () {
1967 public MethodInfo getClinit() {
1968 // <2do> braindead - cache
1969 for (MethodInfo mi : methods.values()) {
1970 if ("<clinit>".equals(mi.getName())) {
1977 public boolean hasCtors() {
1978 // <2do> braindead - cache
1979 for (MethodInfo mi : methods.values()) {
1980 if ("<init>".equals(mi.getName())) {
1988 * see getInitializedClassInfo() for restrictions.
1990 public static ClassInfo getInitializedSystemClassInfo (String clsName, ThreadInfo ti){
1991 ClassLoaderInfo systemLoader = ClassLoaderInfo.getCurrentSystemClassLoader();
1992 ClassInfo ci = systemLoader.getResolvedClassInfo(clsName);
1993 ci.initializeClassAtomic(ti);
1999 * this one is for clients that need to synchronously get an initialized classinfo.
2000 * NOTE: we don't handle clinits here. If there is one, this will throw
2001 * an exception. NO STATIC BLOCKS / FIELDS ALLOWED
2003 public static ClassInfo getInitializedClassInfo (String clsName, ThreadInfo ti){
2004 ClassLoaderInfo cl = ClassLoaderInfo.getCurrentClassLoader();
2005 ClassInfo ci = cl.getResolvedClassInfo(clsName);
2006 ci.initializeClassAtomic(ti);
2011 public boolean isRegistered () {
2012 //return (id != -1);
2013 return getStaticElementInfo() != null;
2017 * this registers a ClassInfo in the corresponding ClassLoader statics so that we can cross-link from
2018 * SUT code and access static fields.
2020 public StaticElementInfo registerClass (ThreadInfo ti){
2021 StaticElementInfo sei = getStaticElementInfo();
2024 // do this recursively for superclasses and interfaceNames
2025 // respective classes might be defined by another classloader, so we have to call their ClassInfo.registerClass()
2027 if (superClass != null) {
2028 superClass.registerClass(ti);
2031 for (ClassInfo ifc : interfaces) {
2032 ifc.registerClass(ti);
2035 ClassInfo.logger.finer("registering class: ", name);
2037 ElementInfo ei = createClassObject( ti);
2038 sei = createAndLinkStaticElementInfo( ti, ei);
2040 // SUT class is fully resolved and registered (but not necessarily initialized), notify listeners
2041 ti.getVM().notifyClassLoaded(this);
2047 ElementInfo createClassObject (ThreadInfo ti){
2048 Heap heap = VM.getVM().getHeap(); // ti can be null (during main thread initialization)
2050 int anchor = name.hashCode(); // 2do - this should also take the ClassLoader ref into account
2052 SystemClassLoaderInfo systemClassLoader = ti.getSystemClassLoaderInfo();
2054 ClassInfo classClassInfo = systemClassLoader.getClassClassInfo();
2055 ElementInfo ei = heap.newSystemObject(classClassInfo, ti, anchor);
2056 int clsObjRef = ei.getObjectRef();
2058 ElementInfo eiClsName = heap.newSystemString(name, ti, clsObjRef);
2059 ei.setReferenceField("name", eiClsName.getObjectRef());
2061 ei.setBooleanField("isPrimitive", isPrimitive());
2063 // setting the ID_FIELD is done in registerClass once we have a StaticElementInfo
2065 // link the SUT class object to the classloader
2066 ei.setReferenceField("classLoader", classLoader.getClassLoaderObjectRef());
2071 StaticElementInfo createAndLinkStaticElementInfo (ThreadInfo ti, ElementInfo eiClsObj) {
2072 Statics statics = classLoader.getStatics();
2073 StaticElementInfo sei = statics.newClass(this, ti, eiClsObj);
2075 id = sei.getObjectRef(); // kind of a misnomer, it's really an id
2076 uniqueId = ((long)classLoader.getId() << 32) | id;
2078 eiClsObj.setIntField( ID_FIELD, id);
2084 // for startup classes, the order of initialization is reversed since we can't create
2085 // heap objects before we have a minimal set of registered classes
2087 void registerStartupClass(ThreadInfo ti, List<ClassInfo> list) {
2088 if (!isRegistered()) {
2089 // do this recursively for superclasses and interfaceNames
2090 // respective classes might be defined by another classloader, so we have
2091 // to call their ClassInfo.registerClass()
2093 if (superClass != null) {
2094 superClass.registerStartupClass(ti, list);
2097 for (ClassInfo ifc : interfaces) {
2098 ifc.registerStartupClass(ti, list);
2102 if (!list.contains(this)) {
2104 ClassInfo.logger.finer("registering startup class: ", name);
2105 createStartupStaticElementInfo(ti);
2108 // SUT class is fully resolved and registered (but not necessarily initialized), notify listeners
2109 ti.getVM().notifyClassLoaded(this);
2112 StaticElementInfo createStartupStaticElementInfo (ThreadInfo ti) {
2113 Statics statics = classLoader.getStatics();
2114 StaticElementInfo sei = statics.newStartupClass(this, ti);
2116 id = sei.getObjectRef(); // kind of a misnomer, it's really an id
2117 uniqueId = ((long)classLoader.getId() << 32) | id;
2122 ElementInfo createAndLinkStartupClassObject (ThreadInfo ti) {
2123 StaticElementInfo sei = getStaticElementInfo();
2124 ElementInfo ei = createClassObject(ti);
2126 sei.setClassObjectRef(ei.getObjectRef());
2127 ei.setIntField( ID_FIELD, id);
2132 boolean checkIfValidClassClassInfo() {
2133 return getDeclaredInstanceField( ID_FIELD) != null;
2136 public boolean isInitializing () {
2137 StaticElementInfo sei = getStaticElementInfo();
2138 return ((sei != null) && (sei.getStatus() >= 0));
2142 * note - this works recursively upwards since there might
2143 * be a superclass with a clinit that is still executing
2145 public boolean isInitialized () {
2146 for (ClassInfo ci = this; ci != null; ci = ci.superClass){
2147 StaticElementInfo sei = ci.getStaticElementInfo();
2148 if (sei == null || sei.getStatus() != INITIALIZED){
2156 public boolean isResolved () {
2157 return (!isObjectClassInfo() && superClass != null);
2160 public boolean needsInitialization (ThreadInfo ti){
2161 StaticElementInfo sei = getStaticElementInfo();
2163 int status = sei.getStatus();
2164 if (status == INITIALIZED || status == ti.getId()){
2172 public void setInitializing(ThreadInfo ti) {
2173 StaticElementInfo sei = getModifiableStaticElementInfo();
2174 sei.setStatus(ti.getId());
2178 * initialize this class and its superclasses (but not interfaces)
2179 * this will cause execution of clinits of not-yet-initialized classes in this hierarchy
2181 * note - we don't treat registration/initialization of a class as
2182 * a sharedness-changing operation since it is done automatically by
2183 * the VM and the triggering action in the SUT (e.g. static field access or method call)
2184 * is the one that should update sharedness and/or break the transition accordingly
2186 * @return true - if initialization pushed DirectCallStackFrames and caller has to re-execute
2188 public boolean initializeClass(ThreadInfo ti){
2189 int pushedFrames = 0;
2191 // push clinits of class hierarchy (upwards, since call stack is LIFO)
2192 for (ClassInfo ci = this; ci != null; ci = ci.getSuperClass()) {
2193 StaticElementInfo sei = ci.getStaticElementInfo();
2195 sei = ci.registerClass(ti);
2198 int status = sei.getStatus();
2199 if (status != INITIALIZED){
2200 // we can't do setInitializing() yet because there is no global lock that
2201 // covers the whole clinit chain, and we might have a context switch before executing
2202 // a already pushed subclass clinit - there can be races as to which thread
2203 // does the static init first. Note this case is checked in INVOKECLINIT
2204 // (which is one of the reasons why we have it).
2206 if (status != ti.getId()) {
2207 // even if it is already initializing - if it does not happen in the current thread
2208 // we have to sync, which we do by calling clinit
2209 MethodInfo mi = ci.getMethod("<clinit>()V", false);
2211 DirectCallStackFrame frame = ci.createDirectCallStackFrame(ti, mi, 0);
2212 ti.pushFrame( frame);
2216 // it has no clinit, we can set it initialized
2217 ci.setInitialized();
2220 // ignore if it's already being initialized by our own thread (recursive request)
2223 break; // if this class is initialized, so are its superclasses
2227 return (pushedFrames > 0);
2231 * use this with care since it will throw a JPFException if we encounter a choice point
2232 * during execution of clinits
2233 * Use this mostly for wrapper exceptions and other system classes that are guaranteed to load
2235 public void initializeClassAtomic (ThreadInfo ti){
2236 for (ClassInfo ci = this; ci != null; ci = ci.getSuperClass()) {
2237 StaticElementInfo sei = ci.getStaticElementInfo();
2239 sei = ci.registerClass(ti);
2242 int status = sei.getStatus();
2243 if (status != INITIALIZED && status != ti.getId()){
2244 MethodInfo mi = ci.getMethod("<clinit>()V", false);
2246 DirectCallStackFrame frame = ci.createDirectCallStackFrame(ti, mi, 0);
2247 ti.executeMethodAtomic(frame);
2249 ci.setInitialized();
2252 break; // if this class is initialized, so are its superclasses
2257 public void setInitialized() {
2258 StaticElementInfo sei = getStaticElementInfo();
2259 if (sei != null && sei.getStatus() != INITIALIZED){
2260 sei = getModifiableStaticElementInfo();
2261 sei.setStatus(INITIALIZED);
2263 // we don't emit classLoaded() notifications for non-builtin classes
2264 // here anymore because it would be confusing to get instructionExecuted()
2265 // notifications from the <clinit> execution before the classLoaded()
2269 public StaticElementInfo getStaticElementInfo() {
2271 return classLoader.getStatics().get( id);
2277 public StaticElementInfo getModifiableStaticElementInfo() {
2279 return classLoader.getStatics().getModifiable( id);
2285 Fields createArrayFields (String type, int nElements, int typeSize, boolean isReferenceArray) {
2286 return fieldsFactory.createArrayFields( type, this,
2287 nElements, typeSize, isReferenceArray);
2291 * Creates the fields for a class. This gets called during registration of a ClassInfo
2293 Fields createStaticFields () {
2294 return fieldsFactory.createStaticFields(this);
2297 void initializeStaticData (ElementInfo ei, ThreadInfo ti) {
2298 for (int i=0; i<sFields.length; i++) {
2299 FieldInfo fi = sFields[i];
2300 fi.initialize(ei, ti);
2305 * Creates the fields for an object.
2307 public Fields createInstanceFields () {
2308 return fieldsFactory.createInstanceFields(this);
2311 void initializeInstanceData (ElementInfo ei, ThreadInfo ti) {
2312 // Note this is only used for field inits, and array elements are not fields!
2313 // Since Java has only limited element init requirements (either 0 or null),
2314 // we do this ad hoc in the ArrayFields ctor
2316 // the order of inits should not matter, since this is only
2317 // for constant inits. In case of a "class X { int a=42; int b=a; ..}"
2318 // we have a explicit "GETFIELD a, PUTFIELD b" in the ctor, but to play it
2319 // safely we init top down
2321 if (superClass != null) { // do superclasses first
2322 superClass.initializeInstanceData(ei, ti);
2325 for (int i=0; i<iFields.length; i++) {
2326 FieldInfo fi = iFields[i];
2327 fi.initialize(ei, ti);
2331 Map<String, MethodInfo> loadArrayMethods () {
2332 return new HashMap<String, MethodInfo>(0);
2335 Map<String, MethodInfo> loadBuiltinMethods (String type) {
2336 type = null; // Get rid of IDE warning
2338 return new HashMap<String, MethodInfo>(0);
2341 protected ClassInfo loadSuperClass (String superName) throws ClassInfoException {
2342 if (isObjectClassInfo()) {
2346 logger.finer("resolving superclass: ", superName, " of ", name);
2348 // resolve the superclass
2349 ClassInfo sci = resolveReferencedClass(superName);
2354 protected Set<ClassInfo> loadInterfaces (String[] ifcNames) throws ClassInfoException {
2355 if (ifcNames == null || ifcNames.length == 0){
2356 return NO_INTERFACES;
2359 Set<ClassInfo> set = new HashSet<ClassInfo>();
2361 for (String ifcName : ifcNames) {
2362 ClassInfo.logger.finer("resolving interface: ", ifcName, " of ", name);
2363 ClassInfo ifc = resolveReferencedClass(ifcName);
2372 * loads superclass and direct interfaces, and computes information
2373 * that depends on them
2375 protected void resolveClass() {
2376 if (!isObjectClassInfo){
2377 superClass = loadSuperClass(superClassName);
2378 releaseActions = superClass.releaseActions;
2380 interfaces = loadInterfaces(interfaceNames);
2382 //computeInheritedAnnotations(superClass);
2384 isWeakReference = isWeakReference0();
2389 * get a ClassInfo for a referenced type that is resolved with the same classLoader, but make
2390 * sure we only do this once per path
2392 * This method is called by the following bytecode instructions:
2393 * anewarray, checkcast, getstatic, instanceof, invokespecial,
2394 * invokestatic, ldc, ldc_w, multianewarray, new, and putstatic
2396 * It loads the class referenced by these instructions and adds it to the
2397 * resolvedClasses map of the classLoader
2399 public ClassInfo resolveReferencedClass(String cname) {
2400 if(name.equals(cname)) {
2404 // if the class has been already resolved just return it
2405 ClassInfo ci = classLoader.getAlreadyResolvedClassInfo(cname);
2410 // The defining class loader of the class initiate the load of referenced classes
2411 ci = classLoader.loadClass(cname);
2412 classLoader.addResolvedClass(ci);
2417 protected int linkFields (FieldInfo[] fields, int idx, int off){
2418 for (FieldInfo fi: fields) {
2419 fi.linkToClass(this, idx, off);
2421 int storageSize = fi.getStorageSize();
2429 protected void linkFields() {
2430 //--- instance fields
2431 if(superClass != null) {
2432 int superDataSize = superClass.instanceDataSize;
2433 instanceDataSize = linkFields( iFields, superClass.nInstanceFields, superDataSize);
2434 nInstanceFields = superClass.nInstanceFields + iFields.length;
2435 instanceDataOffset = superClass.instanceDataSize;
2438 instanceDataSize = linkFields( iFields, 0, 0);
2439 nInstanceFields = iFields.length;
2440 instanceDataOffset = 0;
2444 staticDataSize = linkFields( sFields, 0, 0);
2447 // this resolves all annotations in this class hierarchy, which sets inherited attributes
2448 protected void checkInheritedAnnotations (){
2453 public String toString() {
2454 return "ClassInfo[name=" + name + "]";
2457 protected MethodInfo getFinalizer0 () {
2458 MethodInfo mi = getMethod("finalize()V", true);
2460 // we are only interested in non-empty method bodies, Object.finalize()
2462 if ((mi != null) && (!mi.getClassInfo().isObjectClassInfo())) {
2469 protected boolean isObjectClassInfo0 () {
2470 if (name.equals("java.lang.Object")) {
2476 protected boolean isStringClassInfo0 () {
2477 if(name.equals("java.lang.String")) {
2483 protected boolean isRefClassInfo0 () {
2484 if(name.equals("java.lang.ref.Reference")) {
2490 protected boolean isWeakReference0 () {
2491 if(name.equals("java.lang.ref.WeakReference")) {
2495 for (ClassInfo ci = this; !ci.isObjectClassInfo(); ci = ci.superClass) {
2496 if (ci.isWeakReference()) {
2504 protected boolean isEnum0 () {
2505 if(name.equals("java.lang.Enum")) {
2509 for (ClassInfo ci = this; !ci.isObjectClassInfo(); ci = ci.superClass) {
2518 protected boolean isThreadClassInfo0 () {
2519 if(name.equals("java.lang.Thread")) {
2527 * It creates an instance from a original ClassInfo instance. It doesn't copy sei &
2530 * It is used for the cases where cl tries to load a class that the original version
2531 * of which has been loaded by some other classloader.
2533 public ClassInfo cloneFor (ClassLoaderInfo cl) {
2537 ci = (ClassInfo)clone();
2539 ci.classLoader = cl;
2540 ci.interfaces = new HashSet<ClassInfo>();
2546 if (methods != Collections.EMPTY_MAP){
2547 ci.methods = (Map<String, MethodInfo>)((HashMap<String, MethodInfo>) methods).clone();
2550 for(Map.Entry<String, MethodInfo> e: ci.methods.entrySet()) {
2551 MethodInfo mi = e.getValue();
2552 e.setValue(mi.getInstanceFor(ci));
2555 ci.iFields = new FieldInfo[iFields.length];
2556 for(int i=0; i<iFields.length; i++) {
2557 ci.iFields[i] = iFields[i].getInstanceFor(ci);
2560 ci.sFields = new FieldInfo[sFields.length];
2561 for(int i=0; i<sFields.length; i++) {
2562 ci.sFields[i] = sFields[i].getInstanceFor(ci);
2565 if(nativePeer != null) {
2566 ci.nativePeer = NativePeer.getNativePeer(ci);
2569 ci.setAssertionStatus();
2571 } catch (CloneNotSupportedException cnsx){
2572 cnsx.printStackTrace();
2576 VM.getVM().notifyClassLoaded(ci);
2580 // <2do> should be abstract
2581 public StackFrame createStackFrame (ThreadInfo ti, MethodInfo callee){
2585 public DirectCallStackFrame createDirectCallStackFrame (ThreadInfo ti, MethodInfo callee, int nLocalSlots){
2589 public DirectCallStackFrame createRunStartStackFrame (ThreadInfo ti, MethodInfo miRun){