00001 package gov.nasa.arc.ase.jpf.jvm;
00002
00003 import de.fub.bytecode.Repository;
00004 import de.fub.bytecode.classfile.Field;
00005 import de.fub.bytecode.classfile.JavaClass;
00006 import de.fub.bytecode.classfile.Method;
00007 import gov.nasa.arc.ase.jpf.Engine;
00008 import gov.nasa.arc.ase.jpf.InternalErrorException;
00009 import gov.nasa.arc.ase.jpf.JPFErrorException;
00010 import gov.nasa.arc.ase.jpf.SafeBlocks;
00011 import gov.nasa.arc.ase.jpf.jvm.bytecode.Instruction;
00012 import gov.nasa.arc.ase.jpf.jvm.reflection.Reflection;
00013 import gov.nasa.arc.ase.util.Debug;
00014 import java.io.BufferedReader;
00015 import java.io.File;
00016 import java.io.FileNotFoundException;
00017 import java.io.FileReader;
00018 import java.util.Hashtable;
00019
00020 import gov.nasa.arc.ase.util.BSet;
00021 import gov.nasa.arc.ase.util.ArrayBSet;
00022
00023
00024
00025
00026
00027 public class ClassInfo {
00028
00029
00030
00031 private static Hashtable loadedClasses = new Hashtable();
00032
00033
00034
00035
00036 private static Hashtable safeBlocksPool = new Hashtable();
00037
00038
00039
00040
00041 private String name;
00042
00043
00044
00045
00046 private MethodInfo[] staticMethods;
00047
00048
00049
00050
00051 private MethodInfo[] dynamicMethods;
00052
00053
00054
00055
00056 private FieldInfo[] staticFields;
00057
00058
00059
00060
00061 private FieldInfo[] dynamicFields;
00062
00063
00064
00065
00066 private SafeBlocks safeBlocks;
00067
00068
00069
00070
00071 private ClassInfo superClass;
00072
00073
00074
00075
00076 private String[] interfaces;
00077
00078
00079
00080
00081 private String packageName;
00082
00083
00084
00085
00086 private String sourceFileName;
00087
00088
00089
00090
00091 private Reflection reflection;
00092
00093
00094
00095
00096 private Source source;
00097
00098
00099
00100
00101
00102
00103 private BSet dRefs;
00104
00105
00106
00107
00108 private BSet sRefs;
00109
00110
00111
00112
00113
00114
00115
00116 private ClassInfo(JavaClass jc) {
00117 name = jc.getClassName();
00118
00119 loadedClasses.put(name, this);
00120
00121 superClass = loadSuperClass(jc);
00122 staticMethods = loadStaticMethods(jc);
00123 dynamicMethods = loadDynamicMethods(jc);
00124 staticFields = loadStaticFields(jc);
00125 dynamicFields = loadDynamicFields(jc);
00126 interfaces = loadInterfaces(jc);
00127 packageName = jc.getPackageName();
00128 sourceFileName = jc.getSourceFileName();
00129
00130 safeBlocks = loadSafeBlocks();
00131 reflection = loadReflection();
00132 reflection.setClassInfo(this);
00133
00134 dRefs = loadRefs(dynamicFields);
00135 sRefs = loadRefs(staticFields);
00136
00137
00138 source = null;
00139 }
00140
00141
00142
00143 public Fields createClassFields() {
00144 FieldInfo[] fs = staticFields;
00145 int size = fs.length;
00146 int length = 0;
00147 for(int i = 0; i < size; i++)
00148 if(fs[i] != null)
00149 length++;
00150
00151 Fields f = new Fields(getType(), this, size, length, true
00152
00153 , sRefs
00154
00155 );
00156 for(int i = 0; i < length; ) {
00157 String t = fs[i].getType();
00158 switch(Types.getBaseType(t)) {
00159 case Types.T_BYTE:
00160 case Types.T_CHAR:
00161 case Types.T_FLOAT:
00162 case Types.T_INT:
00163 case Types.T_SHORT:
00164 case Types.T_BOOLEAN:
00165 f.setField(i, 0);
00166 break;
00167
00168 case Types.T_DOUBLE:
00169 case Types.T_LONG:
00170 f.setLongField(i, 0);
00171 break;
00172
00173 case Types.T_REFERENCE:
00174 case Types.T_ARRAY:
00175 f.setField(i, -1);
00176 break;
00177
00178 default:
00179 throw new InternalErrorException("invalid type");
00180 }
00181 i += Types.getTypeSize(t);
00182 }
00183
00184 return f;
00185 }
00186
00187
00188
00189 public ThreadInfo createMainThread(SystemState ss, String[] args) {
00190 int tObjref = ss.ks.da.newObject(
00191 ClassInfo.getClassInfo("java/lang/Thread"),
00192 null);
00193 ThreadInfo th = ss.ks.newThread(tObjref);
00194
00195 MethodInfo mi = getStaticMethod("main([Ljava/lang/String;)V");
00196
00197 if(mi == null)
00198 throw new JPFErrorException("main method not defined in " + name);
00199
00200 th.newFrame(mi);
00201
00202 int argsObjref = ss.ks.da.newArray(
00203 "Ljava/lang/String;",
00204 args.length,
00205 null);
00206 ElementInfo argsElement = ss.ks.da.get(argsObjref);
00207
00208 for(int i = 0; i < args.length; i++) {
00209 int stringObjref = ss.ks.da.newString(args[i], null);
00210 argsElement.setField(i, stringObjref);
00211 }
00212
00213 th.setLocalVariable(0, argsObjref, true);
00214
00215 th.setStatus(ThreadInfo.RUNNING);
00216
00217
00218
00219
00220
00221
00222 return th;
00223 }
00224
00225
00226
00227 public Fields createObjectFields() {
00228 FieldInfo[] fs = dynamicFields;
00229 int size = fs.length;
00230 int length = 0;
00231 for(int i = 0; i < size; i++)
00232 if(fs[i] != null)
00233 length++;
00234
00235 Fields f = new Fields(getType(), this, size, length, false
00236
00237 , dRefs
00238
00239 );
00240 for(int i = 0; i < length; i++) {
00241 if(fs[i] != null) {
00242 switch(Types.getBaseType(fs[i].getType())) {
00243 case Types.T_BYTE:
00244 case Types.T_CHAR:
00245 case Types.T_FLOAT:
00246 case Types.T_INT:
00247 case Types.T_SHORT:
00248 case Types.T_BOOLEAN:
00249 f.setField(i, 0);
00250 break;
00251
00252 case Types.T_DOUBLE:
00253 case Types.T_LONG:
00254 f.setLongField(i, 0);
00255 break;
00256
00257 case Types.T_REFERENCE:
00258 case Types.T_ARRAY:
00259 f.setField(i, -1);
00260 break;
00261
00262 default:
00263 throw new InternalErrorException("invalid type");
00264 }
00265 }
00266 }
00267
00268 return f;
00269 }
00270
00271
00272
00273 public int dynamicFieldIndex(String fname) {
00274 int length = dynamicFields.length;
00275
00276 for(int i = 0; i < length; i++)
00277 if(dynamicFields[i] != null && dynamicFields[i].getName().equals(fname))
00278 return i;
00279
00280 throw new InternalErrorException("class " + getName() + "does not have field `" + fname + "'");
00281 }
00282
00283
00284
00285 public Instruction executeMethod(ThreadInfo th, String mname) {
00286 MethodInfo mi = getDynamicMethod(mname);
00287
00288 Reflection r = reflection.instantiate(th.getCalleeThis(mi));
00289 th.createMethodStackFrame(mi);
00290
00291 return r.executeMethod(th, mi);
00292 }
00293
00294
00295
00296 public Instruction executeStaticMethod(ThreadInfo th, String mname) {
00297 MethodInfo mi = getStaticMethod(mname);
00298
00299 Reflection r = reflection.instantiate();
00300 th.createMethodStackFrame(mi);
00301
00302 return r.executeStaticMethod(th, mi);
00303 }
00304 public static boolean exists(String cname) {
00305 return Repository.lookupClass(cname) != null;
00306 }
00307
00308
00309
00310 public static synchronized ClassInfo getClassInfo(String cname) {
00311 if(cname == null) return null;
00312
00313 cname = cname.replace('/', '.');
00314
00315 ClassInfo ci = (ClassInfo)loadedClasses.get(cname);
00316
00317 if(ci == null) {
00318 JavaClass jc = Repository.lookupClass(cname);
00319
00320 if(jc == null)
00321 throw new JPFErrorException("could not load class " + cname);
00322
00323 Repository.clearCache();
00324
00325 ci = new ClassInfo(jc);
00326 }
00327
00328 return ci;
00329 }
00330
00331
00332
00333 public FieldInfo getDynamicField(int index) {
00334 return dynamicFields[index];
00335 }
00336
00337
00338
00339 public String getDynamicFieldName(int index) {
00340 return dynamicFields[index].getName();
00341 }
00342
00343
00344
00345 public MethodInfo getDynamicMethod(String mname) {
00346 for(int i = 0, l = dynamicMethods.length; i < l; i++)
00347 if(dynamicMethods[i].getFullName().equals(mname))
00348 return dynamicMethods[i];
00349
00350 if(superClass != null)
00351 return superClass.getDynamicMethod(mname);
00352
00353 return null;
00354 }
00355
00356
00357
00358 public String getName() {
00359 return name;
00360 }
00361
00362
00363
00364 public Reflection getReflection() {
00365 return reflection;
00366 }
00367 public Source getSource() {
00368 if(source == null)
00369 source = loadSource();
00370
00371 return source;
00372 }
00373 public String getSourceFileName() {
00374 return sourceFileName;
00375 }
00376
00377
00378
00379 public FieldInfo getStaticField(int index) {
00380 return staticFields[index];
00381 }
00382
00383
00384
00385 public String getStaticFieldName(int index) {
00386 return staticFields[index].getName();
00387 }
00388
00389
00390
00391 public MethodInfo getStaticMethod(String mname) {
00392 for(int i = 0, l = staticMethods.length; i < l; i++)
00393 if(staticMethods[i].getFullName().equals(mname))
00394 return staticMethods[i];
00395
00396
00397 if(mname.equals("<clinit>()V"))
00398 return null;
00399
00400 if(superClass != null)
00401 return superClass.getStaticMethod(mname);
00402
00403 return null;
00404 }
00405
00406
00407
00408 public ClassInfo getSuperClass() {
00409 return superClass;
00410 }
00411
00412
00413
00414 public String getType() {
00415 return "L" + name.replace('.', '/') + ";";
00416 }
00417
00418
00419
00420 public boolean instanceOf(ClassInfo ci) {
00421 if(this == ci) return true;
00422
00423 if(superClass != null)
00424 return superClass.instanceOf(ci);
00425
00426 return false;
00427 }
00428
00429
00430
00431
00432 public boolean instanceOf(String cname) {
00433 cname = cname.replace('/', '.');
00434
00435 if(name.equals(cname)) return true;
00436
00437 for(int i = 0, l = interfaces.length; i < l; i++)
00438 if(interfaces[i].equals(cname))
00439 return true;
00440
00441 if(superClass != null)
00442 return superClass.instanceOf(cname);
00443
00444 return false;
00445 }
00446
00447
00448
00449 public boolean isMethodDeterministic(ThreadInfo th, String mname) {
00450 MethodInfo mi = getDynamicMethod(mname);
00451
00452 Reflection r = reflection.instantiate(th.getCalleeThis(mi));
00453
00454 return r.isMethodDeterministic(th, mi);
00455 }
00456
00457
00458
00459 public boolean isMethodExecutable(ThreadInfo th, String mname) {
00460 MethodInfo mi = getDynamicMethod(mname);
00461
00462 Reflection r = reflection.instantiate(th.getCalleeThis(mi));
00463
00464 return r.isMethodExecutable(th, mi);
00465 }
00466
00467
00468
00469 public boolean isSafe(int line) {
00470 if (safeBlocks == null)
00471 return false;
00472 else
00473 return safeBlocks.isSafe(line);
00474 }
00475
00476
00477
00478 public boolean isStaticMethodDeterministic(ThreadInfo th, String mname) {
00479 MethodInfo mi = getStaticMethod(mname);
00480
00481 Reflection r = reflection.instantiate();
00482
00483 return r.isStaticMethodDeterministic(th, mi);
00484 }
00485
00486
00487
00488 public boolean isStaticMethodExecutable(ThreadInfo th, String mname) {
00489 MethodInfo mi = getStaticMethod(mname);
00490
00491 Reflection r = reflection.instantiate();
00492
00493 return r.isStaticMethodExecutable(th, mi);
00494 }
00495
00496
00497
00498 public boolean isSystemClass() {
00499 return name.startsWith("java.lang.") || name.startsWith("java.util.");
00500 }
00501
00502
00503
00504 private FieldInfo[] loadDynamicFields(JavaClass jc) {
00505 Field[] fields = jc.getFields();
00506
00507 int counter = 0;
00508
00509 for(int i = 0, l = fields.length; i < l; i++)
00510 if(!fields[i].isStatic())
00511 counter += Types.getTypeSize(fields[i].getSignature().toString());
00512
00513 if(superClass != null)
00514 counter += superClass.dynamicFields.length;
00515
00516 FieldInfo[] dFields = new FieldInfo[counter];
00517
00518 if(superClass != null) {
00519 counter = superClass.dynamicFields.length;
00520 System.arraycopy(superClass.dynamicFields, 0, dFields, 0, counter);
00521 } else
00522 counter = 0;
00523
00524 for(int i = 0, l = fields.length; i < l; i++)
00525 if(!fields[i].isStatic()) {
00526 dFields[counter] = new FieldInfo(fields[i], this);
00527 counter += Types.getTypeSize(fields[i].getSignature().toString());
00528 }
00529
00530 return dFields;
00531 }
00532
00533
00534
00535 private MethodInfo[] loadDynamicMethods(JavaClass jc) {
00536 Method[] methods = jc.getMethods();
00537
00538 int counter = 0;
00539 for(int i = 0, l = methods.length; i < l; i++)
00540 if(!methods[i].isStatic())
00541 counter++;
00542
00543 MethodInfo[] dMethods = new MethodInfo[counter];
00544
00545 counter = 0;
00546 for(int i = 0, l = methods.length; i < l; i++)
00547 if(!methods[i].isStatic())
00548 dMethods[counter++] = new MethodInfo(methods[i], this);
00549
00550 return dMethods;
00551 }
00552
00553
00554
00555 private static String[] loadInterfaces(JavaClass jc) {
00556 int[] intInterfaces = jc.getInterfaces();
00557
00558 String[] stringInterfaces = new String[intInterfaces.length];
00559
00560 for(int i = 0, l = intInterfaces.length; i < l; i++)
00561 stringInterfaces[i] =
00562 jc.getConstantPool().getConstant(
00563 intInterfaces[i]
00564 ).toString().replace('/', '.');
00565
00566 return stringInterfaces;
00567 }
00568
00569
00570
00571 private Reflection loadReflection() {
00572 return Reflection.load(name);
00573 }
00574
00575
00576 private static BSet loadRefs(FieldInfo[] f) {
00577 int l = f.length;
00578 boolean[] refs = new boolean[l];
00579
00580 for(int i = 0; i < l; i++)
00581 refs[i] = f[i] != null && Types.isReference(f[i].getType());
00582
00583 return new ArrayBSet(refs);
00584 }
00585
00586
00587
00588 private SafeBlocks loadSafeBlocks() {
00589 if(!Engine.options.po_reduction) return null;
00590
00591 String fname = packageName.replace('.', File.separatorChar) +
00592 File.separator + sourceFileName.substring(0, sourceFileName.length() - 5);
00593
00594 for(int i = 0, l = ClassPath.length(); i < l; i++) {
00595 String filename = ClassPath.get(i) + File.separator + fname + ".safe";
00596 SafeBlocks s = loadSafeBlocks(filename);
00597
00598 if(s != null) return s;
00599 }
00600
00601 return null;
00602 }
00603 private SafeBlocks loadSafeBlocks(String fname) {
00604 SafeBlocks s = (SafeBlocks)safeBlocksPool.get(fname);
00605
00606 if(s == null) {
00607 try {
00608 BufferedReader in = new BufferedReader(new FileReader(fname));
00609 Debug.println(Debug.WARNING, "Loading " + fname);
00610 safeBlocksPool.put(fname, s = new SafeBlocks(in));
00611 } catch (FileNotFoundException e) {
00612 }
00613 }
00614
00615 return s;
00616 }
00617 private Source loadSource() {
00618 return Source.getSource(packageName.replace('.', File.separatorChar) +
00619 File.separator + sourceFileName);
00620 }
00621
00622
00623
00624 private FieldInfo[] loadStaticFields(JavaClass jc) {
00625 Field[] fields = jc.getFields();
00626
00627 int counter = 0;
00628
00629 for(int i = 0, l = fields.length; i < l; i++)
00630 if(fields[i].isStatic())
00631 counter += Types.getTypeSize(fields[i].getSignature().toString());
00632
00633 FieldInfo[] sFields = new FieldInfo[counter];
00634
00635 counter = 0;
00636 for(int i = 0, l = fields.length; i < l; i++)
00637 if(fields[i].isStatic()) {
00638 sFields[counter] = new FieldInfo(fields[i], this);
00639 counter += Types.getTypeSize(fields[i].getSignature().toString());
00640 }
00641
00642 return sFields;
00643 }
00644
00645
00646
00647 private MethodInfo[] loadStaticMethods(JavaClass jc) {
00648 Method[] methods = jc.getMethods();
00649
00650 int counter = 0;
00651 for(int i = 0, l = methods.length; i < l; i++)
00652 if(methods[i].isStatic())
00653 counter++;
00654
00655 MethodInfo[] sMethods = new MethodInfo[counter];
00656
00657 counter = 0;
00658 for(int i = 0, l = methods.length; i < l; i++)
00659 if(methods[i].isStatic())
00660 sMethods[counter++] = new MethodInfo(methods[i], this);
00661
00662 return sMethods;
00663 }
00664
00665
00666
00667 private static ClassInfo loadSuperClass(JavaClass jc) {
00668 if(jc.getClassName().equals("java.lang.Object"))
00669 return null;
00670
00671 return ClassInfo.getClassInfo(jc.getSuperclassName());
00672 }
00673
00674
00675
00676 public int staticFieldIndex(String fname) {
00677 int length = staticFields.length;
00678
00679 for(int i = 0; i < length; i++)
00680 if(staticFields[i] != null && staticFields[i].getName().equals(fname))
00681 return i;
00682
00683 throw new InternalErrorException("class " + getName() + " does not have static field `" + fname + "'");
00684 }
00685 }