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
00109
00110
00111
00112 import ca.mcgill.sable.soot.*;
00113 import ca.mcgill.sable.util.*;
00114 import ca.mcgill.sable.soot.grimp.*;
00115
00116 import java.io.*;
00117
00118 public class Main
00119 {
00120 static boolean naiveJimplification;
00121 static boolean onlyJimpleOutput;
00122 public static boolean isVerbose;
00123 static boolean onlyJasminOutput;
00124 static boolean isProfilingOptimization;
00125 static boolean oldTyping;
00126 static boolean isInDebugMode;
00127 static boolean usePackedLive;
00128 static boolean usePackedDefs = true;
00129 static boolean isTestingPerformance;
00130
00131 public static String jimpleClassPath;
00132
00133 static boolean produceJimpleFile,
00134 produceJasminFile,
00135 produceJimpFile = true;
00136
00137 static int totalFlowNodes,
00138 totalFlowComputations;
00139
00140 static Timer copiesTimer = new Timer(),
00141 defsTimer = new Timer(),
00142 usesTimer = new Timer(),
00143 liveTimer = new Timer(),
00144 splitTimer = new Timer(),
00145 packTimer = new Timer(),
00146 cleanup1Timer = new Timer(),
00147 cleanup2Timer = new Timer(),
00148 conversionTimer = new Timer(),
00149 cleanupAlgorithmTimer = new Timer(),
00150 graphTimer = new Timer(),
00151 assignTimer = new Timer(),
00152 resolveTimer = new Timer(),
00153 totalTimer = new Timer(),
00154 splitPhase1Timer = new Timer(),
00155 splitPhase2Timer = new Timer(),
00156 defsSetupTimer = new Timer(),
00157 defsAnalysisTimer = new Timer(),
00158 defsPostTimer = new Timer(),
00159 liveSetupTimer = new Timer(),
00160 liveAnalysisTimer = new Timer(),
00161 livePostTimer = new Timer(),
00162 aggregationTimer = new Timer(),
00163 grimpAggregationTimer = new Timer(),
00164 deadCodeTimer = new Timer(),
00165 propagatorTimer = new Timer();
00166
00167 static int conversionLocalCount,
00168 cleanup1LocalCount,
00169 splitLocalCount,
00170 assignLocalCount,
00171 packLocalCount,
00172 cleanup2LocalCount;
00173
00174 static int conversionStmtCount,
00175 cleanup1StmtCount,
00176 splitStmtCount,
00177 assignStmtCount,
00178 packStmtCount,
00179 cleanup2StmtCount;
00180
00181
00182 private static void handleClass(SootClass c, String postFix, PrintWriter writerOut, int buildBodyOptions)
00183 {
00184 if(postFix.equals(".jasmin"))
00185 new JasminClass(c, new BuildBody(Grimp.v(), new StoredBody(ClassFile.v()))).print(writerOut);
00186 else if(postFix.equals(".jimp"))
00187 {
00188 c.printTo(new BuildBody(Jimple.v(), new StoredBody(ClassFile.v()), buildBodyOptions),
00189 writerOut, PrintJimpleBodyOption.USE_ABBREVIATIONS);
00190 }
00191 else
00192 c.printTo(new BuildBody(Jimple.v(), new StoredBody(ClassFile.v()), buildBodyOptions),
00193 writerOut);
00194 }
00195 public static void main(String[] args) throws RuntimeException
00196 {
00197 int firstNonOption = 0;
00198 long stmtCount = 0;
00199 int buildBodyOptions = 0;
00200
00201 totalTimer.start();
00202
00203 SootClassManager cm = new SootClassManager();
00204
00205 if(args.length == 0)
00206 {
00207
00208 System.out.println("Jimple version 1.beta.4");
00209 System.out.println("Copyright (C) 1997, 1998 Raja Vallee-Rai (kor@sable.mcgill.ca).");
00210 System.out.println("All rights reserved.");
00211 System.out.println("");
00212 System.out.println("Portions copyright (C) 1997 Clark Verbrugge (clump@sable.mcgill.ca).");
00213 System.out.println("All rights reserved.");
00214 System.out.println("");
00215 System.out.println("Modifications are copyright (C) 1997, 1998 by their respective contributors.");
00216 System.out.println("See individual source files for details.");
00217 System.out.println("");
00218 System.out.println("Jimple comes with ABSOLUTELY NO WARRANTY. This is free software,");
00219 System.out.println("and you are welcome to redistribute it under certain conditions.");
00220 System.out.println("See the accompanying file 'COPYING' for details.");
00221 System.out.println("");
00222 System.out.println("Syntax: java ca.mcgill.sable.soot.jimple.Main [options] class");
00223 System.out.println("");
00224 System.out.println("Classpath Option:");
00225 System.out.println(" -jimpleClassPath <path> uses <path> as classpath for finding classes");
00226 System.out.println("");
00227 System.out.println("Output Options:");
00228 System.out.println(" -jimple produce .jimple code");
00229 System.out.println(" -jimp produce .jimp (abbreviated .jimple) code [default]");
00230 System.out.println(" -jasmin produce .jasmin code");
00231 System.out.println("");
00232 System.out.println("Jimplification Options:");
00233 System.out.println(" -nocleanup no constant or copy propagation is performed");
00234 System.out.println(" -nosplitting no splitting of variables is performed");
00235 System.out.println(" -nocleanup no constant or copy propagation is performed");
00236 System.out.println(" -oldtyping use old typing algorithm");
00237 System.out.println(" -typeless do not assign types. Cannot be used with -jasmin");
00238 System.out.println(" or -nolocalpacking ");
00239 System.out.println(" -nolocalpacking do not re-use locals after jimplification");
00240 System.out.println(" -noaggregating do not perform any Jimple-level aggregation");
00241 System.out.println("");
00242 System.out.println("Profiling/Debugging Options:");
00243 System.out.println(" -timetransform perform full transformation and print timings");
00244 System.out.println(" -verbose print out jimplification process");
00245 System.out.println(" -debug avoid catching errors during jimplification");
00246 System.out.println(" -testperf jimplify all classes & methods and gather stats");
00247 System.out.println(" does not throw exception if error in typing");
00248 System.exit(0);
00249 }
00250
00251
00252 for(int i = 0; i < args.length; i++)
00253 {
00254 if(args[i].equals("-jimple"))
00255 produceJimpleFile = true;
00256 else if(args[i].equals("-jasmin"))
00257 produceJasminFile = true;
00258 else if(args[i].equals("-jimp"))
00259 produceJimpFile = true;
00260 else if(args[i].equals("-nocleanup"))
00261 buildBodyOptions |= BuildJimpleBodyOption.NO_CLEANUP;
00262 else if(args[i].equals("-typeless"))
00263 buildBodyOptions |= BuildJimpleBodyOption.NO_TYPING;
00264 else if(args[i].equals("-nolocalpacking"))
00265 buildBodyOptions |= BuildJimpleBodyOption.NO_PACKING;
00266 else if(args[i].equals("-noaggregating"))
00267 buildBodyOptions |= BuildJimpleBodyOption.NO_AGGREGATING;
00268 else if(args[i].equals("-timetransform"))
00269 isProfilingOptimization = true;
00270 else if(args[i].equals("-verbose"))
00271 isVerbose = true;
00272 else if(args[i].equals("-nosplitting"))
00273 buildBodyOptions |= BuildJimpleBodyOption.NO_SPLITTING;
00274 else if(args[i].equals("-oldtyping"))
00275 oldTyping = true;
00276 else if(args[i].equals("-usepackedlive"))
00277 usePackedLive = true;
00278 else if(args[i].equals("-usepackeddefs"))
00279 usePackedDefs = true;
00280 else if(args[i].equals("-testperf"))
00281 {
00282 isProfilingOptimization = true;
00283 isTestingPerformance = true;
00284 }
00285 else if(args[i].equals("-jimpleClassPath"))
00286 { if(++i < args.length)
00287 jimpleClassPath = args[i];
00288 }
00289 else if(args[i].equals("-debug"))
00290 isInDebugMode = true;
00291 else if(args[i].startsWith("-"))
00292 {
00293 System.out.println("Unrecognized option: " + args[i]);
00294 System.exit(0);
00295 }
00296 else
00297 break;
00298
00299 firstNonOption = i + 1;
00300 }
00301
00302
00303 {
00304 int numFailed = 0;
00305 int numSuccess = 0;
00306
00307 List listBodies = new ArrayList();
00308
00309 for(int i = firstNonOption; i < args.length; i++)
00310 {
00311 SootClass c = cm.getClass(args[i]);
00312 String postFix;
00313 PrintWriter writerOut = null;
00314 FileOutputStream streamOut = null;
00315
00316 System.out.print("Jimplifying " + c.getName() + "... " );
00317 System.out.flush();
00318
00319
00320 {
00321 if(produceJasminFile)
00322 postFix = ".jasmin";
00323 else if(produceJimpleFile)
00324 postFix = ".jimple";
00325 else
00326 postFix = ".jimp";
00327
00328 try {
00329 streamOut = new FileOutputStream(c.getName() + postFix);
00330 writerOut = new PrintWriter(streamOut);
00331 }
00332 catch (IOException e)
00333 {
00334 System.out.println("Cannot output file " + c.getName() + postFix);
00335 }
00336 }
00337
00338 if(isTestingPerformance)
00339 {
00340 Iterator methodIt = c.getMethods().iterator();
00341 long localStmtCount = 0;
00342
00343 try {
00344 while(methodIt.hasNext())
00345 {
00346 SootMethod m = (SootMethod) methodIt.next();
00347 JimpleBody listBody = (JimpleBody) new BuildBody(Jimple.v(), new StoredBody(ClassFile.v())).resolveFor(m);
00348
00349 listBodies.add(listBody);
00350 localStmtCount += listBody.getStmtList().size();
00351 }
00352
00353 stmtCount += localStmtCount;
00354
00355 System.out.println(localStmtCount + " stmts ");
00356 numSuccess++;
00357 }
00358 catch(Exception e)
00359 {
00360 System.out.println("failed due to: " + e);
00361 numFailed++;
00362 }
00363 }
00364 else
00365 {
00366
00367 {
00368 if(!isInDebugMode)
00369 {
00370 try {
00371 handleClass(c, postFix, writerOut, buildBodyOptions);
00372 }
00373 catch(Exception e)
00374 {
00375 System.out.println("failed due to: " + e);
00376 }
00377 }
00378 else {
00379 handleClass(c, postFix, writerOut, buildBodyOptions);
00380 }
00381
00382 try {
00383 writerOut.flush();
00384 streamOut.close();
00385 }
00386 catch(IOException e )
00387 {
00388 System.out.println("Cannot close output file " + c.getName() + postFix);
00389 }
00390
00391 System.out.println();
00392 }
00393 }
00394 }
00395
00396 if(isProfilingOptimization)
00397 {
00398 if(isTestingPerformance)
00399 {
00400 System.out.println("Successfully jimplified " + numSuccess + " classfiles; failed on " + numFailed + ".");
00401
00402
00403 {
00404 Iterator bodyIt = listBodies.iterator();
00405 long storedStmtCount = 0;
00406
00407 while(bodyIt.hasNext())
00408 {
00409 JimpleBody listBody = (JimpleBody) bodyIt.next();
00410 storedStmtCount += listBody.getStmtList().size();
00411 }
00412
00413 System.out.println("Confirmed " + storedStmtCount + " stored statements.");
00414 System.out.println();
00415 }
00416 }
00417
00418 totalTimer.end();
00419
00420 long totalTime = totalTimer.getTime();
00421
00422 System.out.println("Time measurements");
00423 System.out.println();
00424
00425 System.out.println(" Building graphs: " + toTimeString(graphTimer, totalTime));
00426 System.out.println(" Computing LocalDefs: " + toTimeString(defsTimer, totalTime));
00427
00428
00429
00430 System.out.println(" Computing LocalUses: " + toTimeString(usesTimer, totalTime));
00431 System.out.println(" Cleaning up code: " + toTimeString(cleanupAlgorithmTimer, totalTime));
00432 System.out.println("Computing LocalCopies: " + toTimeString(copiesTimer, totalTime));
00433 System.out.println(" Computing LiveLocals: " + toTimeString(liveTimer, totalTime));
00434
00435
00436
00437
00438 System.out.println("Coading coffi structs: " + toTimeString(resolveTimer, totalTime));
00439
00440
00441 System.out.println();
00442
00443
00444 {
00445 float timeInSecs;
00446
00447 System.out.println(" Bytecode -> jimple (naive): " + toTimeString(conversionTimer, totalTime));
00448 System.out.println(" Splitting variables: " + toTimeString(splitTimer, totalTime));
00449 System.out.println(" Assigning types: " + toTimeString(assignTimer, totalTime));
00450 System.out.println(" Propagating copies & csts: " + toTimeString(propagatorTimer, totalTime));
00451 System.out.println(" Eliminating dead code: " + toTimeString(deadCodeTimer, totalTime));
00452 System.out.println(" Aggregation: " + toTimeString(aggregationTimer, totalTime));
00453 System.out.println(" Coloring locals: " + toTimeString(packTimer, totalTime));
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473 timeInSecs = (float) totalTime / 1000.0f;
00474 float memoryUsed = (float) (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1000.0f;
00475
00476 System.out.println("totalTime:" + toTimeString(totalTimer, totalTime));
00477 System.out.println("totalMemory:" + memoryUsed + "k ");
00478
00479 if(isTestingPerformance)
00480 {
00481 System.out.println("Time/Space performance");
00482 System.out.println();
00483
00484 System.out.println(toFormattedString(stmtCount / timeInSecs) + " stmt/s");
00485 System.out.println(toFormattedString((float) memoryUsed / stmtCount) + " k/stmt");
00486
00487 }
00488
00489 System.out.println("totalFlowNodes: " + totalFlowNodes +
00490 " totalFlowComputations: " + totalFlowComputations + " avg: " +
00491 truncatedOf((double) totalFlowComputations / totalFlowNodes, 2));
00492
00493 }
00494 }
00495 }
00496 }
00497 public static String paddedLeftOf(String s, int length)
00498 {
00499 if(s.length() >= length)
00500 return s;
00501 else {
00502 int diff = length - s.length();
00503 char[] padding = new char[diff];
00504
00505 for(int i = 0; i < diff; i++)
00506 padding[i] = ' ';
00507
00508 return new String(padding) + s;
00509 }
00510 }
00511 private static String toFormattedString(double value)
00512 {
00513 return paddedLeftOf(new Double(truncatedOf(value, 2)).toString(), 5);
00514 }
00515 private static String toTimeString(Timer timer, long totalTime)
00516 {
00517 long time = timer.getTime();
00518 String timeString = paddedLeftOf(new Double(truncatedOf(time / 1000.0, 1)).toString(), 5);
00519
00520 return (timeString + "s" + paddedLeftOf(" (" + (time * 100 / totalTime) + "%" + ")", 5));
00521 }
00522 public static double truncatedOf(double d, int numDigits)
00523 {
00524 double multiplier = 1;
00525
00526 for(int i = 0; i < numDigits; i++)
00527 multiplier *= 10;
00528
00529 return ((long) (d * multiplier)) / multiplier;
00530 }
00531 }