00001 package ca.mcgill.sable.soot.jimple;
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
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108 import ca.mcgill.sable.soot.*;
00109 import ca.mcgill.sable.util.*;
00110 import ca.mcgill.sable.soot.baf.*;
00111 import java.io.*;
00112
00113 public class JimpleBody implements StmtBody
00114 {
00115 List locals = new ArrayList();
00116 SootMethod method;
00117
00118 StmtList stmtList;
00119 List traps = new ArrayList();
00120
00121
00122
00123
00124
00125
00126 JimpleBody(SootMethod m)
00127 {
00128 this.method = m;
00129 stmtList = new StmtList(this);
00130 }
00131
00132
00133
00134
00135 public JimpleBody(SootMethod m, Body body, int buildOptions)
00136 {
00137 ClassFileBody fileBody;
00138
00139 if(body instanceof ClassFileBody)
00140 fileBody = (ClassFileBody) body;
00141 else
00142 throw new RuntimeException("Can only construct JimpleBody's directly from ClassFileBody's (for now)");
00143
00144 this.method = fileBody.getMethod();
00145 this.stmtList = new StmtList(this);
00146
00147 ca.mcgill.sable.soot.coffi.ClassFile coffiClass = fileBody.coffiClass;
00148 ca.mcgill.sable.soot.coffi.method_info coffiMethod = fileBody.coffiMethod;
00149
00150
00151
00152
00153
00154
00155
00156 if(Main.isVerbose)
00157 System.out.println("[" + method.getName() + "] Jimplifying...");
00158
00159 if(Modifier.isAbstract(method.getModifiers()) || Modifier.isNative(method.getModifiers()))
00160 return;
00161
00162 if(Main.isProfilingOptimization)
00163 Main.conversionTimer.start();
00164
00165 if(coffiMethod.cfg == null)
00166 {
00167 if(Main.isVerbose)
00168 System.out.println("[" + method.getName() +
00169 "] Building Coffi CFG...");
00170
00171 new ca.mcgill.sable.soot.coffi.CFG(coffiMethod);
00172
00173 if(Main.isVerbose)
00174 System.out.println("[" + method.getName() +
00175 "] Coffi CFG complete.");
00176
00177 }
00178
00179 if(Main.isVerbose)
00180 System.out.println("[" + method.getName() +
00181 "] Producing naive Jimple...");
00182 coffiMethod.cfg.jimplify(coffiClass.constant_pool,
00183 coffiClass.this_class, this);
00184
00185 if(Main.isProfilingOptimization)
00186 {
00187 Main.conversionTimer.end();
00188 Main.conversionLocalCount += getLocalCount();
00189 Main.conversionStmtCount += stmtList.size();
00190 }
00191
00192 if(Main.isVerbose)
00193 System.out.println("[" + method.getName() +
00194 "] Naive typeless Jimple produced.");
00195
00196
00197
00198 if(!BuildJimpleBodyOption.noSplitting(buildOptions))
00199 {
00200 if(Main.isProfilingOptimization)
00201 Main.splitTimer.start();
00202
00203 LocalSplitter.splitLocals(this);
00204
00205 if(Main.isProfilingOptimization)
00206 {
00207 Main.splitTimer.end();
00208 Main.splitLocalCount += getLocalCount();
00209 Main.splitStmtCount += stmtList.size();
00210 }
00211
00212 if(!BuildJimpleBodyOption.noTyping(buildOptions))
00213 {
00214 if(Main.isProfilingOptimization)
00215 Main.assignTimer.start();
00216
00217
00218 Transformations.assignTypesToLocals(this);
00219
00220 if(typingFailed())
00221 {
00222 patchForTyping();
00223
00224 Transformations.assignTypesToLocals(this);
00225
00226 if(typingFailed())
00227 throw new RuntimeException("type inference failed!");
00228
00229 }
00230
00231 if(Main.isProfilingOptimization)
00232 {
00233 Main.assignLocalCount += getLocalCount();
00234 Main.assignStmtCount += stmtList.size();
00235
00236 Main.assignTimer.end();
00237 }
00238 }
00239 }
00240
00241 if(!BuildJimpleBodyOption.noCleanup(buildOptions))
00242 {
00243 Transformations.cleanupCode(this);
00244 Transformations.removeUnusedLocals(this);
00245
00246 if(Main.isProfilingOptimization)
00247 {
00248 Main.cleanup1LocalCount += getLocalCount();
00249 Main.cleanup1StmtCount += stmtList.size();
00250 }
00251 }
00252
00253 if(!BuildJimpleBodyOption.noAggregating(buildOptions))
00254 {
00255 Transformations.aggregate(this);
00256 Transformations.removeUnusedLocals(this);
00257 }
00258
00259 Transformations.renameLocals(this);
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300 }
00301 public void addLocal(Local l) throws AlreadyDeclaredException
00302 {
00303 locals.add(l);
00304 }
00305 public void addTrap(Trap t)
00306 {
00307 traps.add(t);
00308 }
00309 public boolean declaresLocal(String localName)
00310 {
00311 Iterator localIt = getLocals().iterator();
00312
00313 while(localIt.hasNext())
00314 {
00315 Local local = (Local) localIt.next();
00316
00317 if(local.name.equals(localName))
00318 return true;
00319 }
00320
00321 return false;
00322 }
00323 public void eliminateBackPointersTo(Stmt oldLocation)
00324 {
00325 Iterator boxIt = oldLocation.getUnitBoxes().iterator();
00326
00327 while(boxIt.hasNext())
00328 {
00329 StmtBox box = (StmtBox) boxIt.next();
00330 Stmt stmt = (Stmt) box.getUnit();
00331
00332 stmt.getBoxesPointingToThis().remove(oldLocation);
00333 }
00334 }
00335 public Local getLocal(String name) throws ca.mcgill.sable.soot.jimple.NoSuchLocalException
00336 {
00337 Iterator localIt = getLocals().iterator();
00338
00339 while(localIt.hasNext())
00340 {
00341 Local local = (Local) localIt.next();
00342
00343 if(local.name.equals(name))
00344 return local;
00345 }
00346
00347 throw new ca.mcgill.sable.soot.jimple.NoSuchLocalException();
00348 }
00349 public int getLocalCount()
00350 {
00351 return locals.size();
00352 }
00353
00354
00355
00356
00357 public List getLocals()
00358 {
00359 return locals;
00360 }
00361 public SootMethod getMethod()
00362 {
00363 return method;
00364 }
00365 public StmtList getStmtList()
00366 {
00367 return stmtList;
00368 }
00369 public List getTraps()
00370 {
00371 return traps;
00372 }
00373 public List getUnitBoxes()
00374 {
00375 List stmtBoxes = new ArrayList();
00376
00377
00378 Iterator stmtIt = stmtList.iterator();
00379
00380 while(stmtIt.hasNext())
00381 {
00382 Stmt stmt = (Stmt) stmtIt.next();
00383
00384 Iterator boxIt = stmt.getUnitBoxes().iterator();
00385
00386 while(boxIt.hasNext())
00387 stmtBoxes.add(boxIt.next());
00388 }
00389
00390
00391 {
00392 Iterator trapIt = traps.iterator();
00393
00394 while(trapIt.hasNext())
00395 {
00396 Trap trap = (Trap) trapIt.next();
00397 stmtBoxes.addAll(trap.getUnitBoxes());
00398 }
00399 }
00400
00401 return stmtBoxes;
00402 }
00403
00404
00405
00406 private void patchForTyping()
00407 {
00408 int localCount = 0;
00409 ListIterator stmtIt = stmtList.listIterator();
00410 Local newObjectLocal = null;
00411
00412 Transformations.cleanupCode(this);
00413 Transformations.removeUnusedLocals(this);
00414 Transformations.renameLocals(this);
00415
00416 while(stmtIt.hasNext())
00417 {
00418 Stmt s = (Stmt) stmtIt.next();
00419
00420 if(s instanceof AssignStmt)
00421 {
00422 AssignStmt as = (AssignStmt) s;
00423
00424 if(as.getRightOp() instanceof NewExpr &&
00425 as.getLeftOp() instanceof Local)
00426 {
00427
00428 Local tmpLocal = Jimple.v().newLocal("tmp" + localCount,
00429 UnknownType.v());
00430 addLocal(tmpLocal);
00431
00432 localCount++;
00433
00434
00435 newObjectLocal = (Local) as.getLeftOp();
00436 as.setLeftOp(tmpLocal);
00437
00438
00439 {
00440 ListIterator matchIt = stmtList.listIterator(stmtIt.nextIndex());
00441 boolean foundMatch = false;
00442
00443 while(matchIt.hasNext())
00444 {
00445 Stmt r = (Stmt) matchIt.next();
00446
00447 if(r instanceof InvokeStmt)
00448 {
00449 InvokeExpr expr = (InvokeExpr) ((InvokeStmt) r).getInvokeExpr();
00450
00451 if(expr instanceof SpecialInvokeExpr &&
00452 ((SpecialInvokeExpr) expr).getBase() == newObjectLocal)
00453 {
00454
00455 ((SpecialInvokeExpr) expr).setBase(tmpLocal);
00456
00457
00458 matchIt.add(Jimple.v().newAssignStmt(newObjectLocal,
00459 tmpLocal));
00460
00461 foundMatch = true;
00462 break;
00463 }
00464 }
00465 }
00466
00467 if(!foundMatch)
00468 throw new RuntimeException("unable to patch code");
00469 }
00470 }
00471 }
00472 }
00473
00474 }
00475 public void printDebugTo(java.io.PrintWriter out)
00476 {
00477 StmtBody stmtBody = this;
00478 StmtList stmtList = stmtBody.getStmtList();
00479 Map stmtToName = new HashMap(stmtList.size() * 2 + 1, 0.7f);
00480 CompleteStmtGraph stmtGraph = new CompleteStmtGraph(stmtList);
00481
00482 LocalDefs localDefs = new SimpleLocalDefs(stmtGraph);
00483
00484
00485
00486
00487 LocalCopies localCopies = new SimpleLocalCopies(stmtGraph);
00488 LiveLocals liveLocals = new SimpleLiveLocals(stmtGraph);
00489 EqualLocals equalLocals = new SimpleEqualLocals(stmtGraph);
00490
00491
00492 {
00493 int labelCount = 0;
00494
00495 Iterator stmtIt = stmtList.iterator();
00496
00497 while(stmtIt.hasNext())
00498 {
00499 Stmt s = (Stmt) stmtIt.next();
00500
00501 stmtToName.put(s, new Integer(labelCount++).toString());
00502 }
00503 }
00504
00505 for(int j = 0; j < stmtList.size(); j++)
00506 {
00507 Stmt s = ((Stmt) stmtList.get(j));
00508
00509 out.print(" " + stmtToName.get(s) + ": ");
00510
00511 out.print(s.toBriefString(stmtToName, " "));
00512 out.print(";");
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620 out.println();
00621 }
00622
00623
00624 {
00625 Iterator trapIt = stmtBody.getTraps().iterator();
00626
00627 while(trapIt.hasNext())
00628 {
00629 Trap trap = (Trap) trapIt.next();
00630
00631 out.println(".catch " + trap.getException().getName() + " from " +
00632 stmtToName.get(trap.getBeginUnit()) + " to " + stmtToName.get(trap.getEndUnit()) +
00633 " with " + stmtToName.get(trap.getHandlerUnit()));
00634 }
00635 }
00636 }
00637 void printStatementsInBody(java.io.PrintWriter out, boolean isPrecise)
00638 {
00639 StmtList stmtList = this.getStmtList();
00640
00641 Map stmtToName = new HashMap(stmtList.size() * 2 + 1, 0.7f);
00642 StmtGraph stmtGraph = new BriefStmtGraph(stmtList);
00643
00644
00645 {
00646 Iterator boxIt = this.getUnitBoxes().iterator();
00647
00648 Set labelStmts = new HashSet();
00649
00650
00651 {
00652 while(boxIt.hasNext())
00653 {
00654 StmtBox box = (StmtBox) boxIt.next();
00655 Stmt stmt = (Stmt) box.getUnit();
00656
00657 labelStmts.add(stmt);
00658 }
00659 }
00660
00661
00662 {
00663 int labelCount = 0;
00664
00665 Iterator stmtIt = stmtList.iterator();
00666
00667 while(stmtIt.hasNext())
00668 {
00669 Stmt s = (Stmt) stmtIt.next();
00670
00671 if(labelStmts.contains(s))
00672 stmtToName.put(s, "label" + (labelCount++));
00673 }
00674 }
00675 }
00676
00677 for(int j = 0; j < stmtList.size(); j++)
00678 {
00679 Stmt s = ((Stmt) stmtList.get(j));
00680
00681
00682
00683
00684 {
00685 if(j != 0)
00686 {
00687 Stmt previousStmt = (Stmt) stmtList.get(j - 1);
00688
00689 if(stmtGraph.getSuccsOf(previousStmt).size() != 1 ||
00690 stmtGraph.getPredsOf(s).size() != 1 ||
00691 stmtToName.containsKey(s))
00692 out.println();
00693 else {
00694
00695
00696 List succs = stmtGraph.getSuccsOf(previousStmt);
00697
00698 if(succs.get(0) != s)
00699 out.println();
00700
00701 }
00702 }
00703 }
00704
00705 if(stmtToName.containsKey(s))
00706 out.println(" " + stmtToName.get(s) + ":");
00707
00708 if(isPrecise)
00709 out.print(s.toString(stmtToName, " "));
00710 else
00711 out.print(s.toBriefString(stmtToName, " "));
00712
00713 out.print(";");
00714 out.println();
00715 }
00716
00717
00718 {
00719 Iterator trapIt = this.getTraps().iterator();
00720
00721 if(trapIt.hasNext())
00722 out.println();
00723
00724 while(trapIt.hasNext())
00725 {
00726 Trap trap = (Trap) trapIt.next();
00727
00728 out.println(" .catch " + trap.getException().getName() + " from " +
00729 stmtToName.get(trap.getBeginUnit()) + " to " + stmtToName.get(trap.getEndUnit()) +
00730 " with " + stmtToName.get(trap.getHandlerUnit()));
00731 }
00732 }
00733 }
00734 public void printTo(java.io.PrintWriter out)
00735 {
00736 printTo(out, 0);
00737 }
00738 public void printTo(PrintWriter out, int printBodyOptions)
00739 {
00740 boolean isPrecise = !PrintJimpleBodyOption.useAbbreviations(printBodyOptions);
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752 StmtList stmtList = this.getStmtList();
00753
00754 Map stmtToName = new HashMap(stmtList.size() * 2 + 1, 0.7f);
00755
00756
00757 {
00758 StringBuffer buffer = new StringBuffer();
00759
00760 buffer.append(Modifier.toString(method.getModifiers()));
00761
00762 if(buffer.length() != 0)
00763 buffer.append(" ");
00764
00765 buffer.append(method.getReturnType().toString() + " " + method.getName());
00766 buffer.append("(");
00767
00768 Iterator typeIt = method.getParameterTypes().iterator();
00769
00770 if(typeIt.hasNext())
00771 {
00772 buffer.append(typeIt.next());
00773
00774 while(typeIt.hasNext())
00775 {
00776 buffer.append(", ");
00777 buffer.append(typeIt.next());
00778 }
00779 }
00780
00781 buffer.append(")");
00782
00783 out.print(" " + buffer.toString());
00784 }
00785
00786 out.println();
00787 out.println(" {");
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802 {
00803 Map typeToLocalSet = new HashMap(this.getLocalCount() * 2 + 1, 0.7f);
00804
00805
00806 {
00807 Iterator localIt = this.getLocals().iterator();
00808
00809 while(localIt.hasNext())
00810 {
00811 Local local = (Local) localIt.next();
00812
00813 Set localSet;
00814
00815 if(typeToLocalSet.containsKey(local.getType().toString()))
00816 localSet = (Set) typeToLocalSet.get(local.getType().toString());
00817 else
00818 {
00819 localSet = new HashSet();
00820 typeToLocalSet.put(local.getType().toString(), localSet);
00821 }
00822
00823 localSet.add(local);
00824 }
00825 }
00826
00827
00828 {
00829 Set typeSet = typeToLocalSet.keySet();
00830
00831 Object[] types = typeSet.toArray();
00832
00833 for(int j = 0; j < types.length; j++)
00834 {
00835 String type = (String) types[j];
00836
00837 Set localSet = (Set) typeToLocalSet.get(type);
00838 Object[] locals = localSet.toArray();
00839
00840 out.print(" " + type + " ");
00841
00842 for(int k = 0; k < locals.length; k++)
00843 {
00844 if(k != 0)
00845 out.print(", ");
00846
00847 out.print(((Local) locals[k]).getName());
00848 }
00849
00850 out.println(";");
00851 }
00852 }
00853
00854
00855 if(!typeToLocalSet.isEmpty())
00856 out.println();
00857 }
00858
00859
00860 printStatementsInBody(out, isPrecise);
00861
00862 out.println(" }");
00863 }
00864 public void redirectJumps(Stmt oldLocation, Stmt newLocation)
00865 {
00866 List boxesPointing = oldLocation.getBoxesPointingToThis();
00867
00868 Object[] boxes = boxesPointing.toArray();
00869
00870
00871 for(int i = 0; i < boxes.length; i++)
00872 {
00873 StmtBox box = (StmtBox) boxes[i];
00874
00875 if(box.getUnit() != oldLocation)
00876 throw new RuntimeException("Something weird's happening");
00877
00878 box.setUnit(newLocation);
00879 }
00880
00881 }
00882 public void removeLocal(Local l) throws IncorrectDeclarerException
00883 {
00884 locals.remove(l);
00885 }
00886 public void removeTrap(Trap t)
00887 {
00888 traps.remove(t);
00889 }
00890 private boolean typingFailed()
00891 {
00892
00893 {
00894 Iterator localIt = this.getLocals().iterator();
00895
00896 while(localIt.hasNext())
00897 {
00898 Local l = (Local) localIt.next();
00899
00900 if(l.getType().equals(UnknownType.v()) ||
00901 l.getType().equals(ErroneousType.v()))
00902 {
00903 return true;
00904 }
00905 }
00906 }
00907
00908 return false;
00909 }
00910 }