00001 package ca.mcgill.sable.soot.grimp;
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 import ca.mcgill.sable.soot.*;
00080 import ca.mcgill.sable.soot.jimple.*;
00081 import ca.mcgill.sable.util.*;
00082 import ca.mcgill.sable.soot.baf.*;
00083 import java.io.*;
00084
00085 public class GrimpBody implements StmtBody
00086 {
00087 List locals = new ArrayList();
00088 SootMethod method;
00089
00090 StmtList stmtList;
00091 List traps = new ArrayList();
00092
00093
00094
00095
00096
00097 GrimpBody(SootMethod m)
00098 {
00099 this.method = m;
00100 stmtList = new StmtList(this);
00101 }
00102
00103
00104
00105
00106 GrimpBody(SootMethod m, Body body, int buildOptions)
00107 {
00108
00109 JimpleBody jBody = null;
00110
00111 if(body instanceof ClassFileBody)
00112 {
00113
00114
00115 jBody = new JimpleBody(m, body, buildOptions);
00116 }
00117 else if (body instanceof JimpleBody)
00118 {
00119 jBody = (JimpleBody)body;
00120 }
00121 else
00122 throw new RuntimeException("Can only construct GrimpBody's from ClassFileBody's or JimpleBody's (for now)");
00123
00124 this.method = jBody.getMethod();
00125 this.locals = new LinkedList();
00126 Iterator it = jBody.getLocals().iterator();
00127 while (it.hasNext())
00128 this.locals.add(((Local)(it.next())));
00129
00130
00131 stmtList = new StmtList(this);
00132 it = jBody.getStmtList().iterator();
00133
00134 final HashMap oldToNew = new HashMap(stmtList.size() * 2 + 1, 0.7f);
00135 LinkedList updates = new LinkedList();
00136
00137
00138 while (it.hasNext())
00139 {
00140 Stmt oldStmt = (Stmt)(it.next());
00141 final StmtBox newStmtBox = new StmtBox(null);
00142 final StmtBox updateStmtBox = new StmtBox(null);
00143
00144
00145
00146 oldStmt.apply(new AbstractStmtSwitch()
00147 {
00148 public void caseAssignStmt(AssignStmt s)
00149 {
00150 newStmtBox.setUnit(Grimp.v().newAssignStmt(s));
00151 }
00152 public void caseIdentityStmt(IdentityStmt s)
00153 {
00154 newStmtBox.setUnit(Grimp.v().newIdentityStmt(s));
00155 }
00156 public void caseBreakpointStmt(BreakpointStmt s)
00157 {
00158 newStmtBox.setUnit(Grimp.v().newBreakpointStmt(s));
00159 }
00160 public void caseInvokeStmt(InvokeStmt s)
00161 {
00162 newStmtBox.setUnit(Grimp.v().newInvokeStmt(s));
00163 }
00164 public void defaultCase(Stmt s)
00165 {
00166 throw new RuntimeException("invalid jimple stmt: "+s);
00167 }
00168 public void caseEnterMonitorStmt(EnterMonitorStmt s)
00169 {
00170 newStmtBox.setUnit(Grimp.v().newEnterMonitorStmt(s));
00171 }
00172 public void caseExitMonitorStmt(ExitMonitorStmt s)
00173 {
00174 newStmtBox.setUnit(Grimp.v().newExitMonitorStmt(s));
00175 }
00176 public void caseGotoStmt(GotoStmt s)
00177 {
00178 newStmtBox.setUnit(Grimp.v().newGotoStmt(s));
00179 updateStmtBox.setUnit(s);
00180 }
00181 public void caseIfStmt(IfStmt s)
00182 {
00183 newStmtBox.setUnit(Grimp.v().newIfStmt(s));
00184 updateStmtBox.setUnit(s);
00185 }
00186 public void caseLookupSwitchStmt(LookupSwitchStmt s)
00187 {
00188 newStmtBox.setUnit(Grimp.v().newLookupSwitchStmt(s));
00189 updateStmtBox.setUnit(s);
00190 }
00191 public void caseNopStmt(NopStmt s)
00192 {
00193 newStmtBox.setUnit(Grimp.v().newNopStmt(s));
00194 }
00195 public void caseRetStmt(RetStmt s)
00196 {
00197 newStmtBox.setUnit(Grimp.v().newRetStmt(s));
00198 }
00199 public void caseReturnStmt(ReturnStmt s)
00200 {
00201 newStmtBox.setUnit(Grimp.v().newReturnStmt(s));
00202 }
00203 public void caseReturnVoidStmt(ReturnVoidStmt s)
00204 {
00205 newStmtBox.setUnit(Grimp.v().newReturnVoidStmt(s));
00206 }
00207 public void caseTableSwitchStmt(TableSwitchStmt s)
00208 {
00209 newStmtBox.setUnit(Grimp.v().newTableSwitchStmt(s));
00210 updateStmtBox.setUnit(s);
00211 }
00212 public void caseThrowStmt(ThrowStmt s)
00213 {
00214 newStmtBox.setUnit(Grimp.v().newThrowStmt(s));
00215 }
00216 });
00217
00218
00219 Stmt newStmt = (Stmt)(newStmtBox.getUnit());
00220 Iterator useBoxesIt = (Iterator)
00221 newStmt.getUseAndDefBoxes().iterator();
00222 while(useBoxesIt.hasNext())
00223 {
00224 ValueBox b = (ValueBox) (useBoxesIt.next());
00225 b.setValue(Grimp.v().newExpr(b.getValue()));
00226 }
00227
00228 stmtList.add(newStmt);
00229 oldToNew.put(oldStmt, newStmt);
00230 if (updateStmtBox.getUnit() != null)
00231 updates.add(updateStmtBox.getUnit());
00232 }
00233
00234
00235 it = updates.iterator();
00236 while (it.hasNext())
00237 {
00238 Stmt stmt = (Stmt)(it.next());
00239
00240 stmt.apply(new AbstractStmtSwitch()
00241 {
00242 public void defaultCase(Stmt s)
00243 {
00244 throw new RuntimeException("Internal error: "+s);
00245 }
00246 public void caseGotoStmt(GotoStmt s)
00247 {
00248 GotoStmt newStmt = (GotoStmt)(oldToNew.get(s));
00249 newStmt.setTarget((Stmt)oldToNew.get(newStmt.getTarget()));
00250 }
00251 public void caseIfStmt(IfStmt s)
00252 {
00253 IfStmt newStmt = (IfStmt)(oldToNew.get(s));
00254 newStmt.setTarget((Stmt)oldToNew.get(newStmt.getTarget()));
00255 }
00256 public void caseLookupSwitchStmt(LookupSwitchStmt s)
00257 {
00258 LookupSwitchStmt newStmt =
00259 (LookupSwitchStmt)(oldToNew.get(s));
00260 newStmt.setDefaultTarget
00261 ((Unit)(oldToNew.get(newStmt.getDefaultTarget())));
00262 Unit[] newTargList = new Unit[newStmt.getTargetCount()];
00263 for (int i = 0; i < newStmt.getTargetCount(); i++)
00264 newTargList[i] = (Unit)(oldToNew.get
00265 (newStmt.getTarget(i)));
00266 newStmt.setTargets(newTargList);
00267 }
00268 public void caseTableSwitchStmt(TableSwitchStmt s)
00269 {
00270 TableSwitchStmt newStmt =
00271 (TableSwitchStmt)(oldToNew.get(s));
00272 newStmt.setDefaultTarget
00273 ((Unit)(oldToNew.get(newStmt.getDefaultTarget())));
00274 int tc = newStmt.getHighIndex() - newStmt.getLowIndex()+1;
00275 LinkedList newTargList = new LinkedList();
00276 for (int i = 0; i < tc; i++)
00277 newTargList.add(oldToNew.get
00278 (newStmt.getTarget(i)));
00279 newStmt.setTargets(newTargList);
00280 }
00281 });
00282 }
00283
00284 this.traps = new ArrayList();
00285 it = jBody.getTraps().iterator();
00286 while (it.hasNext())
00287 {
00288 Trap oldTrap = (Trap)(it.next());
00289 this.traps.add(Grimp.v().newTrap
00290 (oldTrap.getException(),
00291 (Unit)(oldToNew.get(oldTrap.getBeginUnit())),
00292 (Unit)(oldToNew.get(oldTrap.getEndUnit())),
00293 (Unit)(oldToNew.get(oldTrap.getHandlerUnit()))));
00294 }
00295
00296 if (Main.isProfilingOptimization)
00297 Main.aggregationTimer.start();
00298
00299 if (!BuildGrimpBodyOption.noAggregating(buildOptions))
00300 {
00301 GrimpTransformations.foldConstructors(this);
00302 Transformations.aggregate(this);
00303 Transformations.removeUnusedLocals(this);
00304 }
00305
00306 if (Main.isProfilingOptimization)
00307 Main.aggregationTimer.end();
00308 }
00309 public void addLocal(Local l) throws AlreadyDeclaredException
00310 {
00311 locals.add(l);
00312 }
00313 public void addTrap(Trap t)
00314 {
00315 traps.add(t);
00316 }
00317 public boolean declaresLocal(String localName)
00318 {
00319 Iterator localIt = getLocals().iterator();
00320
00321 while(localIt.hasNext())
00322 {
00323 Local local = (Local) localIt.next();
00324
00325 if(local.getName().equals(localName))
00326 return true;
00327 }
00328
00329 return false;
00330 }
00331 public void eliminateBackPointersTo(Stmt oldLocation)
00332 {
00333 Iterator boxIt = oldLocation.getUnitBoxes().iterator();
00334
00335 while(boxIt.hasNext())
00336 {
00337 StmtBox box = (StmtBox) boxIt.next();
00338 Stmt stmt = (Stmt) box.getUnit();
00339
00340 stmt.getBoxesPointingToThis().remove(oldLocation);
00341 }
00342 }
00343 public Local getLocal(String name) throws ca.mcgill.sable.soot.jimple.NoSuchLocalException
00344 {
00345 Iterator localIt = getLocals().iterator();
00346
00347 while(localIt.hasNext())
00348 {
00349 Local local = (Local) localIt.next();
00350
00351 if(local.getName().equals(name))
00352 return local;
00353 }
00354
00355 throw new ca.mcgill.sable.soot.jimple.NoSuchLocalException();
00356 }
00357 public int getLocalCount()
00358 {
00359 return locals.size();
00360 }
00361
00362
00363
00364
00365 public List getLocals()
00366 {
00367 return locals;
00368 }
00369 public SootMethod getMethod()
00370 {
00371 return method;
00372 }
00373 public StmtList getStmtList()
00374 {
00375 return stmtList;
00376 }
00377 public List getTraps()
00378 {
00379 return traps;
00380 }
00381 public List getUnitBoxes()
00382 {
00383 List stmtBoxes = new ArrayList();
00384
00385
00386 Iterator stmtIt = stmtList.iterator();
00387
00388 while(stmtIt.hasNext())
00389 {
00390 Stmt stmt = (Stmt) stmtIt.next();
00391
00392 Iterator boxIt = stmt.getUnitBoxes().iterator();
00393
00394 while(boxIt.hasNext())
00395 stmtBoxes.add(boxIt.next());
00396 }
00397
00398
00399 {
00400 Iterator trapIt = traps.iterator();
00401
00402 while(trapIt.hasNext())
00403 {
00404 Trap trap = (Trap) trapIt.next();
00405 stmtBoxes.addAll(trap.getUnitBoxes());
00406 }
00407 }
00408
00409 return stmtBoxes;
00410 }
00411 void print_debug(java.io.PrintWriter out)
00412 {
00413 StmtList stmtList = this.getStmtList();
00414
00415
00416 Map stmtToName = new HashMap(stmtList.size() * 2 + 1, 0.7f);
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436 {
00437 int labelCount = 0;
00438
00439 Iterator stmtIt = stmtList.iterator();
00440
00441 while(stmtIt.hasNext())
00442 {
00443 Stmt s = (Stmt) stmtIt.next();
00444
00445 stmtToName.put(s, new Integer(labelCount++).toString());
00446 }
00447 }
00448
00449 for(int j = 0; j < stmtList.size(); j++)
00450 {
00451 Stmt s = ((Stmt) stmtList.get(j));
00452
00453 out.print(" " + stmtToName.get(s) + ": ");
00454
00455 out.print(s.toString(stmtToName, " "));
00456 out.print(";");
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
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 out.println();
00567 }
00568
00569
00570 {
00571 Iterator trapIt = this.getTraps().iterator();
00572
00573 while(trapIt.hasNext())
00574 {
00575 Trap trap = (Trap) trapIt.next();
00576
00577 out.println(".catch " + trap.getException().getName() + " from " +
00578 stmtToName.get(trap.getBeginUnit()) + " to " + stmtToName.get(trap.getEndUnit()) +
00579 " with " + stmtToName.get(trap.getHandlerUnit()));
00580 }
00581 }
00582 }
00583 void printStatementsInBody(java.io.PrintWriter out, boolean isPrecise)
00584 {
00585 StmtList stmtList = this.getStmtList();
00586
00587 Map stmtToName = new HashMap(stmtList.size() * 2 + 1, 0.7f);
00588 StmtGraph stmtGraph = new BriefStmtGraph(stmtList);
00589
00590
00591 {
00592 Iterator boxIt = this.getUnitBoxes().iterator();
00593
00594 Set labelStmts = new HashSet();
00595
00596
00597 {
00598 while(boxIt.hasNext())
00599 {
00600 StmtBox box = (StmtBox) boxIt.next();
00601 Stmt stmt = (Stmt) box.getUnit();
00602
00603 labelStmts.add(stmt);
00604 }
00605 }
00606
00607
00608 {
00609 int labelCount = 0;
00610
00611 Iterator stmtIt = stmtList.iterator();
00612
00613 while(stmtIt.hasNext())
00614 {
00615 Stmt s = (Stmt) stmtIt.next();
00616
00617 if(labelStmts.contains(s))
00618 stmtToName.put(s, "label" + (labelCount++));
00619 }
00620 }
00621 }
00622
00623 for(int j = 0; j < stmtList.size(); j++)
00624 {
00625 Stmt s = ((Stmt) stmtList.get(j));
00626
00627
00628
00629
00630 {
00631 if(j != 0)
00632 {
00633 Stmt previousStmt = (Stmt) stmtList.get(j - 1);
00634
00635 if(stmtGraph.getSuccsOf(previousStmt).size() != 1 ||
00636 stmtGraph.getPredsOf(s).size() != 1 ||
00637 stmtToName.containsKey(s))
00638 out.println();
00639 else {
00640
00641
00642 List succs = stmtGraph.getSuccsOf(previousStmt);
00643
00644 if(succs.get(0) != s)
00645 out.println();
00646
00647 }
00648 }
00649 }
00650
00651 if(stmtToName.containsKey(s))
00652 out.println(" " + stmtToName.get(s) + ":");
00653
00654 if(isPrecise)
00655 out.print(s.toString(stmtToName, " "));
00656 else
00657 out.print(s.toBriefString(stmtToName, " "));
00658
00659 out.print(";");
00660 out.println();
00661 }
00662
00663
00664 {
00665 Iterator trapIt = this.getTraps().iterator();
00666
00667 if(trapIt.hasNext())
00668 out.println();
00669
00670 while(trapIt.hasNext())
00671 {
00672 Trap trap = (Trap) trapIt.next();
00673
00674 out.println(" .catch " + trap.getException().getName() + " from " +
00675 stmtToName.get(trap.getBeginUnit()) + " to " + stmtToName.get(trap.getEndUnit()) +
00676 " with " + stmtToName.get(trap.getHandlerUnit()));
00677 }
00678 }
00679 }
00680 public void printTo(java.io.PrintWriter out)
00681 {
00682 printTo(out, 0);
00683 }
00684 public void printTo(PrintWriter out, int printBodyOptions)
00685 {
00686 boolean isPrecise = !PrintJimpleBodyOption.useAbbreviations(printBodyOptions);
00687
00688 if(PrintJimpleBodyOption.debugMode(printBodyOptions))
00689 {
00690 print_debug(out);
00691 return;
00692 }
00693
00694
00695
00696 StmtList stmtList = this.getStmtList();
00697
00698 Map stmtToName = new HashMap(stmtList.size() * 2 + 1, 0.7f);
00699
00700
00701 {
00702 StringBuffer buffer = new StringBuffer();
00703
00704 buffer.append(Modifier.toString(method.getModifiers()));
00705
00706 if(buffer.length() != 0)
00707 buffer.append(" ");
00708
00709 buffer.append(method.getReturnType().toString() + " " + method.getName());
00710 buffer.append("(");
00711
00712 Iterator typeIt = method.getParameterTypes().iterator();
00713
00714 if(typeIt.hasNext())
00715 {
00716 buffer.append(typeIt.next());
00717
00718 while(typeIt.hasNext())
00719 {
00720 buffer.append(", ");
00721 buffer.append(typeIt.next());
00722 }
00723 }
00724
00725 buffer.append(")");
00726
00727 out.print(" " + buffer.toString());
00728 }
00729
00730 out.println();
00731 out.println(" {");
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746 {
00747 Map typeToLocalSet = new HashMap(this.getLocalCount() * 2 + 1, 0.7f);
00748
00749
00750 {
00751 Iterator localIt = this.getLocals().iterator();
00752
00753 while(localIt.hasNext())
00754 {
00755 Local local = (Local) localIt.next();
00756
00757 Set localSet;
00758
00759 if(typeToLocalSet.containsKey(local.getType().toString()))
00760 localSet = (Set) typeToLocalSet.get(local.getType().toString());
00761 else
00762 {
00763 localSet = new HashSet();
00764 typeToLocalSet.put(local.getType().toString(), localSet);
00765 }
00766
00767 localSet.add(local);
00768 }
00769 }
00770
00771
00772 {
00773 Set typeSet = typeToLocalSet.keySet();
00774
00775 Object[] types = typeSet.toArray();
00776
00777 for(int j = 0; j < types.length; j++)
00778 {
00779 String type = (String) types[j];
00780
00781 Set localSet = (Set) typeToLocalSet.get(type);
00782 Object[] locals = localSet.toArray();
00783
00784 out.print(" " + type + " ");
00785
00786 for(int k = 0; k < locals.length; k++)
00787 {
00788 if(k != 0)
00789 out.print(", ");
00790
00791 out.print(((Local) locals[k]).getName());
00792 }
00793
00794 out.println(";");
00795 }
00796 }
00797
00798
00799 if(!typeToLocalSet.isEmpty())
00800 out.println();
00801 }
00802
00803
00804 printStatementsInBody(out, isPrecise);
00805
00806 out.println(" }");
00807 }
00808 public void redirectJumps(Stmt oldLocation, Stmt newLocation)
00809 {
00810 List boxesPointing = oldLocation.getBoxesPointingToThis();
00811
00812 Object[] boxes = boxesPointing.toArray();
00813
00814
00815 for(int i = 0; i < boxes.length; i++)
00816 {
00817 StmtBox box = (StmtBox) boxes[i];
00818
00819 if(box.getUnit() != oldLocation)
00820 throw new RuntimeException("Something weird's happening");
00821
00822 box.setUnit(newLocation);
00823 }
00824
00825 }
00826 public void removeLocal(Local l) throws IncorrectDeclarerException
00827 {
00828 locals.remove(l);
00829 }
00830 public void removeTrap(Trap t)
00831 {
00832 traps.remove(t);
00833 }
00834 }