00001 package edu.ksu.cis.bandera.pdgslicer;
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 import ca.mcgill.sable.util.*;
00037 import ca.mcgill.sable.soot.*;
00038 import ca.mcgill.sable.soot.jimple.*;
00039 import edu.ksu.cis.bandera.pdgslicer.exceptions.*;
00040 import edu.ksu.cis.bandera.annotation.*;
00041
00042
00043 import java.util.Enumeration;
00044 import java.util.Vector;
00045 import java.util.BitSet;
00046 import java.util.Hashtable;
00047
00048
00049
00050
00051 public class LockAnalysis {
00052 private StmtGraph stmtGraph;
00053 private StmtList stmtList;
00054 private BuildPDG pdgDom;
00055 private MethodInfo mdInfo;
00056
00057
00058
00059 private List lockPairList;
00060
00061
00062
00063
00064
00065 private List waitStmtList;
00066
00067
00068
00069 private List notifyStmtList;
00070
00071
00072
00073
00074 public LockAnalysis(MethodInfo methodInfo, AnnotationManager cfanns) {
00075 mdInfo = methodInfo;
00076 stmtList = methodInfo.originalStmtList;
00077 stmtGraph = methodInfo.indexMaps.getStmtGraph();
00078 pdgDom = methodInfo.methodPDG;
00079 buildLockPairList(cfanns);
00080 collectWaitNotifyStmt();
00081 if (lockPairList.isEmpty() && waitStmtList.isEmpty() && notifyStmtList.isEmpty())
00082 pdgDom.setLockAnalysis(null);
00083 else
00084 pdgDom.setLockAnalysis(this);
00085 }
00086
00087
00088
00089
00090
00091 private void buildLockPairList(AnnotationManager cfanns) {
00092 lockPairList = new ArrayList();
00093 SootMethod sm = mdInfo.sootMethod;
00094 SootClass sootClass = mdInfo.sootClass;
00095 Annotation annForSm = cfanns.getAnnotation(sootClass, sm);
00096 Vector synchAnnotations = getSynchAnnotation(stmtList, annForSm);
00097 for (Enumeration e = synchAnnotations.elements(); e.hasMoreElements();) {
00098 SynchronizedStmtAnnotation cfann = (SynchronizedStmtAnnotation) e.nextElement();
00099 SynchronizedStmtAnnotation synchCFANN = (SynchronizedStmtAnnotation) cfann;
00100 Stmt enterMonitorStmt = synchCFANN.getEnterMonitor();
00101 MonitorPair mp = new MonitorPair();
00102 mp.setSynchroBodyAnn(synchCFANN.getBlockAnnotation());
00103 mp.setCatchAnn(synchCFANN.getCatchAnnotation());
00104 Stmt synchroStmts[] = synchCFANN.getStatements();
00105 mp.setBeginSynchroStmt(synchroStmts[0]);
00106 mp.setEndSynchroStmt(synchroStmts[synchroStmts.length - 1]);
00107 mp.setEnterMonitor((EnterMonitorStmt) enterMonitorStmt);
00108 mp.setExitMonitors(synchCFANN.getExitMonitors().elements());
00109 mp.setLock(getActualLock(enterMonitorStmt));
00110 Annotation catchAnn = synchCFANN.getCatchAnnotation();
00111 Stmt catchStmts[] = catchAnn.getStatements();
00112 mp.setExitMonitorInException(catchStmts[1]);
00113 lockPairList.add(mp);
00114 }
00115 }
00116
00117
00118
00119
00120
00121 private void collectWaitNotifyStmt() {
00122 waitStmtList = new ArrayList();
00123 notifyStmtList = new ArrayList();
00124 Iterator stmtIt = stmtList.iterator();
00125 while (stmtIt.hasNext()) {
00126 Stmt stmt = (Stmt) stmtIt.next();
00127 if (stmt instanceof InvokeStmt) {
00128 Value expr = ((InvokeStmt) stmt).getInvokeExpr();
00129 if (expr instanceof VirtualInvokeExpr) {
00130 VirtualInvokeExpr vie = (VirtualInvokeExpr) expr;
00131 if (vie.getMethod().getName().equals("wait") && (vie.getType() instanceof VoidType) && vie.getArgCount() == 0) {
00132 SynchroStmt synStmt = new SynchroStmt(stmt, "wait");
00133
00134 synStmt.setLock(vie.getBase());
00135 waitStmtList.add(synStmt);
00136 } else
00137 if ((vie.getMethod().getName().equals("notify") || vie.getMethod().getName().equals("notifyAll")) && vie.getType() instanceof VoidType && vie.getArgCount() == 0) {
00138 SynchroStmt synStmt = new SynchroStmt(stmt, vie.getMethod().getName());
00139
00140 synStmt.setLock(vie.getBase());
00141 notifyStmtList.add(synStmt);
00142 }
00143 }
00144 }
00145 }
00146 }
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161 public Hashtable dependOnMonitorPairs(Stmt stmt)
00162 {
00163 List monitorPairList = dependOnMonitors(stmt);
00164 Hashtable monitorPairs = new Hashtable();
00165 for (Iterator listIt = monitorPairList.iterator(); listIt.hasNext();) {
00166 MonitorPair monitorPair = (MonitorPair) listIt.next();
00167 Stmt monitorStmt = (Stmt) monitorPair.getEnterMonitor();
00168
00169
00170
00171
00172 monitorPairs.put(monitorStmt, monitorPair);
00173 }
00174 return monitorPairs;
00175 }
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191 public List dependOnMonitors(Stmt stmt) {
00192 List monitorPairList = new ArrayList();
00193 Iterator lockPairIt = lockPairList.iterator();
00194 while (lockPairIt.hasNext()) {
00195 MonitorPair lockPair = (MonitorPair) lockPairIt.next();
00196 BitSet codeBetweenMonitor = stmtsBetween(lockPair);
00197 if (codeBetweenMonitor.get(stmtList.indexOf(stmt)))
00198 monitorPairList.add(lockPair);
00199 }
00200 return monitorPairList;
00201 }
00202
00203
00204
00205
00206
00207
00208
00209 public BitSet dependOnMonitorSet(Stmt stmt)
00210
00211 {
00212 List monitorPairList = dependOnMonitors(stmt);
00213 Set monitorSet = new ArraySet();
00214 for (Iterator listIt = monitorPairList.iterator(); listIt.hasNext();) {
00215 MonitorPair monitorPair = (MonitorPair) listIt.next();
00216 Stmt monitorStmt = (Stmt) monitorPair.getEnterMonitor();
00217 monitorSet.add(monitorStmt);
00218 Set exitMonitorSet = exitMonitorsIn(monitorPair);
00219 monitorSet.addAll(exitMonitorSet);
00220 }
00221 return SetUtil.stmtSetToBitSet(monitorSet,stmtList);
00222 }
00223
00224
00225
00226
00227
00228
00229 public Set exitMonitorsIn(MonitorPair mp) {
00230 Set exitMonitorIndexSet = new ArraySet();
00231 for (Iterator exitIt = mp.getExitMonitors().iterator(); exitIt.hasNext();) {
00232 Stmt exitMonitor = (Stmt) exitIt.next();
00233 if (exitMonitor != null)
00234
00235
00236
00237 exitMonitorIndexSet.add(exitMonitor);
00238 }
00239 Stmt exitMonitorInException = mp.getExitMonitorInException();
00240 Stmt endSynchroStmt = mp.getEndSynchroStmt();
00241 int exitMonitorInExceptionIndex = stmtList.indexOf(exitMonitorInException);
00242 int endSynchroStmtIndex = stmtList.indexOf(endSynchroStmt);
00243 for (int i = exitMonitorInExceptionIndex; i < endSynchroStmtIndex; i++)
00244 exitMonitorIndexSet.add((Stmt) stmtList.get(i));
00245 return exitMonitorIndexSet;
00246 }
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257 public Value getActualLock(Stmt monitorStmt) {
00258 if (!(monitorStmt instanceof EnterMonitorStmt) && !(monitorStmt instanceof ExitMonitorStmt))
00259 throw new MonitorStmtInstanceException("The statement monitorStmt should be an EnterMonitor or ExitMonitor Stmt in getActualLock of LockAnalysis");
00260 Value lock;
00261 if (monitorStmt instanceof EnterMonitorStmt)
00262 lock = ((EnterMonitorStmt) monitorStmt).getOp();
00263 else
00264
00265 lock = ((ExitMonitorStmt) monitorStmt).getOp();
00266
00267 return lock;
00268 }
00269
00270
00271
00272
00273
00274 public List getLockPairList()
00275 {
00276 return lockPairList;
00277 }
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287 public MonitorPair getMonitorPair(Stmt monitor) {
00288 if (monitor instanceof EnterMonitorStmt)
00289 return getMonitorPairFromEnter(monitor);
00290 else
00291 if (monitor instanceof ExitMonitorStmt)
00292 return getMonitorPairFromExit(monitor);
00293 else
00294 throw new StatementTypeException("The statement should be entermonitor or exitmonitor statement : " + monitor + " in LockAnalysis");
00295 }
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305 private MonitorPair getMonitorPairFromEnter(Stmt enterMonitor) {
00306 for (Iterator lockPairIt = lockPairList.iterator(); lockPairIt.hasNext();) {
00307 MonitorPair lockPair = (MonitorPair) lockPairIt.next();
00308 Stmt lockStmt = (Stmt) lockPair.getEnterMonitor();
00309 if (enterMonitor.equals(lockStmt))
00310 return lockPair;
00311 }
00312 throw new CorrespondingMonitorNotFoundException("Can't find the corresponding monitor pair according to the statement (index) : " + enterMonitor + " in LockAnalysis");
00313 }
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323 private MonitorPair getMonitorPairFromExit(Stmt exitMonitor) {
00324 for (Iterator lockPairIt = lockPairList.iterator(); lockPairIt.hasNext();) {
00325 MonitorPair lockPair = (MonitorPair) lockPairIt.next();
00326 Set exitMonitorsInLockPair = exitMonitorsIn(lockPair);
00327 if (exitMonitorsInLockPair.contains(exitMonitor))
00328 return lockPair;
00329 }
00330 throw new CorrespondingMonitorNotFoundException("Can't find the corresponding monitor pair according to the statement (index) : " + exitMonitor + " in LockAnalysis");
00331 }
00332
00333
00334
00335
00336
00337 public List getNotifyStmtList()
00338 {
00339 return notifyStmtList;
00340 }
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350 private Vector getSynchAnnotation(StmtList stmtList, Annotation annotation) {
00351 Vector v = new Vector();
00352 for (Iterator i = stmtList.iterator(); i.hasNext();) {
00353 Stmt stmt = (Stmt) i.next();
00354 if (stmt instanceof JEnterMonitorStmt) {
00355 Annotation a = null;
00356 try {
00357 a = annotation.getContainingAnnotation(stmt);
00358 } catch (Exception e) {
00359 }
00360 if (a == null) {
00361 System.out.println("HEYYYY! The annotation for method " + mdInfo.sootClass.getName() + "." + mdInfo.sootMethod.getName() + " is null because current version of jjjc make the <init> method without annotation. This will be modified later.");
00362 } else {
00363 v.addElement(a);
00364 }
00365 }
00366 }
00367 return v;
00368 }
00369
00370
00371
00372
00373
00374 public List getWaitStmtList()
00375 {
00376 return waitStmtList;
00377 }
00378
00379
00380
00381
00382
00383 private Set lockValueSet() {
00384 Set lockSet = new ArraySet();
00385 for (int i = 0; i < this.lockPairList.size(); i++) {
00386 MonitorPair mp = (MonitorPair) this.lockPairList.get(i);
00387 Value lockValue = mp.getLock();
00388 lockSet.add(lockValue);
00389 }
00390 return lockSet;
00391 }
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401 public BitSet reachableStmtFrom(Stmt stmt) {
00402 BitSet reachableStmt = new BitSet(stmtList.size());
00403
00404 LinkedList stack = new LinkedList();
00405 stack.addFirst(stmt);
00406 while (!stack.isEmpty()) {
00407 Stmt currentStmt = (Stmt) stack.removeFirst();
00408 List succsList = stmtGraph.getSuccsOf(currentStmt);
00409 for (Iterator succsIt = succsList.iterator(); succsIt.hasNext();) {
00410 Stmt succ = (Stmt) succsIt.next();
00411 int succIndex = stmtList.indexOf(succ);
00412 if (!reachableStmt.get(succIndex)) {
00413 reachableStmt.set(succIndex);
00414 stack.addLast(succ);
00415 }
00416 }
00417 }
00418 return reachableStmt;
00419 }
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429 public Set readyDependOnEnters(Stmt stmt) {
00430 Set enterSet = new ArraySet();
00431 for (Iterator lockPairIt = lockPairList.iterator(); lockPairIt.hasNext();) {
00432 MonitorPair monitorPair = (MonitorPair) lockPairIt.next();
00433 Stmt monitorStmt = (Stmt) monitorPair.getEnterMonitor();
00434 BitSet reachableStmt = reachableStmtFrom(monitorStmt);
00435 if (reachableStmt.get(stmtList.indexOf(stmt))) {
00436 if (!safeLock(monitorPair))
00437
00438 enterSet.add(monitorStmt);
00439 }
00440 }
00441 return enterSet;
00442 }
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452 public BitSet readyDependOnWaits(Stmt stmt) {
00453 Set waitSet = new ArraySet();
00454 for (Iterator waitStmtIt = waitStmtList.iterator(); waitStmtIt.hasNext();) {
00455 SynchroStmt synStmt = (SynchroStmt) waitStmtIt.next();
00456 Stmt waitStmt = synStmt.getWaitNotify();
00457 if (stmt.equals(waitStmt)) continue;
00458 BitSet reachableStmt = reachableStmtFrom(waitStmt);
00459 if (reachableStmt.get(stmtList.indexOf(stmt)))
00460 waitSet.add(waitStmt);
00461 }
00462 return SetUtil.stmtSetToBitSet(waitSet,stmtList);
00463 }
00464
00465
00466
00467
00468
00469
00470
00471 public boolean safeLock(Stmt monitor)
00472 {
00473 MonitorPair monitorPair = getMonitorPair(monitor);
00474
00475 return safeLock(monitorPair);
00476 }
00477
00478
00479
00480
00481
00482
00483
00484
00485 public boolean safeLock(MonitorPair monitorPair)
00486 {
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503 return true;
00504 }
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515 private BitSet stmtsBetween(MonitorPair monitorPair) {
00516 BitSet stmtsBetweenMonitor = new BitSet(stmtList.size());
00517 Stmt monitorStmt = (Stmt) monitorPair.getEnterMonitor();
00518 int enterIndex = stmtList.indexOf(monitorStmt);
00519 monitorStmt = monitorPair.getEndSynchroStmt();
00520 int endIndex = stmtList.indexOf(monitorStmt);
00521 List exitMonitors = monitorPair.getExitMonitors();
00522 for (int i = enterIndex + 1; i <= endIndex; i++)
00523 if (!exitMonitors.contains(stmtList.get(i)))
00524 stmtsBetweenMonitor.set(i);
00525 return stmtsBetweenMonitor;
00526 }
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536 public boolean stmtSynchroDependOn(Stmt stmt, Stmt monitor)
00537
00538 {
00539 if (monitor instanceof EnterMonitorStmt || monitor instanceof ExitMonitorStmt) {
00540
00541 MonitorPair monitorPair = getMonitorPair(monitor);
00542 return stmtSynchroDependOn(stmt, monitorPair);
00543 } else
00544 throw new StatementTypeException("The statement should be entermonitor or exitmonitor statement : " + monitor + " in LockAnalysis");
00545 }
00546
00547
00548
00549
00550
00551
00552
00553
00554 public boolean stmtSynchroDependOn(Stmt stmt, MonitorPair monitorPair)
00555
00556 {
00557 int stmtIndex = stmtList.indexOf(stmt);
00558 BitSet codeBetweenMonitor = stmtsBetween(monitorPair);
00559 if (codeBetweenMonitor.get(stmtIndex))
00560 return true;
00561 return false;
00562 }
00563 }