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
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140 import ca.mcgill.sable.soot.*;
00141 import ca.mcgill.sable.util.*;
00142 import java.io.*;
00143
00144 public class JasminClass
00145 {
00146 Map stmtToLabel;
00147 Map localToSlot;
00148 Map subroutineToReturnAddressSlot;
00149
00150 List code;
00151
00152 boolean isEmittingMethodCode;
00153 int labelCount;
00154
00155 boolean isNextGotoAJsr;
00156 int returnAddressSlot;
00157 int currentStackHeight = 0;
00158 int maxStackHeight = 0;
00159
00160 Map localToGroup;
00161 Map groupToColorCount;
00162 Map localToColor;
00163
00164
00165
00166
00167 Value plusPlusValue;
00168 Local plusPlusHolder;
00169 int plusPlusState;
00170 int plusPlusPlace;
00171 int plusPlusHeight;
00172 Stmt plusPlusIncrementer;
00173
00174 public JasminClass(SootClass SootClass, BodyExpr bodyExpr)
00175 {
00176 code = new LinkedList();
00177
00178
00179 {
00180 int modifiers = SootClass.getModifiers();
00181
00182 if(Modifier.isInterface(modifiers))
00183 {
00184 modifiers -= Modifier.INTERFACE;
00185
00186 emit(".interface " + Modifier.toString(modifiers) + " " + slashify(SootClass.getName()));
00187 }
00188 else
00189 emit(".class " + Modifier.toString(modifiers) + " " + slashify(SootClass.getName()));
00190
00191 if(SootClass.hasSuperClass())
00192 emit(".super " + slashify(SootClass.getSuperClass().getName()));
00193 else
00194 emit(".super " + slashify(SootClass.getName()));
00195
00196 emit("");
00197 }
00198
00199
00200 {
00201 Iterator interfaceIt = SootClass.getInterfaces().iterator();
00202
00203 while(interfaceIt.hasNext())
00204 {
00205 SootClass inter = (SootClass) interfaceIt.next();
00206
00207 emit(".implements " + slashify(inter.getName()));
00208 }
00209
00210 if(SootClass.getInterfaceCount() != 0)
00211 emit("");
00212 }
00213
00214
00215 {
00216 Iterator fieldIt = SootClass.getFields().iterator();
00217
00218 while(fieldIt.hasNext())
00219 {
00220 SootField field = (SootField) fieldIt.next();
00221
00222 emit(".field " + Modifier.toString(field.getModifiers()) + " " +
00223 "\"" + field.getName() + "\"" + " " + jasminDescriptorOf(field.getType()));
00224 }
00225
00226 if(SootClass.getFieldCount() != 0)
00227 emit("");
00228 }
00229
00230
00231 {
00232 Iterator methodIt = SootClass.getMethods().iterator();
00233
00234 while(methodIt.hasNext())
00235 {
00236 emitMethod((SootMethod) methodIt.next(), bodyExpr);
00237 emit("");
00238 }
00239 }
00240 }
00241 int argCountOf(SootMethod m)
00242 {
00243 int argCount = 0;
00244 Iterator typeIt = m.getParameterTypes().iterator();
00245
00246 while(typeIt.hasNext())
00247 {
00248 Type t = (Type) typeIt.next();
00249
00250 argCount += sizeOfType(t);
00251 }
00252
00253 return argCount;
00254 }
00255 void assignColorsToLocals(StmtBody body)
00256 {
00257 if(Main.isVerbose)
00258 System.out.println("[" + body.getMethod().getName() +
00259 "] Assigning colors to locals...");
00260
00261 if(Main.isProfilingOptimization)
00262 Main.packTimer.start();
00263
00264 localToGroup = new HashMap(body.getLocalCount() * 2 + 1, 0.7f);
00265 groupToColorCount = new HashMap(body.getLocalCount() * 2 + 1, 0.7f);
00266 localToColor = new HashMap(body.getLocalCount() * 2 + 1, 0.7f);
00267
00268
00269 {
00270 Iterator localIt = body.getLocals().iterator();
00271
00272 while(localIt.hasNext())
00273 {
00274 Local l = (Local) localIt.next();
00275 Object g;
00276
00277 if(sizeOfType(l.getType()) == 1)
00278 g = IntType.v();
00279 else
00280 g = LongType.v();
00281
00282 localToGroup.put(l, g);
00283
00284 if(!groupToColorCount.containsKey(g))
00285 {
00286 groupToColorCount.put(g, new Integer(0));
00287 }
00288 }
00289 }
00290
00291
00292 {
00293 Iterator codeIt = body.getStmtList().iterator();
00294
00295 while(codeIt.hasNext())
00296 {
00297 Stmt s = (Stmt) codeIt.next();
00298
00299 if(s instanceof IdentityStmt &&
00300 ((IdentityStmt) s).getLeftOp() instanceof Local)
00301 {
00302 Local l = (Local) ((IdentityStmt) s).getLeftOp();
00303
00304 Object group = localToGroup.get(l);
00305 int count = ((Integer) groupToColorCount.get(group)).intValue();
00306
00307 localToColor.put(l, new Integer(count));
00308
00309 count++;
00310
00311 groupToColorCount.put(group, new Integer(count));
00312 }
00313 }
00314 }
00315
00316
00317 FastColorer.assignColorsToLocals(body, localToGroup,
00318 localToColor, groupToColorCount);
00319
00320 if(Main.isProfilingOptimization)
00321 Main.packTimer.end();
00322
00323 }
00324 void emit(String s)
00325 {
00326 okayEmit(s);
00327 }
00328 void emit(String s, int stackChange)
00329 {
00330 modifyStackHeight(stackChange);
00331 okayEmit(s);
00332 }
00333 void emitAssignStmt(AssignStmt stmt)
00334 {
00335 final Value lvalue = stmt.getLeftOp();
00336 final Value rvalue = stmt.getRightOp();
00337
00338
00339 if(lvalue instanceof Local && (rvalue instanceof AddExpr || rvalue instanceof SubExpr))
00340 {
00341 Local l = (Local) lvalue;
00342 BinopExpr expr = (BinopExpr) rvalue;
00343 Value op1 = expr.getOp1();
00344 Value op2 = expr.getOp2();
00345
00346 if(l.getType().equals(IntType.v()))
00347 {
00348 boolean isValidCase = false;
00349 int x = 0;
00350
00351 if(op1 == l && op2 instanceof IntConstant)
00352 {
00353 x = ((IntConstant) op2).value;
00354 isValidCase = true;
00355 }
00356 else if(expr instanceof AddExpr &&
00357 op2 == l && op1 instanceof IntConstant)
00358 {
00359
00360
00361 x = ((IntConstant) op1).value;
00362 isValidCase = true;
00363 }
00364
00365 if(isValidCase && x >= Short.MIN_VALUE && x <= Short.MAX_VALUE)
00366 {
00367 emit("iinc " + ((Integer) localToSlot.get(l)).intValue() + " " +
00368 ((expr instanceof AddExpr) ? x : -x), 0);
00369 return;
00370 }
00371 }
00372 }
00373
00374 lvalue.apply(new AbstractJimpleValueSwitch()
00375 {
00376 public void caseArrayRef(ArrayRef v)
00377 {
00378 emitValue(v.getBase());
00379 emitValue(v.getIndex());
00380 emitValue(rvalue);
00381
00382 v.getType().apply(new TypeSwitch()
00383 {
00384 public void caseArrayType(ArrayType t)
00385 {
00386 emit("aastore", -3);
00387 }
00388
00389 public void caseDoubleType(DoubleType t)
00390 {
00391 emit("dastore", -4);
00392 }
00393
00394 public void caseFloatType(FloatType t)
00395 {
00396 emit("fastore", -3);
00397 }
00398
00399 public void caseIntType(IntType t)
00400 {
00401 emit("iastore", -3);
00402 }
00403
00404 public void caseLongType(LongType t)
00405 {
00406 emit("lastore", -4);
00407 }
00408
00409 public void caseRefType(RefType t)
00410 {
00411 emit("aastore", -3);
00412 }
00413
00414 public void caseByteType(ByteType t)
00415 {
00416 emit("bastore", -3);
00417 }
00418
00419 public void caseBooleanType(BooleanType t)
00420 {
00421 emit("bastore", -3);
00422 }
00423
00424 public void caseCharType(CharType t)
00425 {
00426 emit("castore", -3);
00427 }
00428
00429 public void caseShortType(ShortType t)
00430 {
00431 emit("sastore", -3);
00432 }
00433
00434 public void defaultCase(Type t)
00435 {
00436 throw new RuntimeException("Invalid type: " + t);
00437 }
00438 });
00439 }
00440
00441 public void defaultCase(Value v)
00442 {
00443 throw new RuntimeException("Can't store in value " + v);
00444 }
00445
00446 public void caseInstanceFieldRef(InstanceFieldRef v)
00447 {
00448 emitValue(v.getBase());
00449 emitValue(rvalue);
00450
00451 emit("putfield " + slashify(v.getField().getDeclaringClass().getName()) + "/" +
00452 v.getField().getName() + " " + jasminDescriptorOf(v.getField().getType()),
00453 -1 + -sizeOfType(v.getField().getType()));
00454 }
00455
00456 public void caseLocal(final Local v)
00457 {
00458 final int slot = ((Integer) localToSlot.get(v)).intValue();
00459
00460 v.getType().apply(new TypeSwitch()
00461 {
00462 public void caseArrayType(ArrayType t)
00463 {
00464 emitValue(rvalue);
00465
00466 if(slot >= 0 && slot <= 3)
00467 emit("astore_" + slot, -1);
00468 else
00469 emit("astore " + slot, -1);
00470 }
00471
00472 public void caseDoubleType(DoubleType t)
00473 {
00474 emitValue(rvalue);
00475
00476 if(slot >= 0 && slot <= 3)
00477 emit("dstore_" + slot, -2);
00478 else
00479 emit("dstore " + slot, -2);
00480 }
00481
00482 public void caseFloatType(FloatType t)
00483 {
00484 emitValue(rvalue);
00485
00486 if(slot >= 0 && slot <= 3)
00487 emit("fstore_" + slot, -1);
00488 else
00489 emit("fstore " + slot, -1);
00490 }
00491
00492 public void caseIntType(IntType t)
00493 {
00494 emitValue(rvalue);
00495
00496 if(slot >= 0 && slot <= 3)
00497 emit("istore_" + slot, -1);
00498 else
00499 emit("istore " + slot, -1);
00500 }
00501
00502 public void caseLongType(LongType t)
00503 {
00504 emitValue(rvalue);
00505
00506 if(slot >= 0 && slot <= 3)
00507 emit("lstore_" + slot, -2);
00508 else
00509 emit("lstore " + slot, -2);
00510 }
00511
00512 public void caseRefType(RefType t)
00513 {
00514 emitValue(rvalue);
00515
00516 if(slot >= 0 && slot <= 3)
00517 emit("astore_" + slot, -1);
00518 else
00519 emit("astore " + slot, -1);
00520 }
00521
00522 public void caseStmtAddressType(StmtAddressType t)
00523 {
00524 isNextGotoAJsr = true;
00525 returnAddressSlot = slot;
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535 }
00536
00537 public void caseNullType(NullType t)
00538 {
00539 emitValue(rvalue);
00540
00541 if(slot >= 0 && slot <= 3)
00542 emit("astore_" + slot, -1);
00543 else
00544 emit("astore " + slot, -1);
00545 }
00546
00547 public void defaultCase(Type t)
00548 {
00549 throw new RuntimeException("Invalid local type: " + t);
00550 }
00551 });
00552 }
00553
00554 public void caseStaticFieldRef(StaticFieldRef v)
00555 {
00556 SootField field = v.getField();
00557
00558 emitValue(rvalue);
00559 emit("putstatic " + slashify(field.getDeclaringClass().getName()) + "/" +
00560 field.getName() + " " + jasminDescriptorOf(field.getType()),
00561 -sizeOfType(v.getField().getType()));
00562 }
00563 });
00564 }
00565 public void emitBooleanBranch(String s)
00566 {
00567 int count;
00568
00569 if(s.indexOf("icmp") != -1 || s.indexOf("acmp") != -1)
00570 count = -2;
00571 else
00572 count = -1;
00573
00574 emit(s + " label" + labelCount, count);
00575 emit("iconst_0", 1);
00576 emit("goto label" + labelCount+1, 0);
00577 emit("label" + labelCount++ + ":");
00578 emit("iconst_1", 1);
00579 emit("label" + labelCount++ + ":");
00580 }
00581 void emitIfStmt(IfStmt stmt)
00582 {
00583 Value cond = stmt.getCondition();
00584
00585 final Value op1 = ((BinopExpr) cond).getOp1();
00586 final Value op2 = ((BinopExpr) cond).getOp2();
00587 final String label = (String) stmtToLabel.get(stmt.getTarget());
00588
00589
00590 if(op2 instanceof NullConstant || op1 instanceof NullConstant)
00591 {
00592 if(op2 instanceof NullConstant)
00593 emitValue(op1);
00594 else
00595 emitValue(op2);
00596
00597 if(cond instanceof EqExpr)
00598 emit("ifnull " + label, -1);
00599 else if(cond instanceof NeExpr)
00600 emit("ifnonnull "+ label, -1);
00601 else
00602 throw new RuntimeException("invalid condition");
00603
00604 return;
00605 }
00606
00607
00608 if(op2 instanceof IntConstant && ((IntConstant) op2).value == 0)
00609 {
00610 emitValue(op1);
00611
00612 cond.apply(new AbstractJimpleValueSwitch()
00613 {
00614 public void caseEqExpr(EqExpr expr)
00615 {
00616 emit("ifeq " + label, -1);
00617 }
00618
00619 public void caseNeExpr(NeExpr expr)
00620 {
00621 emit("ifne " + label, -1);
00622 }
00623
00624 public void caseLtExpr(LtExpr expr)
00625 {
00626 emit("iflt " + label, -1);
00627 }
00628
00629 public void caseLeExpr(LeExpr expr)
00630 {
00631 emit("ifle " + label, -1);
00632 }
00633
00634 public void caseGtExpr(GtExpr expr)
00635 {
00636 emit("ifgt " + label, -1);
00637 }
00638
00639 public void caseGeExpr(GeExpr expr)
00640 {
00641 emit("ifge " + label, -1);
00642 }
00643
00644 public void defaultCase(Value v)
00645 {
00646 throw new RuntimeException("invalid condition " + v);
00647 }
00648 });
00649
00650 return;
00651 }
00652
00653
00654 if(op1 instanceof IntConstant && ((IntConstant) op1).value == 0)
00655 {
00656 emitValue(op2);
00657
00658 cond.apply(new AbstractJimpleValueSwitch()
00659 {
00660 public void caseEqExpr(EqExpr expr)
00661 {
00662 emit("ifeq " + label, -1);
00663 }
00664
00665 public void caseNeExpr(NeExpr expr)
00666 {
00667 emit("ifne " + label, -1);
00668 }
00669
00670 public void caseLtExpr(LtExpr expr)
00671 {
00672 emit("ifgt " + label, -1);
00673 }
00674
00675 public void caseLeExpr(LeExpr expr)
00676 {
00677 emit("ifge " + label, -1);
00678 }
00679
00680 public void caseGtExpr(GtExpr expr)
00681 {
00682 emit("iflt " + label, -1);
00683 }
00684
00685 public void caseGeExpr(GeExpr expr)
00686 {
00687 emit("ifle " + label, -1);
00688 }
00689
00690 public void defaultCase(Value v)
00691 {
00692 throw new RuntimeException("invalid condition " + v);
00693 }
00694 });
00695
00696 return;
00697 }
00698
00699 emitValue(op1);
00700 emitValue(op2);
00701
00702 cond.apply(new AbstractJimpleValueSwitch()
00703 {
00704 public void caseEqExpr(EqExpr expr)
00705 {
00706 op1.getType().apply(new TypeSwitch()
00707 {
00708 public void caseIntType(IntType t)
00709 {
00710 emit("if_icmpeq " + label, -2);
00711 }
00712
00713 public void caseBooleanType(BooleanType t)
00714 {
00715 emit("if_icmpeq " + label, -2);
00716 }
00717
00718 public void caseShortType(ShortType t)
00719 {
00720 emit("if_icmpeq " + label, -2);
00721 }
00722
00723 public void caseCharType(CharType t)
00724 {
00725 emit("if_icmpeq " + label, -2);
00726 }
00727
00728 public void caseByteType(ByteType t)
00729 {
00730 emit("if_icmpeq " + label, -2);
00731 }
00732
00733 public void caseDoubleType(DoubleType t)
00734 {
00735 emit("dcmpg", -3);
00736 emit("ifeq " + label, -1);
00737 }
00738
00739 public void caseLongType(LongType t)
00740 {
00741 emit("lcmp", -3);
00742 emit("ifeq " + label, -1);
00743 }
00744
00745 public void caseFloatType(FloatType t)
00746 {
00747 emit("fcmpg", -1);
00748 emit("ifeq " + label, -1);
00749 }
00750
00751 public void caseArrayType(ArrayType t)
00752 {
00753 emit("if_acmpeq " + label, -2);
00754 }
00755
00756 public void caseRefType(RefType t)
00757 {
00758 emit("if_acmpeq " + label, -2);
00759 }
00760
00761 public void caseNullType(NullType t)
00762 {
00763 emit("if_acmpeq " + label, -2);
00764 }
00765
00766 public void defaultCase(Type t)
00767 {
00768 throw new RuntimeException("invalid type");
00769 }
00770 });
00771 }
00772
00773 public void caseNeExpr(NeExpr expr)
00774 {
00775 op1.getType().apply(new TypeSwitch()
00776 {
00777 public void caseIntType(IntType t)
00778 {
00779 emit("if_icmpne " + label, -2);
00780 }
00781
00782 public void caseBooleanType(BooleanType t)
00783 {
00784 emit("if_icmpne " + label, -2);
00785 }
00786
00787 public void caseShortType(ShortType t)
00788 {
00789 emit("if_icmpne " + label, -2);
00790 }
00791
00792 public void caseCharType(CharType t)
00793 {
00794 emit("if_icmpne " + label, -2);
00795 }
00796
00797 public void caseByteType(ByteType t)
00798 {
00799 emit("if_icmpne " + label, -2);
00800 }
00801
00802 public void caseDoubleType(DoubleType t)
00803 {
00804 emit("dcmpg", -3);
00805 emit("ifne " + label, -1);
00806 }
00807
00808 public void caseLongType(LongType t)
00809 {
00810 emit("lcmp", -3);
00811 emit("ifne " + label, -1);
00812 }
00813
00814 public void caseFloatType(FloatType t)
00815 {
00816 emit("fcmpg", -1);
00817 emit("ifne " + label, -1);
00818 }
00819
00820 public void caseArrayType(ArrayType t)
00821 {
00822 emit("if_acmpne " + label, -2);
00823 }
00824
00825 public void caseRefType(RefType t)
00826 {
00827 emit("if_acmpne " + label, -2);
00828 }
00829
00830 public void caseNullType(NullType t)
00831 {
00832 emit("if_acmpne " + label, -2);
00833 }
00834
00835 public void defaultCase(Type t)
00836 {
00837 throw new RuntimeException("invalid type for NeExpr: " + t);
00838 }
00839 });
00840 }
00841
00842 public void caseLtExpr(LtExpr expr)
00843 {
00844 op1.getType().apply(new TypeSwitch()
00845 {
00846 public void caseIntType(IntType t)
00847 {
00848 emit("if_icmplt " + label, -2);
00849 }
00850
00851 public void caseBooleanType(BooleanType t)
00852 {
00853 emit("if_icmplt " + label, -2);
00854 }
00855
00856 public void caseShortType(ShortType t)
00857 {
00858 emit("if_icmplt " + label, -2);
00859 }
00860
00861 public void caseCharType(CharType t)
00862 {
00863 emit("if_icmplt " + label, -2);
00864 }
00865
00866 public void caseByteType(ByteType t)
00867 {
00868 emit("if_icmplt " + label, -2);
00869 }
00870
00871
00872 public void caseDoubleType(DoubleType t)
00873 {
00874 emit("dcmpg", -3);
00875 emit("iflt " + label, -1);
00876 }
00877
00878 public void caseLongType(LongType t)
00879 {
00880 emit("lcmp", -3);
00881 emit("iflt " + label, -1);
00882 }
00883
00884 public void caseFloatType(FloatType t)
00885 {
00886 emit("fcmpg", -1);
00887 emit("iflt " + label, -1);
00888 }
00889
00890 public void defaultCase(Type t)
00891 {
00892 throw new RuntimeException("invalid type");
00893 }
00894 });
00895 }
00896
00897 public void caseLeExpr(LeExpr expr)
00898 {
00899 op1.getType().apply(new TypeSwitch()
00900 {
00901 public void caseIntType(IntType t)
00902 {
00903 emit("if_icmple " + label, -2);
00904 }
00905
00906 public void caseBooleanType(BooleanType t)
00907 {
00908 emit("if_icmple " + label, -2);
00909 }
00910
00911 public void caseShortType(ShortType t)
00912 {
00913 emit("if_icmple " + label, -2);
00914 }
00915
00916 public void caseCharType(CharType t)
00917 {
00918 emit("if_icmple " + label, -2);
00919 }
00920
00921 public void caseByteType(ByteType t)
00922 {
00923 emit("if_icmple " + label, -2);
00924 }
00925
00926 public void caseDoubleType(DoubleType t)
00927 {
00928 emit("dcmpg", -3);
00929 emit("ifle " + label, -1);
00930 }
00931
00932 public void caseLongType(LongType t)
00933 {
00934 emit("lcmp", -3);
00935 emit("ifle " + label, -1);
00936 }
00937
00938 public void caseFloatType(FloatType t)
00939 {
00940 emit("fcmpg", -1);
00941 emit("ifle " + label, -1);
00942 }
00943
00944 public void defaultCase(Type t)
00945 {
00946 throw new RuntimeException("invalid type");
00947 }
00948 });
00949 }
00950
00951 public void caseGtExpr(GtExpr expr)
00952 {
00953 op1.getType().apply(new TypeSwitch()
00954 {
00955 public void caseIntType(IntType t)
00956 {
00957 emit("if_icmpgt " + label, -2);
00958 }
00959
00960 public void caseBooleanType(BooleanType t)
00961 {
00962 emit("if_icmpgt " + label, -2);
00963 }
00964
00965 public void caseShortType(ShortType t)
00966 {
00967 emit("if_icmpgt " + label, -2);
00968 }
00969
00970 public void caseCharType(CharType t)
00971 {
00972 emit("if_icmpgt " + label, -2);
00973 }
00974
00975 public void caseByteType(ByteType t)
00976 {
00977 emit("if_icmpgt " + label, -2);
00978 }
00979
00980 public void caseDoubleType(DoubleType t)
00981 {
00982 emit("dcmpg", -3);
00983 emit("ifgt " + label, -1);
00984 }
00985
00986 public void caseLongType(LongType t)
00987 {
00988 emit("lcmp", -3);
00989 emit("ifgt " + label, -1);
00990 }
00991
00992 public void caseFloatType(FloatType t)
00993 {
00994 emit("fcmpg", -1);
00995 emit("ifgt " + label, -1);
00996 }
00997
00998 public void defaultCase(Type t)
00999 {
01000 throw new RuntimeException("invalid type");
01001 }
01002 });
01003 }
01004
01005 public void caseGeExpr(GeExpr expr)
01006 {
01007 op1.getType().apply(new TypeSwitch()
01008 {
01009 public void caseIntType(IntType t)
01010 {
01011 emit("if_icmpge " + label, -2);
01012 }
01013
01014 public void caseBooleanType(BooleanType t)
01015 {
01016 emit("if_icmpge " + label, -2);
01017 }
01018
01019 public void caseShortType(ShortType t)
01020 {
01021 emit("if_icmpge " + label, -2);
01022 }
01023
01024 public void caseCharType(CharType t)
01025 {
01026 emit("if_icmpge " + label, -2);
01027 }
01028
01029 public void caseByteType(ByteType t)
01030 {
01031 emit("if_icmpge " + label, -2);
01032 }
01033
01034 public void caseDoubleType(DoubleType t)
01035 {
01036 emit("dcmpg", -3);
01037 emit("ifge " + label, -1);
01038 }
01039
01040 public void caseLongType(LongType t)
01041 {
01042 emit("lcmp", -3);
01043 emit("ifge " + label, -1);
01044 }
01045
01046 public void caseFloatType(FloatType t)
01047 {
01048 emit("fcmpg", -1);
01049 emit("ifge " + label, -1);
01050 }
01051
01052 public void defaultCase(Type t)
01053 {
01054 throw new RuntimeException("invalid type");
01055 }
01056 });
01057 }
01058
01059 public void defaultCase(Value v)
01060 {
01061 throw new RuntimeException("invalid condition " + v);
01062 }
01063 });
01064 }
01065 void emitLocal(Local v)
01066 {
01067 final int slot = ((Integer) localToSlot.get(v)).intValue();
01068 final Local vAlias = v;
01069
01070 v.getType().apply(new TypeSwitch()
01071 {
01072 public void caseArrayType(ArrayType t)
01073 {
01074 if(slot >= 0 && slot <= 3)
01075 emit("aload_" + slot, 1);
01076 else
01077 emit("aload " + slot, 1);
01078 }
01079
01080 public void defaultCase(Type t)
01081 {
01082 throw new RuntimeException("invalid local type to load" + t);
01083 }
01084
01085 public void caseDoubleType(DoubleType t)
01086 {
01087 if(slot >= 0 && slot <= 3)
01088 emit("dload_" + slot, 2);
01089 else
01090 emit("dload " + slot, 2);
01091 }
01092
01093 public void caseFloatType(FloatType t)
01094 {
01095 if(slot >= 0 && slot <= 3)
01096 emit("fload_" + slot, 1);
01097 else
01098 emit("fload " + slot, 1);
01099 }
01100
01101 public void caseIntType(IntType t)
01102 {
01103 if (vAlias.equals(plusPlusHolder))
01104 {
01105 switch(plusPlusState)
01106 {
01107 case 0:
01108
01109
01110
01111
01112
01113
01114
01115 plusPlusState = 1;
01116
01117 emitStmt(plusPlusIncrementer);
01118 int diff = plusPlusHeight - currentStackHeight + 1;
01119 if (diff > 0)
01120 code.set(plusPlusPlace, " dup_x"+diff);
01121 plusPlusHolder = null;
01122
01123
01124 return;
01125 case 1:
01126 plusPlusHeight = currentStackHeight;
01127
01128 emitValue(plusPlusValue);
01129
01130 plusPlusPlace = code.size();
01131 emit("dup", 1);
01132
01133 return;
01134 }
01135 }
01136 if(slot >= 0 && slot <= 3)
01137 emit("iload_" + slot, 1);
01138 else
01139 emit("iload " + slot, 1);
01140 }
01141
01142 public void caseLongType(LongType t)
01143 {
01144 if(slot >= 0 && slot <= 3)
01145 emit("lload_" + slot, 2);
01146 else
01147 emit("lload " + slot, 2);
01148 }
01149
01150 public void caseRefType(RefType t)
01151 {
01152 if(slot >= 0 && slot <= 3)
01153 emit("aload_" + slot, 1);
01154 else
01155 emit("aload " + slot, 1);
01156 }
01157
01158 public void caseNullType(NullType t)
01159 {
01160 if(slot >= 0 && slot <= 3)
01161 emit("aload_" + slot, 1);
01162 else
01163 emit("aload " + slot, 1);
01164 }
01165 });
01166 }
01167 void emitMethod(SootMethod method, BodyExpr bodyExpr)
01168 {
01169 StmtBody body = (StmtBody) bodyExpr.resolveFor(method);
01170 StmtList stmtList = body.getStmtList();
01171
01172
01173
01174 if(Main.isVerbose)
01175 System.out.println("[" + body.getMethod().getName() +
01176 "] Performing peephole optimizations...");
01177
01178 CompleteStmtGraph stmtGraph = new CompleteStmtGraph(stmtList);
01179
01180 LocalDefs ld = new SimpleLocalDefs(stmtGraph);
01181 LocalUses lu = new SimpleLocalUses(stmtGraph, ld);
01182
01183 int stackLimitIndex;
01184
01185
01186 emit(".method " + Modifier.toString(method.getModifiers()) + " " +
01187 method.getName() + jasminDescriptorOf(method));
01188
01189 subroutineToReturnAddressSlot = new HashMap(10, 0.7f);
01190
01191
01192 {
01193 Iterator boxIt = body.getUnitBoxes().iterator();
01194
01195 stmtToLabel = new HashMap(stmtList.size() * 2 + 1, 0.7f);
01196 labelCount = 0;
01197
01198 while(boxIt.hasNext())
01199 {
01200
01201 {
01202 StmtBox box = (StmtBox) boxIt.next();
01203
01204 if(!stmtToLabel.containsKey(box.getUnit()))
01205 stmtToLabel.put(box.getUnit(), "label" + labelCount++);
01206 }
01207 }
01208 }
01209
01210
01211 {
01212 Iterator trapIt = body.getTraps().iterator();
01213
01214 while(trapIt.hasNext())
01215 {
01216 Trap trap = (Trap) trapIt.next();
01217
01218 if(trap.getBeginUnit() != trap.getEndUnit())
01219 emit(".catch " + slashify(trap.getException().getName()) + " from " +
01220 stmtToLabel.get(trap.getBeginUnit()) + " to " + stmtToLabel.get(trap.getEndUnit()) +
01221 " using " + stmtToLabel.get(trap.getHandlerUnit()));
01222 }
01223 }
01224
01225
01226 {
01227 int localCount = 0;
01228 int[] paramSlots = new int[method.getParameterCount()];
01229 int thisSlot = 0;
01230 Set assignedLocals = new HashSet();
01231 Map groupColorPairToSlot = new HashMap(body.getLocalCount() * 2 + 1, 0.7f);
01232
01233 localToSlot = new HashMap(body.getLocalCount() * 2 + 1, 0.7f);
01234
01235 assignColorsToLocals(body);
01236
01237
01238 {
01239 List paramTypes = method.getParameterTypes();
01240
01241 if(!method.isStatic())
01242 {
01243 thisSlot = 0;
01244 localCount++;
01245 }
01246
01247 for(int i = 0; i < paramTypes.size(); i++)
01248 {
01249 paramSlots[i] = localCount;
01250 localCount += sizeOfType((Type) paramTypes.get(i));
01251 }
01252 }
01253
01254
01255 {
01256 Iterator stmtIt = stmtList.iterator();
01257
01258 while(stmtIt.hasNext())
01259 {
01260 Stmt s = (Stmt) stmtIt.next();
01261
01262 if(s instanceof IdentityStmt && ((IdentityStmt) s).getLeftOp() instanceof Local)
01263 {
01264 Local l = (Local) ((IdentityStmt) s).getLeftOp();
01265 IdentityRef identity = (IdentityRef) ((IdentityStmt) s).getRightOp();
01266
01267 int slot = 0;
01268
01269 if(identity instanceof ThisRef)
01270 {
01271 if(method.isStatic())
01272 throw new RuntimeException("Attempting to use 'this' in static method");
01273
01274 slot = thisSlot;
01275 }
01276 else if(identity instanceof ParameterRef)
01277 slot = paramSlots[((ParameterRef) identity).getIndex()];
01278 else {
01279
01280 continue;
01281 }
01282
01283
01284
01285 {
01286
01287 GroupIntPair pair = new GroupIntPair(localToGroup.get(l),
01288 ((Integer) localToColor.get(l)).intValue());
01289
01290 groupColorPairToSlot.put(pair, new Integer(slot));
01291 }
01292
01293 localToSlot.put(l, new Integer(slot));
01294 assignedLocals.add(l);
01295
01296 }
01297 }
01298 }
01299
01300
01301 {
01302 Iterator localIt = body.getLocals().iterator();
01303
01304 while(localIt.hasNext())
01305 {
01306 Local local = (Local) localIt.next();
01307
01308 if(!assignedLocals.contains(local))
01309 {
01310 GroupIntPair pair = new GroupIntPair(localToGroup.get(local),
01311 ((Integer) localToColor.get(local)).intValue());
01312
01313 int slot;
01314
01315 if(groupColorPairToSlot.containsKey(pair))
01316 {
01317
01318
01319
01320 slot = ((Integer) groupColorPairToSlot.get(pair)).intValue();
01321 }
01322 else {
01323 slot = localCount;
01324 localCount += sizeOfType(local.getType());
01325
01326 groupColorPairToSlot.put(pair, new Integer(slot));
01327 }
01328
01329 localToSlot.put(local, new Integer(slot));
01330 assignedLocals.add(local);
01331 }
01332 }
01333
01334 emit(" .limit stack ?");
01335 stackLimitIndex = code.size() - 1;
01336
01337 emit(" .limit locals " + localCount);
01338 }
01339 }
01340
01341
01342 {
01343 Iterator codeIt = stmtList.iterator();
01344
01345 isEmittingMethodCode = true;
01346 maxStackHeight = 0;
01347 isNextGotoAJsr = false;
01348
01349 while(codeIt.hasNext())
01350 {
01351 Stmt s = (Stmt) codeIt.next();
01352
01353 if(stmtToLabel.containsKey(s))
01354 emit(stmtToLabel.get(s) + ":");
01355
01356 if(subroutineToReturnAddressSlot.containsKey(s))
01357 {
01358 AssignStmt assignStmt = (AssignStmt) s;
01359
01360 modifyStackHeight(1);
01361
01362 emit("astore " + localToSlot.get(assignStmt.getLeftOp()), -1);
01363
01364
01365
01366 }
01367
01368
01369
01370
01371
01372 boolean contFlag = false;
01373
01374 do
01375 {
01376 if (!(s instanceof AssignStmt))
01377 break;
01378
01379 AssignStmt stmt = (AssignStmt)s;
01380
01381
01382 if (!codeIt.hasNext())
01383 break;
01384
01385 Stmt ns = (Stmt)(stmtGraph.getSuccsOf(stmt).get(0));
01386 if (!(ns instanceof AssignStmt))
01387 break;
01388 AssignStmt nextStmt = (AssignStmt)ns;
01389
01390 List l = stmtGraph.getSuccsOf(nextStmt);
01391 if (l.size() != 1)
01392 break;
01393
01394 Stmt nextNextStmt = (Stmt)(l.get(0));
01395
01396 final Value lvalue = stmt.getLeftOp();
01397 final Value rvalue = stmt.getRightOp();
01398
01399 if (!(lvalue instanceof Local))
01400 break;
01401
01402
01403
01404
01405
01406
01407
01408 if (!(lvalue instanceof Local)
01409 || !nextStmt.getLeftOp().equals(rvalue)
01410 || !(nextStmt.getRightOp() instanceof AddExpr))
01411 break;
01412
01413 AddExpr addexp = (AddExpr)nextStmt.getRightOp();
01414 if (!addexp.getOp1().equals(lvalue))
01415 break;
01416
01417 Value added = addexp.getOp2();
01418
01419 if (!(added instanceof IntConstant)
01420 || ((IntConstant)(added)).value != 1)
01421 break;
01422
01423
01424
01425
01426
01427 if (lu.getUsesOf(stmt).size() != 2 ||
01428 ld.getDefsOfAt((Local)lvalue, nextStmt).size() != 1 ||
01429 ld.getDefsOfAt((Local)lvalue, nextNextStmt).size() !=1)
01430 break;
01431
01432
01433
01434
01435
01436
01437
01438
01439
01440
01441 if (lvalue.getType() != IntType.v())
01442 break;
01443
01444
01445
01446
01447
01448
01449
01450 currentStackHeight = 0;
01451
01452
01453 plusPlusValue = rvalue;
01454 plusPlusHolder = (Local)lvalue;
01455 plusPlusIncrementer = nextStmt;
01456 plusPlusState = 0;
01457
01458
01459 emitStmt(nextNextStmt);
01460
01461
01462 if (plusPlusHolder != null)
01463 { emitStmt(stmt); emitStmt(nextStmt); }
01464
01465 if(currentStackHeight != 0)
01466 throw new RuntimeException("Stack has height " + currentStackHeight + " after execution of stmt: " + s);
01467 contFlag = true;
01468 codeIt.next(); codeIt.next();
01469 }
01470 while(false);
01471 if (contFlag)
01472 continue;
01473
01474
01475 {
01476 currentStackHeight = 0;
01477 emitStmt(s);
01478
01479 if(currentStackHeight != 0)
01480 throw new RuntimeException("Stack has height " + currentStackHeight + " after execution of stmt: " + s);
01481 }
01482 }
01483
01484 isEmittingMethodCode = false;
01485
01486 code.set(stackLimitIndex, " .limit stack " + maxStackHeight);
01487 }
01488
01489
01490 emit(".end method");
01491
01492 }
01493 void emitStmt(Stmt stmt)
01494 {
01495 stmt.apply(new AbstractStmtSwitch()
01496 {
01497 public void caseAssignStmt(AssignStmt s)
01498 {
01499 emitAssignStmt(s);
01500 }
01501
01502 public void caseIdentityStmt(IdentityStmt s)
01503 {
01504 if(s.getRightOp() instanceof CaughtExceptionRef &&
01505 s.getLeftOp() instanceof Local)
01506 {
01507 int slot = ((Integer) localToSlot.get(s.getLeftOp())).intValue();
01508
01509 modifyStackHeight(1);
01510
01511 emit("astore " + slot, -1);
01512 }
01513 }
01514
01515 public void caseBreakpointStmt(BreakpointStmt s)
01516 {
01517 emit("breakpoint", 0);
01518 }
01519
01520 public void caseInvokeStmt(InvokeStmt s)
01521 {
01522 emitValue(s.getInvokeExpr());
01523
01524 Type returnType = ((InvokeExpr) s.getInvokeExpr()).getMethod().getReturnType();
01525
01526 if(!returnType.equals(VoidType.v()))
01527 {
01528
01529
01530 if(sizeOfType(returnType) == 1)
01531 emit("pop", -1);
01532 else
01533 emit("pop2", -2);
01534 }
01535 }
01536
01537 public void defaultCase(Stmt s)
01538 {
01539 throw new RuntimeException("invalid stmt: " + s);
01540 }
01541
01542 public void caseEnterMonitorStmt(EnterMonitorStmt s)
01543 {
01544 emitValue(s.getOp());
01545 emit("monitorenter", -1);
01546 }
01547
01548 public void caseExitMonitorStmt(ExitMonitorStmt s)
01549 {
01550 emitValue(s.getOp());
01551 emit("monitorexit", -1);
01552 }
01553
01554 public void caseGotoStmt(GotoStmt s)
01555 {
01556 if(isNextGotoAJsr)
01557 {
01558 emit("jsr " + stmtToLabel.get(s.getTarget()));
01559 isNextGotoAJsr = false;
01560
01561 subroutineToReturnAddressSlot.put(s.getTarget(), new Integer(returnAddressSlot));
01562 }
01563 else
01564 emit("goto " + stmtToLabel.get(s.getTarget()));
01565 }
01566
01567
01568 public void caseIfStmt(IfStmt s)
01569 {
01570 emitIfStmt(s);
01571 }
01572
01573 public void caseLookupSwitchStmt(LookupSwitchStmt s)
01574 {
01575 emitValue(s.getKey());
01576 emit("lookupswitch", -1);
01577
01578 List lookupValues = s.getLookupValues();
01579 List targets = s.getTargets();
01580
01581 for(int i = 0; i < lookupValues.size(); i++)
01582 emit(" " + lookupValues.get(i) + " : " + stmtToLabel.get(targets.get(i)));
01583
01584 emit(" default : " + stmtToLabel.get(s.getDefaultTarget()));
01585 }
01586
01587 public void caseNopStmt(NopStmt s)
01588 {
01589 emit("nop", 0);
01590 }
01591
01592 public void caseRetStmt(RetStmt s)
01593 {
01594 emit("ret " + localToSlot.get(s.getStmtAddress()), 0);
01595 }
01596
01597 public void caseReturnStmt(ReturnStmt s)
01598 {
01599 emitValue(s.getReturnValue());
01600
01601 Value returnValue = s.getReturnValue();
01602
01603 returnValue.getType().apply(new TypeSwitch()
01604 {
01605 public void defaultCase(Type t)
01606 {
01607 throw new RuntimeException("invalid return type " + t.toString());
01608 }
01609
01610 public void caseDoubleType(DoubleType t)
01611 {
01612 emit("dreturn", -2);
01613 }
01614
01615 public void caseFloatType(FloatType t)
01616 {
01617 emit("freturn", -1);
01618 }
01619
01620 public void caseIntType(IntType t)
01621 {
01622 emit("ireturn", -1);
01623 }
01624
01625 public void caseByteType(ByteType t)
01626 {
01627 emit("ireturn", -1);
01628 }
01629
01630 public void caseShortType(ShortType t)
01631 {
01632 emit("ireturn", -1);
01633 }
01634
01635 public void caseCharType(CharType t)
01636 {
01637 emit("ireturn", -1);
01638 }
01639
01640 public void caseBooleanType(BooleanType t)
01641 {
01642 emit("ireturn", -1);
01643 }
01644
01645 public void caseLongType(LongType t)
01646 {
01647 emit("lreturn", -2);
01648 }
01649
01650 public void caseArrayType(ArrayType t)
01651 {
01652 emit("areturn", -1);
01653 }
01654
01655 public void caseRefType(RefType t)
01656 {
01657 emit("areturn", -1);
01658 }
01659
01660 public void caseNullType(NullType t)
01661 {
01662 emit("areturn", -1);
01663 }
01664
01665 });
01666 }
01667
01668 public void caseReturnVoidStmt(ReturnVoidStmt s)
01669 {
01670 emit("return", 0);
01671 }
01672
01673 public void caseTableSwitchStmt(TableSwitchStmt s)
01674 {
01675 emitValue(s.getKey());
01676 emit("tableswitch " + s.getLowIndex() + " ; high = " + s.getHighIndex(), -1);
01677
01678 List targets = s.getTargets();
01679
01680 for(int i = 0; i < targets.size(); i++)
01681 emit(" " + stmtToLabel.get(targets.get(i)));
01682
01683 emit("default : " + stmtToLabel.get(s.getDefaultTarget()));
01684 }
01685
01686 public void caseThrowStmt(ThrowStmt s)
01687 {
01688 emitValue(s.getOp());
01689 emit("athrow", -1);
01690 }
01691 });
01692 }
01693 void emitValue(Value value)
01694 {
01695 value.apply(new AbstractJimpleValueSwitch()
01696 {
01697 public void caseAddExpr(AddExpr v)
01698 {
01699 emitValue(v.getOp1());
01700 emitValue(v.getOp2());
01701
01702 v.getType().apply(new TypeSwitch()
01703 {
01704 private void handleIntCase()
01705 {
01706 emit("iadd", -1);
01707 }
01708
01709 public void caseIntType(IntType t) { handleIntCase(); }
01710 public void caseBooleanType(BooleanType t) { handleIntCase(); }
01711 public void caseShortType(ShortType t) { handleIntCase(); }
01712 public void caseCharType(CharType t) { handleIntCase(); }
01713 public void caseByteType(ByteType t) { handleIntCase(); }
01714
01715 public void caseLongType(LongType t)
01716 {
01717 emit("ladd", -2);
01718 }
01719
01720 public void caseDoubleType(DoubleType t)
01721 {
01722 emit("dadd", -2);
01723 }
01724
01725 public void caseFloatType(FloatType t)
01726 {
01727 emit("fadd", -1);
01728 }
01729
01730 public void defaultCase(Type t)
01731 {
01732 throw new RuntimeException("Invalid argument type for add");
01733 }
01734 });
01735
01736 }
01737
01738 public void caseAndExpr(AndExpr v)
01739 {
01740 emitValue(v.getOp1());
01741 emitValue(v.getOp2());
01742
01743 v.getType().apply(new TypeSwitch()
01744 {
01745 private void handleIntCase()
01746 {
01747 emit("iand", -1);
01748 }
01749
01750 public void caseIntType(IntType t) { handleIntCase(); }
01751 public void caseBooleanType(BooleanType t) { handleIntCase(); }
01752 public void caseShortType(ShortType t) { handleIntCase(); }
01753 public void caseCharType(CharType t) { handleIntCase(); }
01754 public void caseByteType(ByteType t) { handleIntCase(); }
01755
01756 public void caseLongType(LongType t)
01757 {
01758 emit("land", -2);
01759 }
01760
01761 public void defaultCase(Type t)
01762 {
01763 throw new RuntimeException("Invalid argument type for and");
01764 }
01765 });
01766 }
01767
01768 public void caseArrayRef(ArrayRef v)
01769 {
01770 emitValue(v.getBase());
01771 emitValue(v.getIndex());
01772
01773 v.getType().apply(new TypeSwitch()
01774 {
01775 public void caseArrayType(ArrayType ty)
01776 {
01777 emit("aaload", -1);
01778 }
01779
01780 public void caseBooleanType(BooleanType ty)
01781 {
01782 emit("baload", -1);
01783 }
01784
01785 public void caseByteType(ByteType ty)
01786 {
01787 emit("baload", -1);
01788 }
01789
01790 public void caseCharType(CharType ty)
01791 {
01792 emit("caload", -1);
01793 }
01794
01795 public void defaultCase(Type ty)
01796 {
01797 throw new RuntimeException("invalid base type");
01798 }
01799
01800 public void caseDoubleType(DoubleType ty)
01801 {
01802 emit("daload", 0);
01803 }
01804
01805 public void caseFloatType(FloatType ty)
01806 {
01807 emit("faload", -1);
01808 }
01809
01810 public void caseIntType(IntType ty)
01811 {
01812 emit("iaload", -1);
01813 }
01814
01815 public void caseLongType(LongType ty)
01816 {
01817 emit("laload", 0);
01818 }
01819
01820 public void caseNullType(NullType ty)
01821 {
01822 emit("aaload", -1);
01823 }
01824 public void caseRefType(RefType ty)
01825 {
01826 emit("aaload", -1);
01827 }
01828
01829 public void caseShortType(ShortType ty)
01830 {
01831 emit("saload", -1);
01832 }
01833 });
01834 }
01835
01836 public void caseCastExpr(final CastExpr v)
01837 {
01838 final Type toType = v.getCastType();
01839 final Type fromType = v.getOp().getType();
01840
01841 emitValue(v.getOp());
01842
01843 if(toType instanceof RefType)
01844 emit("checkcast " + slashify(toType.toString()), 0);
01845 else if(toType instanceof ArrayType)
01846 emit("checkcast " + jasminDescriptorOf(toType), 0);
01847 else {
01848 fromType.apply(new TypeSwitch()
01849 {
01850 public void defaultCase(Type ty)
01851 {
01852 throw new RuntimeException("invalid fromType " + fromType);
01853 }
01854
01855 public void caseDoubleType(DoubleType ty)
01856 {
01857 if(toType.equals(IntType.v()))
01858 emit("d2i", -1);
01859 else if(toType.equals(LongType.v()))
01860 emit("d2l", 0);
01861 else if(toType.equals(FloatType.v()))
01862 emit("d2f", -1);
01863 else
01864 throw new RuntimeException("invalid toType from double: " + toType);
01865 }
01866
01867 public void caseFloatType(FloatType ty)
01868 {
01869 if(toType.equals(IntType.v()))
01870 emit("f2i", 0);
01871 else if(toType.equals(LongType.v()))
01872 emit("f2l", 1);
01873 else if(toType.equals(DoubleType.v()))
01874 emit("f2d", 1);
01875 else
01876 throw new RuntimeException("invalid toType from float: " + toType);
01877 }
01878
01879 public void caseIntType(IntType ty)
01880 {
01881 emitIntToTypeCast();
01882 }
01883
01884 public void caseBooleanType(BooleanType ty)
01885 {
01886 emitIntToTypeCast();
01887 }
01888
01889 public void caseByteType(ByteType ty)
01890 {
01891 emitIntToTypeCast();
01892 }
01893
01894 public void caseCharType(CharType ty)
01895 {
01896 emitIntToTypeCast();
01897 }
01898
01899 public void caseShortType(ShortType ty)
01900 {
01901 emitIntToTypeCast();
01902 }
01903
01904 private void emitIntToTypeCast()
01905 {
01906 if(toType.equals(ByteType.v()))
01907 emit("i2b", 0);
01908 else if(toType.equals(CharType.v()))
01909 emit("i2c", 0);
01910 else if(toType.equals(ShortType.v()))
01911 emit("i2s", 0);
01912 else if(toType.equals(FloatType.v()))
01913 emit("i2f", 0);
01914 else if(toType.equals(LongType.v()))
01915 emit("i2l", 1);
01916 else if(toType.equals(DoubleType.v()))
01917 emit("i2d", 1);
01918 else if(toType.equals(IntType.v()))
01919 ;
01920 else
01921 throw new RuntimeException("invalid toType from int: " + toType +
01922 " " + v.toString());
01923 }
01924
01925 public void caseLongType(LongType ty)
01926 {
01927 if(toType.equals(IntType.v()))
01928 emit("l2i", -1);
01929 else if(toType.equals(FloatType.v()))
01930 emit("l2f", -1);
01931 else if(toType.equals(DoubleType.v()))
01932 emit("l2d", 0);
01933 else if(toType.equals(ByteType.v()))
01934 { emit("l2i", -1); emitIntToTypeCast(); }
01935 else if(toType.equals(ShortType.v()))
01936 { emit("l2i", -1); emitIntToTypeCast(); }
01937 else if(toType.equals(CharType.v()))
01938 { emit("l2i", -1); emitIntToTypeCast(); }
01939 else if(toType.equals(BooleanType.v()))
01940 { emit("l2i", -1); emitIntToTypeCast(); }
01941 else
01942 throw new RuntimeException("invalid toType from long: " + toType);
01943 }
01944 });
01945 }
01946 }
01947
01948 public void caseCmpExpr(CmpExpr v)
01949 {
01950 emitValue(v.getOp1());
01951 emitValue(v.getOp2());
01952 emit("lcmp", -3);
01953 }
01954
01955 public void caseCmpgExpr(CmpgExpr v)
01956 {
01957 emitValue(v.getOp1());
01958 emitValue(v.getOp2());
01959
01960 if(v.getOp1().getType().equals(FloatType.v()))
01961 emit("fcmpg", -1);
01962 else
01963 emit("dcmpg", -3);
01964 }
01965
01966 public void caseCmplExpr(CmplExpr v)
01967 {
01968 emitValue(v.getOp1());
01969 emitValue(v.getOp2());
01970
01971 if(v.getOp1().getType().equals(FloatType.v()))
01972 emit("fcmpl", -1);
01973 else
01974 emit("dcmpl", -3);
01975 }
01976
01977 public void defaultCase(Value v)
01978 {
01979 throw new RuntimeException("Can't load value: " + v);
01980 }
01981
01982 public void caseDivExpr(DivExpr v)
01983 {
01984 emitValue(v.getOp1());
01985 emitValue(v.getOp2());
01986
01987 v.getType().apply(new TypeSwitch()
01988 {
01989 private void handleIntCase()
01990 {
01991 emit("idiv", -1);
01992 }
01993
01994 public void caseIntType(IntType t) { handleIntCase(); }
01995 public void caseBooleanType(BooleanType t) { handleIntCase(); }
01996 public void caseShortType(ShortType t) { handleIntCase(); }
01997 public void caseCharType(CharType t) { handleIntCase(); }
01998 public void caseByteType(ByteType t) { handleIntCase(); }
01999
02000 public void caseLongType(LongType t)
02001 {
02002 emit("ldiv", -2);
02003 }
02004
02005 public void caseDoubleType(DoubleType t)
02006 {
02007 emit("ddiv", -2);
02008 }
02009
02010 public void caseFloatType(FloatType t)
02011 {
02012 emit("fdiv", -1);
02013 }
02014
02015 public void defaultCase(Type t)
02016 {
02017 throw new RuntimeException("Invalid argument type for div");
02018 }
02019 });
02020
02021 }
02022
02023 public void caseDoubleConstant(DoubleConstant v)
02024 {
02025 if(v.value == 0)
02026 emit("dconst_0", 2);
02027 else if(v.value == 1)
02028 emit("dconst_1", 2);
02029 else {
02030 String s = v.toString();
02031
02032 if(s.equals("Infinity"))
02033 s="+DoubleInfinity";
02034 if(s.equals("-Infinity"))
02035 s="-DoubleInfinity";
02036
02037 emit("ldc2_w " + s, 2);
02038 }
02039 }
02040
02041 public void caseFloatConstant(FloatConstant v)
02042 {
02043 if(v.value == 0)
02044 emit("fconst_0", 1);
02045 else if(v.value == 1)
02046 emit("fconst_1", 1);
02047 else if(v.value == 2)
02048 emit("fconst_2", 1);
02049 else {
02050 String s = v.toString();
02051
02052 if(s.equals("Infinity"))
02053 s="+FloatInfinity";
02054 if(s.equals("-Infinity"))
02055 s="-FloatInfinity";
02056
02057 emit("ldc " + s, 1);
02058 }
02059 }
02060
02061
02062 public void caseInstanceFieldRef(InstanceFieldRef v)
02063 {
02064 emitValue(v.getBase());
02065
02066 emit("getfield " + slashify(v.getField().getDeclaringClass().getName()) + "/" +
02067 v.getField().getName() + " " + jasminDescriptorOf(v.getField().getType()),
02068 -1 + sizeOfType(v.getField().getType()));
02069 }
02070
02071 public void caseInstanceOfExpr(InstanceOfExpr v)
02072 {
02073 emitValue(v.getOp());
02074
02075 emit("instanceof " + slashify(v.getCheckType().toString()), 0);
02076 }
02077
02078 public void caseIntConstant(IntConstant v)
02079 {
02080 if(v.value == -1)
02081 emit("iconst_m1", 1);
02082 else if(v.value >= 0 && v.value <= 5)
02083 emit("iconst_" + v.value, 1);
02084 else if(v.value >= Byte.MIN_VALUE && v.value <= Byte.MAX_VALUE)
02085 emit("bipush " + v.value, 1);
02086 else if(v.value >= Short.MIN_VALUE && v.value <= Short.MAX_VALUE)
02087 emit("sipush " + v.value, 1);
02088 else
02089 emit("ldc " + v.toString(), 1);
02090 }
02091
02092 public void caseInterfaceInvokeExpr(InterfaceInvokeExpr v)
02093 {
02094 SootMethod m = v.getMethod();
02095
02096 emitValue(v.getBase());
02097
02098 for(int i = 0; i < m.getParameterCount(); i++)
02099 emitValue(v.getArg(i));
02100
02101 emit("invokeinterface " + slashify(m.getDeclaringClass().getName()) + "/" +
02102 m.getName() + jasminDescriptorOf(m) + " " + (argCountOf(m) + 1),
02103 -(argCountOf(m) + 1) + sizeOfType(m.getReturnType()));
02104 }
02105
02106 public void caseLengthExpr(LengthExpr v)
02107 {
02108 emitValue(v.getOp());
02109 emit("arraylength", 0);
02110 }
02111
02112 public void caseLocal(Local v)
02113 {
02114 emitLocal(v);
02115 }
02116
02117 public void caseLongConstant(LongConstant v)
02118 {
02119 if(v.value == 0)
02120 emit("lconst_0", 2);
02121 else if(v.value == 1)
02122 emit("lconst_1", 2);
02123 else
02124 emit("ldc2_w " + v.toString(), 2);
02125 }
02126
02127
02128 public void caseMulExpr(MulExpr v)
02129 {
02130 emitValue(v.getOp1());
02131 emitValue(v.getOp2());
02132
02133 v.getType().apply(new TypeSwitch()
02134 {
02135 private void handleIntCase()
02136 {
02137 emit("imul", -1);
02138 }
02139
02140 public void caseIntType(IntType t) { handleIntCase(); }
02141 public void caseBooleanType(BooleanType t) { handleIntCase(); }
02142 public void caseShortType(ShortType t) { handleIntCase(); }
02143 public void caseCharType(CharType t) { handleIntCase(); }
02144 public void caseByteType(ByteType t) { handleIntCase(); }
02145
02146 public void caseLongType(LongType t)
02147 {
02148 emit("lmul", -2);
02149 }
02150
02151 public void caseDoubleType(DoubleType t)
02152 {
02153 emit("dmul", -2);
02154 }
02155
02156 public void caseFloatType(FloatType t)
02157 {
02158 emit("fmul", -1);
02159 }
02160
02161 public void defaultCase(Type t)
02162 {
02163 throw new RuntimeException("Invalid argument type for mul");
02164 }
02165 });
02166 }
02167
02168 public void caseLtExpr(LtExpr v)
02169 {
02170 emitValue(v.getOp1());
02171 emitValue(v.getOp2());
02172
02173 v.getOp1().getType().apply(new TypeSwitch()
02174 {
02175 public void caseDoubleType(DoubleType t)
02176 {
02177 emit("dcmpg", -3);
02178 emitBooleanBranch("iflt");
02179 }
02180
02181 public void caseFloatType(FloatType t)
02182 {
02183 emit("fcmpg", -1);
02184 emitBooleanBranch("iflt");
02185 }
02186
02187 private void handleIntCase()
02188 {
02189 emit("if_icmplt", -2);
02190 }
02191
02192
02193 public void caseIntType(IntType t) { handleIntCase(); }
02194 public void caseBooleanType(BooleanType t) { handleIntCase(); }
02195 public void caseShortType(ShortType t) { handleIntCase(); }
02196 public void caseCharType(CharType t) { handleIntCase(); }
02197 public void caseByteType(ByteType t) { handleIntCase(); }
02198
02199 public void caseLongType(LongType t)
02200 {
02201 emit("lcmp", -3);
02202 emitBooleanBranch("iflt");
02203 }
02204
02205 public void defaultCase(Type t)
02206 {
02207 throw new RuntimeException("invalid type");
02208 }
02209 });
02210 }
02211
02212 public void caseLeExpr(LeExpr v)
02213 {
02214 emitValue(v.getOp1());
02215 emitValue(v.getOp2());
02216
02217 v.getOp1().getType().apply(new TypeSwitch()
02218 {
02219 public void caseDoubleType(DoubleType t)
02220 {
02221 emit("dcmpg", -3);
02222 emitBooleanBranch("ifle");
02223 }
02224
02225 public void caseFloatType(FloatType t)
02226 {
02227 emit("fcmpg", -1);
02228 emitBooleanBranch("ifle");
02229 }
02230
02231 private void handleIntCase()
02232 {
02233 emit("if_icmple", -2);
02234 }
02235
02236 public void caseIntType(IntType t) { handleIntCase(); }
02237 public void caseBooleanType(BooleanType t) { handleIntCase(); }
02238 public void caseShortType(ShortType t) { handleIntCase(); }
02239 public void caseCharType(CharType t) { handleIntCase(); }
02240 public void caseByteType(ByteType t) { handleIntCase(); }
02241
02242 public void caseLongType(LongType t)
02243 {
02244 emit("lcmp", -3);
02245 emitBooleanBranch("ifle");
02246 }
02247
02248 public void defaultCase(Type t)
02249 {
02250 throw new RuntimeException("invalid type");
02251 }
02252 });
02253 }
02254
02255 public void caseGtExpr(GtExpr v)
02256 {
02257 emitValue(v.getOp1());
02258 emitValue(v.getOp2());
02259
02260 v.getOp1().getType().apply(new TypeSwitch()
02261 {
02262 public void caseDoubleType(DoubleType t)
02263 {
02264 emit("dcmpg", -3);
02265 emitBooleanBranch("ifgt");
02266 }
02267
02268 public void caseFloatType(FloatType t)
02269 {
02270 emit("fcmpg", -1);
02271 emitBooleanBranch("ifgt");
02272 }
02273
02274 private void handleIntCase()
02275 {
02276 emit("if_icmpgt", -2);
02277 }
02278
02279 public void caseIntType(IntType t) { handleIntCase(); }
02280 public void caseBooleanType(BooleanType t) { handleIntCase(); }
02281 public void caseShortType(ShortType t) { handleIntCase(); }
02282 public void caseCharType(CharType t) { handleIntCase(); }
02283 public void caseByteType(ByteType t) { handleIntCase(); }
02284
02285 public void caseLongType(LongType t)
02286 {
02287 emit("lcmp", -3);
02288 emitBooleanBranch("ifgt");
02289 }
02290
02291 public void defaultCase(Type t)
02292 {
02293 throw new RuntimeException("invalid type");
02294 }
02295 });
02296 }
02297
02298 public void caseGeExpr(GeExpr v)
02299 {
02300 emitValue(v.getOp1());
02301 emitValue(v.getOp2());
02302
02303 v.getOp1().getType().apply(new TypeSwitch()
02304 {
02305 public void caseDoubleType(DoubleType t)
02306 {
02307 emit("dcmpg", -3);
02308 emitBooleanBranch("ifge");
02309 }
02310
02311 public void caseFloatType(FloatType t)
02312 {
02313 emit("fcmpg", -1);
02314 emitBooleanBranch("ifge");
02315 }
02316
02317 private void handleIntCase()
02318 {
02319 emit("if_icmpge", -2);
02320 }
02321
02322 public void caseIntType(IntType t) { handleIntCase(); }
02323 public void caseBooleanType(BooleanType t) { handleIntCase(); }
02324 public void caseShortType(ShortType t) { handleIntCase(); }
02325 public void caseCharType(CharType t) { handleIntCase(); }
02326 public void caseByteType(ByteType t) { handleIntCase(); }
02327
02328 public void caseLongType(LongType t)
02329 {
02330 emit("lcmp", -3);
02331 emitBooleanBranch("ifge");
02332 }
02333
02334 public void defaultCase(Type t)
02335 {
02336 throw new RuntimeException("invalid type");
02337 }
02338 });
02339 }
02340
02341 public void caseNeExpr(NeExpr v)
02342 {
02343 emitValue(v.getOp1());
02344 emitValue(v.getOp2());
02345
02346 v.getOp1().getType().apply(new TypeSwitch()
02347 {
02348 public void caseDoubleType(DoubleType t)
02349 {
02350 emit("dcmpg", -3);
02351 emit("iconst_0", 1);
02352 emitBooleanBranch("if_icmpne");
02353 }
02354
02355 public void caseFloatType(FloatType t)
02356 {
02357 emit("fcmpg", -1);
02358 emit("iconst_0", 1);
02359 emitBooleanBranch("if_icmpne");
02360 }
02361
02362 private void handleIntCase()
02363 {
02364 emit("if_icmpne", -2);
02365 }
02366
02367 public void caseIntType(IntType t) { handleIntCase(); }
02368 public void caseBooleanType(BooleanType t) { handleIntCase(); }
02369 public void caseShortType(ShortType t) { handleIntCase(); }
02370 public void caseCharType(CharType t) { handleIntCase(); }
02371 public void caseByteType(ByteType t) { handleIntCase(); }
02372
02373 public void caseLongType(LongType t)
02374 {
02375 emit("lcmp", -3);
02376 emit("iconst_0", 1);
02377 emitBooleanBranch("if_icmpne");
02378 }
02379
02380 public void caseArrayType(ArrayType t)
02381 {
02382 emitBooleanBranch("if_acmpne");
02383 }
02384
02385 public void caseRefType(RefType t)
02386 {
02387 emitBooleanBranch("if_acmpne");
02388 }
02389
02390 public void defaultCase(Type t)
02391 {
02392 throw new RuntimeException("invalid type");
02393 }
02394 });
02395 }
02396
02397 public void caseEqExpr(EqExpr v)
02398 {
02399 emitValue(v.getOp1());
02400 emitValue(v.getOp2());
02401
02402 v.getOp1().getType().apply(new TypeSwitch()
02403 {
02404 public void caseDoubleType(DoubleType t)
02405 {
02406 emit("dcmpg", -3);
02407 emit("iconst_0", 1);
02408 emitBooleanBranch("if_icmpeq");
02409 }
02410
02411 public void caseFloatType(FloatType t)
02412 {
02413 emit("fcmpg", -3);
02414 emit("iconst_0", 1);
02415 emitBooleanBranch("if_icmpeq");
02416 }
02417
02418 private void handleIntCase()
02419 {
02420 emit("if_icmpeq", -2);
02421 }
02422
02423 public void caseIntType(IntType t) { handleIntCase(); }
02424 public void caseBooleanType(BooleanType t) { handleIntCase(); }
02425 public void caseShortType(ShortType t) { handleIntCase(); }
02426 public void caseCharType(CharType t) { handleIntCase(); }
02427 public void caseByteType(ByteType t) { handleIntCase(); }
02428
02429 public void caseLongType(LongType t)
02430 {
02431 emit("lcmp", -3);
02432 emit("iconst_0", 1);
02433 emitBooleanBranch("if_icmpeq");
02434 }
02435
02436 public void caseArrayType(ArrayType t)
02437 {
02438 emitBooleanBranch("if_acmpeq");
02439 }
02440
02441 public void casbeRefType(RefType t)
02442 {
02443 emitBooleanBranch("if_acmpeq");
02444 }
02445
02446 public void defaultCase(Type t)
02447 {
02448 throw new RuntimeException("invalid type");
02449 }
02450 });
02451 }
02452
02453 public void caseNegExpr(NegExpr v)
02454 {
02455 emitValue(v.getOp());
02456
02457 v.getType().apply(new TypeSwitch()
02458 {
02459 private void handleIntCase()
02460 {
02461 emit("ineg", 0);
02462 }
02463
02464 public void caseIntType(IntType t) { handleIntCase(); }
02465 public void caseBooleanType(BooleanType t) { handleIntCase(); }
02466 public void caseShortType(ShortType t) { handleIntCase(); }
02467 public void caseCharType(CharType t) { handleIntCase(); }
02468 public void caseByteType(ByteType t) { handleIntCase(); }
02469
02470 public void caseLongType(LongType t)
02471 {
02472 emit("lneg", 0);
02473 }
02474
02475 public void caseDoubleType(DoubleType t)
02476 {
02477 emit("dneg", 0);
02478 }
02479
02480 public void caseFloatType(FloatType t)
02481 {
02482 emit("fneg", 0);
02483 }
02484
02485 public void defaultCase(Type t)
02486 {
02487 throw new RuntimeException("Invalid argument type for neg");
02488 }
02489 });
02490
02491 }
02492
02493 public void caseNewArrayExpr(NewArrayExpr v)
02494 {
02495 Value size = v.getSize();
02496
02497 emitValue(size);
02498
02499 if(v.getBaseType() instanceof RefType)
02500 emit("anewarray " + slashify(v.getBaseType().toString()), 0);
02501 else if(v.getBaseType() instanceof ArrayType)
02502 emit("anewarray " + jasminDescriptorOf(v.getBaseType()), 0);
02503 else
02504 emit("newarray " + v.getBaseType().toString(), 0);
02505 }
02506
02507 public void caseNewMultiArrayExpr(NewMultiArrayExpr v)
02508 {
02509 List sizes = v.getSizes();
02510
02511 for(int i = 0; i < sizes.size(); i++)
02512 emitValue((Value) sizes.get(i));
02513
02514 emit("multianewarray " + jasminDescriptorOf(v.getBaseType()) + " " + sizes.size(), -sizes.size() + 1);
02515 }
02516
02517 public void caseNewExpr(NewExpr v)
02518 {
02519 emit("new " + slashify(v.getBaseType().toString()), 1);
02520 }
02521
02522 public void caseNewInvokeExpr(NewInvokeExpr v)
02523 {
02524 emit("new " + slashify(v.getBaseType().toString()), 1);
02525 emit("dup", 1);
02526
02527 SootMethod m = v.getMethod();
02528
02529
02530
02531
02532 for(int i = 0; i < m.getParameterCount(); i++)
02533 emitValue(v.getArg(i));
02534
02535 emit("invokespecial " + slashify(m.getDeclaringClass().getName()) + "/" +
02536 m.getName() + jasminDescriptorOf(m),
02537 -(argCountOf(m) + 1) + sizeOfType(m.getReturnType()));
02538 }
02539
02540 public void caseNullConstant(NullConstant v)
02541 {
02542 emit("aconst_null", 1);
02543 }
02544
02545 public void caseOrExpr(OrExpr v)
02546 {
02547 emitValue(v.getOp1());
02548 emitValue(v.getOp2());
02549
02550 v.getType().apply(new TypeSwitch()
02551 {
02552 private void handleIntCase()
02553 {
02554 emit("ior", -1);
02555 }
02556
02557 public void caseIntType(IntType t) { handleIntCase(); }
02558 public void caseBooleanType(BooleanType t) { handleIntCase(); }
02559 public void caseShortType(ShortType t) { handleIntCase(); }
02560 public void caseCharType(CharType t) { handleIntCase(); }
02561 public void caseByteType(ByteType t) { handleIntCase(); }
02562
02563 public void caseLongType(LongType t)
02564 {
02565 emit("lor", -2);
02566 }
02567
02568 public void defaultCase(Type t)
02569 {
02570 throw new RuntimeException("Invalid argument type for or");
02571 }
02572 });
02573 }
02574
02575 public void caseRemExpr(RemExpr v)
02576 {
02577 emitValue(v.getOp1());
02578 emitValue(v.getOp2());
02579
02580 v.getType().apply(new TypeSwitch()
02581 {
02582 private void handleIntCase()
02583 {
02584 emit("irem", -1);
02585 }
02586
02587 public void caseIntType(IntType t) { handleIntCase(); }
02588 public void caseBooleanType(BooleanType t) { handleIntCase(); }
02589 public void caseShortType(ShortType t) { handleIntCase(); }
02590 public void caseCharType(CharType t) { handleIntCase(); }
02591 public void caseByteType(ByteType t) { handleIntCase(); }
02592
02593 public void caseLongType(LongType t)
02594 {
02595 emit("lrem", -2);
02596 }
02597
02598 public void caseDoubleType(DoubleType t)
02599 {
02600 emit("drem", -2);
02601 }
02602
02603 public void caseFloatType(FloatType t)
02604 {
02605 emit("frem", -1);
02606 }
02607
02608 public void defaultCase(Type t)
02609 {
02610 throw new RuntimeException("Invalid argument type for rem");
02611 }
02612 });
02613 }
02614
02615 public void caseShlExpr(ShlExpr v)
02616 {
02617 emitValue(v.getOp1());
02618 emitValue(v.getOp2());
02619
02620 v.getType().apply(new TypeSwitch()
02621 {
02622 private void handleIntCase()
02623 {
02624 emit("ishl", -1);
02625 }
02626
02627 public void caseIntType(IntType t) { handleIntCase(); }
02628 public void caseBooleanType(BooleanType t) { handleIntCase(); }
02629 public void caseShortType(ShortType t) { handleIntCase(); }
02630 public void caseCharType(CharType t) { handleIntCase(); }
02631 public void caseByteType(ByteType t) { handleIntCase(); }
02632
02633 public void caseLongType(LongType t)
02634 {
02635 emit("lshl", -1);
02636 }
02637
02638 public void defaultCase(Type t)
02639 {
02640 throw new RuntimeException("Invalid argument type for shl");
02641 }
02642 });
02643 }
02644
02645 public void caseShrExpr(ShrExpr v)
02646 {
02647 emitValue(v.getOp1());
02648 emitValue(v.getOp2());
02649
02650 v.getType().apply(new TypeSwitch()
02651 {
02652 private void handleIntCase()
02653 {
02654 emit("ishr", -1);
02655 }
02656
02657 public void caseIntType(IntType t) { handleIntCase(); }
02658 public void caseBooleanType(BooleanType t) { handleIntCase(); }
02659 public void caseShortType(ShortType t) { handleIntCase(); }
02660 public void caseCharType(CharType t) { handleIntCase(); }
02661 public void caseByteType(ByteType t) { handleIntCase(); }
02662
02663 public void caseLongType(LongType t)
02664 {
02665 emit("lshr", -1);
02666 }
02667
02668 public void defaultCase(Type t)
02669 {
02670 throw new RuntimeException("Invalid argument type for shr");
02671 }
02672 });
02673 }
02674
02675 public void caseSpecialInvokeExpr(SpecialInvokeExpr v)
02676 {
02677 SootMethod m = v.getMethod();
02678
02679 emitValue(v.getBase());
02680
02681 for(int i = 0; i < m.getParameterCount(); i++)
02682 emitValue(v.getArg(i));
02683
02684 emit("invokespecial " + slashify(m.getDeclaringClass().getName()) + "/" +
02685 m.getName() + jasminDescriptorOf(m),
02686 -(argCountOf(m) + 1) + sizeOfType(m.getReturnType()));
02687 }
02688
02689 public void caseStaticInvokeExpr(StaticInvokeExpr v)
02690 {
02691 SootMethod m = v.getMethod();
02692
02693 for(int i = 0; i < m.getParameterCount(); i++)
02694 emitValue(v.getArg(i));
02695
02696 emit("invokestatic " + slashify(m.getDeclaringClass().getName()) + "/" +
02697 m.getName() + jasminDescriptorOf(m),
02698 -(argCountOf(m)) + sizeOfType(m.getReturnType()));
02699 }
02700
02701 public void caseStaticFieldRef(StaticFieldRef v)
02702 {
02703 emit("getstatic " + slashify(v.getField().getDeclaringClass().getName()) + "/" +
02704 v.getField().getName() + " " + jasminDescriptorOf(v.getField().getType()),
02705 sizeOfType(v.getField().getType()));
02706 }
02707
02708 public void caseStringConstant(StringConstant v)
02709 {
02710 StringBuffer src = new StringBuffer(v.value);
02711 StringBuffer dest = new StringBuffer();
02712
02713 for(int i = 0; i < src.length(); i++)
02714 {
02715 if(src.charAt(i) == '\"')
02716 dest.append("\\\"");
02717 else if(src.charAt(i) == '\'')
02718 dest.append("\\\'");
02719 else if(src.charAt(i) == '\\')
02720 dest.append("\\\\");
02721 else
02722 dest.append(src.charAt(i));
02723 }
02724
02725 emit("ldc " + '"' + dest.toString() + '"', 1);
02726 }
02727
02728 public void caseSubExpr(SubExpr v)
02729 {
02730 emitValue(v.getOp1());
02731 emitValue(v.getOp2());
02732
02733 v.getType().apply(new TypeSwitch()
02734 {
02735 private void handleIntCase()
02736 {
02737 emit("isub", -1);
02738 }
02739
02740 public void caseIntType(IntType t) { handleIntCase(); }
02741 public void caseBooleanType(BooleanType t) { handleIntCase(); }
02742 public void caseShortType(ShortType t) { handleIntCase(); }
02743 public void caseCharType(CharType t) { handleIntCase(); }
02744 public void caseByteType(ByteType t) { handleIntCase(); }
02745
02746 public void caseLongType(LongType t)
02747 {
02748 emit("lsub", -2);
02749 }
02750
02751 public void caseDoubleType(DoubleType t)
02752 {
02753 emit("dsub", -2);
02754 }
02755
02756 public void caseFloatType(FloatType t)
02757 {
02758 emit("fsub", -1);
02759 }
02760
02761 public void defaultCase(Type t)
02762 {
02763 throw new RuntimeException("Invalid argument type for sub");
02764 }
02765 });
02766
02767 }
02768
02769 public void caseUshrExpr(UshrExpr v)
02770 {
02771 emitValue(v.getOp1());
02772 emitValue(v.getOp2());
02773
02774 v.getType().apply(new TypeSwitch()
02775 {
02776 private void handleIntCase()
02777 {
02778 emit("iushr", -1);
02779 }
02780
02781 public void caseIntType(IntType t) { handleIntCase(); }
02782 public void caseBooleanType(BooleanType t) { handleIntCase(); }
02783 public void caseShortType(ShortType t) { handleIntCase(); }
02784 public void caseCharType(CharType t) { handleIntCase(); }
02785 public void caseByteType(ByteType t) { handleIntCase(); }
02786
02787 public void caseLongType(LongType t)
02788 {
02789 emit("lushr", -1);
02790 }
02791
02792 public void defaultCase(Type t)
02793 {
02794 throw new RuntimeException("Invalid argument type for ushr");
02795 }
02796 });
02797 }
02798
02799 public void caseVirtualInvokeExpr(VirtualInvokeExpr v)
02800 {
02801 SootMethod m = v.getMethod();
02802
02803 emitValue(v.getBase());
02804
02805 for(int i = 0; i < m.getParameterCount(); i++)
02806 emitValue(v.getArg(i));
02807
02808 emit("invokevirtual " + slashify(m.getDeclaringClass().getName()) + "/" +
02809 m.getName() + jasminDescriptorOf(m),
02810 -(argCountOf(m) + 1) + sizeOfType(m.getReturnType()));
02811 }
02812
02813 public void caseXorExpr(XorExpr v)
02814 {
02815 emitValue(v.getOp1());
02816 emitValue(v.getOp2());
02817
02818 v.getType().apply(new TypeSwitch()
02819 {
02820 private void handleIntCase()
02821 {
02822 emit ("ixor", -1);
02823 }
02824
02825 public void caseIntType(IntType t) { handleIntCase(); }
02826 public void caseBooleanType(BooleanType t) { handleIntCase(); }
02827 public void caseShortType(ShortType t) { handleIntCase(); }
02828 public void caseCharType(CharType t) { handleIntCase(); }
02829 public void caseByteType(ByteType t) { handleIntCase(); }
02830
02831 public void caseLongType(LongType t)
02832 {
02833 emit("lxor", -2);
02834 }
02835
02836 public void defaultCase(Type t)
02837 {
02838 throw new RuntimeException("Invalid argument type for xor");
02839 }
02840 });
02841 }
02842 });
02843 }
02844 String jasminDescriptorOf(SootMethod m)
02845 {
02846 StringBuffer buffer = new StringBuffer();
02847
02848 buffer.append("(");
02849
02850
02851 {
02852 Iterator typeIt = m.getParameterTypes().iterator();
02853
02854 while(typeIt.hasNext())
02855 {
02856 Type t = (Type) typeIt.next();
02857
02858 buffer.append(jasminDescriptorOf(t));
02859 }
02860 }
02861
02862 buffer.append(")");
02863
02864 buffer.append(jasminDescriptorOf(m.getReturnType()));
02865
02866 return buffer.toString();
02867 }
02868 String jasminDescriptorOf(Type type)
02869 {
02870 TypeSwitch sw;
02871
02872 type.apply(sw = new TypeSwitch()
02873 {
02874 public void caseBooleanType(BooleanType t)
02875 {
02876 setResult("Z");
02877 }
02878
02879 public void caseByteType(ByteType t)
02880 {
02881 setResult("B");
02882 }
02883
02884 public void caseCharType(CharType t)
02885 {
02886 setResult("C");
02887 }
02888
02889 public void caseDoubleType(DoubleType t)
02890 {
02891 setResult("D");
02892 }
02893
02894 public void caseFloatType(FloatType t)
02895 {
02896 setResult("F");
02897 }
02898
02899 public void caseIntType(IntType t)
02900 {
02901 setResult("I");
02902 }
02903
02904 public void caseLongType(LongType t)
02905 {
02906 setResult("J");
02907 }
02908
02909 public void caseShortType(ShortType t)
02910 {
02911 setResult("S");
02912 }
02913
02914 public void defaultCase(Type t)
02915 {
02916 throw new RuntimeException("Invalid type: " + t);
02917 }
02918
02919 public void caseArrayType(ArrayType t)
02920 {
02921 StringBuffer buffer = new StringBuffer();
02922
02923 for(int i = 0; i < t.numDimensions; i++)
02924 buffer.append("[");
02925
02926 setResult(buffer.toString() + jasminDescriptorOf(t.baseType));
02927 }
02928
02929 public void caseRefType(RefType t)
02930 {
02931 setResult("L" + t.className.replace('.', '/') + ";");
02932 }
02933
02934 public void caseVoidType(VoidType t)
02935 {
02936 setResult("V");
02937 }
02938 });
02939
02940 return (String) sw.getResult();
02941
02942 }
02943 void modifyStackHeight(int stackChange)
02944 {
02945 currentStackHeight += stackChange;
02946
02947 if(currentStackHeight < 0)
02948 throw new RuntimeException("Stack height is negative!");
02949
02950 if(currentStackHeight > maxStackHeight)
02951 maxStackHeight = currentStackHeight;
02952 }
02953 void okayEmit(String s)
02954 {
02955 if(isEmittingMethodCode && !s.endsWith(":"))
02956 code.add(" " + s);
02957 else
02958 code.add(s);
02959
02960
02961 }
02962 public void print(PrintWriter out)
02963 {
02964 Iterator it = code.iterator();
02965
02966 while(it.hasNext())
02967 out.println(it.next());
02968 }
02969 int sizeOfType(Type t)
02970 {
02971 if(t instanceof DoubleType || t instanceof LongType)
02972 return 2;
02973 else if(t instanceof VoidType)
02974 return 0;
02975 else
02976 return 1;
02977 }
02978 String slashify(String s)
02979 {
02980 return s.replace('.', '/');
02981 }
02982 }