0001: /*
0002: * FindBugs - Find bugs in Java programs
0003: * Copyright (C) 2004 Dave Brosius <dbrosius@users.sourceforge.net>
0004: * Copyright (C) 2003-2006 University of Maryland
0005: *
0006: * This library is free software; you can redistribute it and/or
0007: * modify it under the terms of the GNU Lesser General Public
0008: * License as published by the Free Software Foundation; either
0009: * version 2.1 of the License, or (at your option) any later version.
0010: *
0011: * This library is distributed in the hope that it will be useful,
0012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014: * Lesser General Public License for more details.
0015: *
0016: * You should have received a copy of the GNU Lesser General Public
0017: * License along with this library; if not, write to the Free Software
0018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0019: */
0020:
0021: package edu.umd.cs.findbugs;
0022:
0023: import java.util.ArrayList;
0024: import java.util.BitSet;
0025: import java.util.HashMap;
0026: import java.util.List;
0027: import java.util.Map;
0028:
0029: import org.apache.bcel.Repository;
0030: import org.apache.bcel.classfile.Code;
0031: import org.apache.bcel.classfile.CodeException;
0032: import org.apache.bcel.classfile.Constant;
0033: import org.apache.bcel.classfile.ConstantClass;
0034: import org.apache.bcel.classfile.ConstantDouble;
0035: import org.apache.bcel.classfile.ConstantFloat;
0036: import org.apache.bcel.classfile.ConstantInteger;
0037: import org.apache.bcel.classfile.ConstantLong;
0038: import org.apache.bcel.classfile.ConstantString;
0039: import org.apache.bcel.classfile.ConstantUtf8;
0040: import org.apache.bcel.classfile.JavaClass;
0041: import org.apache.bcel.classfile.LocalVariable;
0042: import org.apache.bcel.classfile.LocalVariableTable;
0043: import org.apache.bcel.classfile.Method;
0044: import org.apache.bcel.generic.BasicType;
0045: import org.apache.bcel.generic.Type;
0046:
0047: import edu.umd.cs.findbugs.annotations.CheckForNull;
0048: import edu.umd.cs.findbugs.ba.AnalysisContext;
0049: import edu.umd.cs.findbugs.ba.AnalysisFeatures;
0050: import edu.umd.cs.findbugs.ba.ClassMember;
0051: import edu.umd.cs.findbugs.ba.XFactory;
0052: import edu.umd.cs.findbugs.ba.XField;
0053: import edu.umd.cs.findbugs.ba.XMethod;
0054: import edu.umd.cs.findbugs.classfile.CheckedAnalysisException;
0055: import edu.umd.cs.findbugs.classfile.Global;
0056: import edu.umd.cs.findbugs.classfile.IAnalysisCache;
0057: import edu.umd.cs.findbugs.classfile.MethodDescriptor;
0058: import edu.umd.cs.findbugs.classfile.engine.bcel.AnalysisFactory;
0059: import edu.umd.cs.findbugs.internalAnnotations.SlashedClassName;
0060: import edu.umd.cs.findbugs.util.ClassName;
0061: import edu.umd.cs.findbugs.util.Util;
0062: import edu.umd.cs.findbugs.visitclass.Constants2;
0063: import edu.umd.cs.findbugs.visitclass.DismantleBytecode;
0064: import edu.umd.cs.findbugs.visitclass.LVTHelper;
0065: import edu.umd.cs.findbugs.visitclass.PreorderVisitor;
0066:
0067: /**
0068: * tracks the types and numbers of objects that are currently on the operand stack
0069: * throughout the execution of method. To use, a detector should instantiate one for
0070: * each method, and call <p>stack.sawOpcode(this,seen);</p> at the bottom of their sawOpcode method.
0071: * at any point you can then inspect the stack and see what the types of objects are on
0072: * the stack, including constant values if they were pushed. The types described are of
0073: * course, only the static types.
0074: * There are some outstanding opcodes that have yet to be implemented, I couldn't
0075: * find any code that actually generated these, so i didn't put them in because
0076: * I couldn't test them:
0077: * <ul>
0078: * <li>dup2_x2</li>
0079: * <li>jsr_w</li>
0080: * <li>wide</li>
0081: * </ul>
0082: */
0083: public class OpcodeStack implements Constants2 {
0084: private static final boolean DEBUG = SystemProperties
0085: .getBoolean("ocstack.debug");
0086: private static final boolean DEBUG2 = DEBUG;
0087: private List<Item> stack;
0088: private List<Item> lvValues;
0089: private List<Integer> lastUpdate;
0090: private boolean top;
0091:
0092: private boolean seenTransferOfControl = false;
0093:
0094: private boolean useIterativeAnalysis = AnalysisContext
0095: .currentAnalysisContext().getBoolProperty(
0096: AnalysisFeatures.INTERATIVE_OPCODE_STACK_ANALYSIS);
0097:
0098: public static class Item {
0099: public static final int SIGNED_BYTE = 1;
0100: public static final int RANDOM_INT = 2;
0101: public static final int LOW_8_BITS_CLEAR = 3;
0102: public static final int HASHCODE_INT = 4;
0103: public static final int INTEGER_SUM = 5;
0104: public static final int AVERAGE_COMPUTED_USING_DIVISION = 6;
0105: public static final int FLOAT_MATH = 7;
0106: public static final int RANDOM_INT_REMAINDER = 8;
0107: public static final int HASHCODE_INT_REMAINDER = 9;
0108: public static final int FILE_SEPARATOR_STRING = 10;
0109: public static final int MATH_ABS = 11;
0110: public static final int NON_NEGATIVE = 12;
0111: public static final int NASTY_FLOAT_MATH = 13;
0112: public static final int FILE_OPENED_IN_APPEND_MODE = 14;
0113:
0114: private static final int IS_INITIAL_PARAMETER_FLAG = 1;
0115: private static final int COULD_BE_ZERO_FLAG = 2;
0116: private static final int IS_NULL_FLAG = 4;
0117:
0118: public static final Object UNKNOWN = null;
0119: private int specialKind;
0120: private String signature;
0121: private Object constValue = UNKNOWN;
0122: private @CheckForNull
0123: ClassMember source;
0124: private int flags;
0125: // private boolean isNull = false;
0126: private int registerNumber = -1;
0127: // private boolean isInitialParameter = false;
0128: // private boolean couldBeZero = false;
0129: private Object userValue = null;
0130: private int fieldLoadedFromRegister = -1;
0131:
0132: public int getSize() {
0133: if (signature.equals("J") || signature.equals("D"))
0134: return 2;
0135: return 1;
0136: }
0137:
0138: public boolean isWide() {
0139: return getSize() == 2;
0140: }
0141:
0142: private static boolean equals(Object o1, Object o2) {
0143: if (o1 == o2)
0144: return true;
0145: if (o1 == null || o2 == null)
0146: return false;
0147: return o1.equals(o2);
0148: }
0149:
0150: @Override
0151: public int hashCode() {
0152: int r = 42 + specialKind;
0153: if (signature != null)
0154: r += signature.hashCode();
0155: r *= 31;
0156: if (constValue != null)
0157: r += constValue.hashCode();
0158: r *= 31;
0159: if (source != null)
0160: r += source.hashCode();
0161: r *= 31;
0162: r += flags;
0163: r *= 31;
0164: r += registerNumber;
0165: return r;
0166:
0167: }
0168:
0169: @Override
0170: public boolean equals(Object o) {
0171: if (!(o instanceof Item))
0172: return false;
0173: Item that = (Item) o;
0174:
0175: return equals(this .signature, that.signature)
0176: && equals(this .constValue, that.constValue)
0177: && equals(this .source, that.source)
0178: && this .specialKind == that.specialKind
0179: && this .registerNumber == that.registerNumber
0180: && this .flags == that.flags
0181: && this .userValue == that.userValue
0182: && this .fieldLoadedFromRegister == that.fieldLoadedFromRegister;
0183:
0184: }
0185:
0186: @Override
0187: public String toString() {
0188: StringBuffer buf = new StringBuffer("< ");
0189: buf.append(signature);
0190: switch (specialKind) {
0191: case SIGNED_BYTE:
0192: buf.append(", byte_array_load");
0193: break;
0194: case RANDOM_INT:
0195: buf.append(", random_int");
0196: break;
0197: case LOW_8_BITS_CLEAR:
0198: buf.append(", low8clear");
0199: break;
0200: case HASHCODE_INT:
0201: buf.append(", hashcode_int");
0202: break;
0203: case INTEGER_SUM:
0204: buf.append(", int_sum");
0205: break;
0206: case AVERAGE_COMPUTED_USING_DIVISION:
0207: buf.append(", averageComputingUsingDivision");
0208: break;
0209: case FLOAT_MATH:
0210: buf.append(", floatMath");
0211: break;
0212: case NASTY_FLOAT_MATH:
0213: buf.append(", nastyFloatMath");
0214: break;
0215: case HASHCODE_INT_REMAINDER:
0216: buf.append(", hashcode_int_rem");
0217: break;
0218: case RANDOM_INT_REMAINDER:
0219: buf.append(", random_int_rem");
0220: break;
0221: case FILE_SEPARATOR_STRING:
0222: buf.append(", file_separator_string");
0223: break;
0224: case MATH_ABS:
0225: buf.append(", Math.abs");
0226: break;
0227: case NON_NEGATIVE:
0228: buf.append(", non_negative");
0229: break;
0230: case FILE_OPENED_IN_APPEND_MODE:
0231: buf.append(", file opened in append mode");
0232: break;
0233:
0234: case 0:
0235: break;
0236: default:
0237: buf.append(", #" + specialKind);
0238: break;
0239:
0240: }
0241: if (constValue != UNKNOWN) {
0242: if (constValue instanceof String) {
0243: buf.append(", \"");
0244: buf.append(constValue);
0245: buf.append("\"");
0246: } else {
0247: buf.append(", ");
0248: buf.append(constValue);
0249: }
0250: }
0251: if (source instanceof XField) {
0252: buf.append(", ");
0253: if (fieldLoadedFromRegister != -1)
0254: buf.append(fieldLoadedFromRegister).append(':');
0255: buf.append(source);
0256: }
0257: if (source instanceof XMethod) {
0258: buf.append(", return value from ");
0259: buf.append(source);
0260: }
0261: if (isInitialParameter()) {
0262: buf.append(", IP");
0263: }
0264: if (isNull()) {
0265: buf.append(", isNull");
0266: }
0267:
0268: if (registerNumber != -1) {
0269: buf.append(", r");
0270: buf.append(registerNumber);
0271: }
0272: if (isCouldBeZero())
0273: buf.append(", cbz");
0274: buf.append(" >");
0275: return buf.toString();
0276: }
0277:
0278: public static Item merge(Item i1, Item i2) {
0279: if (i1 == null)
0280: return i2;
0281: if (i2 == null)
0282: return i1;
0283: if (i1.equals(i2))
0284: return i1;
0285: Item m = new Item();
0286: m.flags = i1.flags & i2.flags;
0287: m.setCouldBeZero(i1.isCouldBeZero() || i2.isCouldBeZero());
0288: if (equals(i1.signature, i2.signature))
0289: m.signature = i1.signature;
0290: if (equals(i1.constValue, i2.constValue))
0291: m.constValue = i1.constValue;
0292: if (equals(i1.source, i2.source)) {
0293: m.source = i1.source;
0294: }
0295:
0296: if (i1.registerNumber == i2.registerNumber)
0297: m.registerNumber = i1.registerNumber;
0298: if (i1.fieldLoadedFromRegister == i2.fieldLoadedFromRegister)
0299: m.fieldLoadedFromRegister = i1.fieldLoadedFromRegister;
0300:
0301: if (i1.specialKind == i2.specialKind)
0302: m.specialKind = i1.specialKind;
0303: else if (i1.specialKind == NASTY_FLOAT_MATH
0304: || i2.specialKind == NASTY_FLOAT_MATH)
0305: m.specialKind = NASTY_FLOAT_MATH;
0306: else if (i1.specialKind == FLOAT_MATH
0307: || i2.specialKind == FLOAT_MATH)
0308: m.specialKind = FLOAT_MATH;
0309: if (DEBUG)
0310: System.out.println("Merge " + i1 + " and " + i2
0311: + " gives " + m);
0312: return m;
0313: }
0314:
0315: public Item(String signature, int constValue) {
0316: this (signature, (Object) (Integer) constValue);
0317: }
0318:
0319: public Item(String signature) {
0320: this (signature, UNKNOWN);
0321: }
0322:
0323: public Item(Item it) {
0324: this .signature = it.signature;
0325: this .constValue = it.constValue;
0326: this .source = it.source;
0327: this .registerNumber = it.registerNumber;
0328: this .userValue = it.userValue;
0329: this .flags = it.flags;
0330: this .specialKind = it.specialKind;
0331: }
0332:
0333: public Item(Item it, int reg) {
0334: this (it);
0335: this .registerNumber = reg;
0336: }
0337:
0338: public Item(String signature, FieldAnnotation f) {
0339: this .signature = signature;
0340: if (f != null)
0341: source = XFactory.createXField(f);
0342: fieldLoadedFromRegister = -1;
0343: }
0344:
0345: public Item(String signature, FieldAnnotation f,
0346: int fieldLoadedFromRegister) {
0347: this .signature = signature;
0348: if (f != null)
0349: source = XFactory.createXField(f);
0350: this .fieldLoadedFromRegister = fieldLoadedFromRegister;
0351: }
0352:
0353: public int getFieldLoadedFromRegister() {
0354: return fieldLoadedFromRegister;
0355: }
0356:
0357: public Item(String signature, Object constantValue) {
0358: this .signature = signature;
0359: constValue = constantValue;
0360: if (constantValue instanceof Integer) {
0361: int value = (Integer) constantValue;
0362: if (value != 0 && (value & 0xff) == 0)
0363: specialKind = LOW_8_BITS_CLEAR;
0364: if (value == 0)
0365: setCouldBeZero(true);
0366:
0367: } else if (constantValue instanceof Long) {
0368: long value = (Long) constantValue;
0369: if (value != 0 && (value & 0xff) == 0)
0370: specialKind = LOW_8_BITS_CLEAR;
0371: if (value == 0)
0372: setCouldBeZero(true);
0373: }
0374:
0375: }
0376:
0377: public Item() {
0378: signature = "Ljava/lang/Object;";
0379: constValue = null;
0380: setNull(true);
0381: }
0382:
0383: /** Returns null for primitive and arrays */
0384: public @CheckForNull
0385: JavaClass getJavaClass() throws ClassNotFoundException {
0386: String baseSig;
0387: try {
0388:
0389: if (isPrimitive() || isArray())
0390: return null;
0391:
0392: baseSig = signature;
0393:
0394: if (baseSig.length() == 0)
0395: return null;
0396: baseSig = baseSig.substring(1, baseSig.length() - 1);
0397: baseSig = baseSig.replace('/', '.');
0398: return Repository.lookupClass(baseSig);
0399: } catch (RuntimeException e) {
0400: e.printStackTrace();
0401: throw e;
0402: }
0403: }
0404:
0405: public boolean isArray() {
0406: return signature.startsWith("[");
0407: }
0408:
0409: public String getElementSignature() {
0410: if (!isArray())
0411: return signature;
0412: else {
0413: int pos = 0;
0414: int len = signature.length();
0415: while (pos < len) {
0416: if (signature.charAt(pos) != '[')
0417: break;
0418: pos++;
0419: }
0420: return signature.substring(pos);
0421: }
0422: }
0423:
0424: public boolean isNonNegative() {
0425: if (specialKind == NON_NEGATIVE)
0426: return true;
0427: if (constValue instanceof Number) {
0428: double value = ((Number) constValue).doubleValue();
0429: return value >= 0;
0430: }
0431: return false;
0432: }
0433:
0434: public boolean isPrimitive() {
0435: return !signature.startsWith("L")
0436: && !signature.startsWith("[");
0437: }
0438:
0439: public int getRegisterNumber() {
0440: return registerNumber;
0441: }
0442:
0443: public String getSignature() {
0444: return signature;
0445: }
0446:
0447: /**
0448: * Returns a constant value for this Item, if known.
0449: * NOTE: if the value is a constant Class object, the constant value returned is the name of the class.
0450: */
0451: public Object getConstant() {
0452: return constValue;
0453: }
0454:
0455: /** Use getXField instead */
0456: @Deprecated
0457: public FieldAnnotation getFieldAnnotation() {
0458: return FieldAnnotation.fromXField(getXField());
0459: }
0460:
0461: public XField getXField() {
0462: if (source instanceof XField)
0463: return (XField) source;
0464: return null;
0465: }
0466:
0467: /**
0468: * @param specialKind The specialKind to set.
0469: */
0470: public void setSpecialKind(int specialKind) {
0471: this .specialKind = specialKind;
0472: }
0473:
0474: /**
0475: * @return Returns the specialKind.
0476: */
0477: public int getSpecialKind() {
0478: return specialKind;
0479: }
0480:
0481: /**
0482: * attaches a detector specified value to this item
0483: *
0484: * @param value the custom value to set
0485: */
0486: public void setUserValue(Object value) {
0487: userValue = value;
0488: }
0489:
0490: /**
0491: *
0492: * @return if this value is the return value of a method, give the method
0493: * invoked
0494: */
0495: public @CheckForNull
0496: XMethod getReturnValueOf() {
0497: if (source instanceof XMethod)
0498: return (XMethod) source;
0499: return null;
0500: }
0501:
0502: public boolean couldBeZero() {
0503: return isCouldBeZero();
0504: }
0505:
0506: public boolean mustBeZero() {
0507: Object value = getConstant();
0508: return value instanceof Number
0509: && ((Number) value).intValue() == 0;
0510: }
0511:
0512: /**
0513: * gets the detector specified value for this item
0514: *
0515: * @return the custom value
0516: */
0517: public Object getUserValue() {
0518: return userValue;
0519: }
0520:
0521: public boolean valueCouldBeNegative() {
0522: return !isNonNegative()
0523: && (getSpecialKind() == Item.RANDOM_INT
0524: || getSpecialKind() == Item.SIGNED_BYTE
0525: || getSpecialKind() == Item.HASHCODE_INT
0526: || getSpecialKind() == Item.RANDOM_INT_REMAINDER || getSpecialKind() == Item.HASHCODE_INT_REMAINDER);
0527:
0528: }
0529:
0530: /**
0531: * @param isInitialParameter The isInitialParameter to set.
0532: */
0533: private void setInitialParameter(boolean isInitialParameter) {
0534: setFlag(isInitialParameter, IS_INITIAL_PARAMETER_FLAG);
0535: }
0536:
0537: /**
0538: * @return Returns the isInitialParameter.
0539: */
0540: public boolean isInitialParameter() {
0541: return (flags & IS_INITIAL_PARAMETER_FLAG) != 0;
0542: }
0543:
0544: /**
0545: * @param couldBeZero The couldBeZero to set.
0546: */
0547: private void setCouldBeZero(boolean couldBeZero) {
0548: setFlag(couldBeZero, COULD_BE_ZERO_FLAG);
0549: }
0550:
0551: /**
0552: * @return Returns the couldBeZero.
0553: */
0554: private boolean isCouldBeZero() {
0555: return (flags & COULD_BE_ZERO_FLAG) != 0;
0556: }
0557:
0558: /**
0559: * @param isNull The isNull to set.
0560: */
0561: private void setNull(boolean isNull) {
0562: setFlag(isNull, IS_NULL_FLAG);
0563: }
0564:
0565: private void setFlag(boolean value, int flagBit) {
0566: if (value)
0567: flags |= flagBit;
0568: else
0569: flags &= ~flagBit;
0570: }
0571:
0572: /**
0573: * @return Returns the isNull.
0574: */
0575: public boolean isNull() {
0576: return (flags & IS_NULL_FLAG) != 0;
0577: }
0578: }
0579:
0580: @Override
0581: public String toString() {
0582: if (isTop())
0583: return "TOP";
0584: return stack.toString() + "::" + lvValues.toString();
0585: }
0586:
0587: public OpcodeStack() {
0588: stack = new ArrayList<Item>();
0589: lvValues = new ArrayList<Item>();
0590: lastUpdate = new ArrayList<Integer>();
0591: }
0592:
0593: boolean needToMerge = true;
0594: private boolean reachOnlyByBranch = false;
0595:
0596: public static String getExceptionSig(DismantleBytecode dbc,
0597: CodeException e) {
0598: if (e.getCatchType() == 0)
0599: return "Ljava/lang/Throwable;";
0600: Constant c = dbc.getConstantPool()
0601: .getConstant(e.getCatchType());
0602: if (c instanceof ConstantClass)
0603: return "L"
0604: + ((ConstantClass) c).getBytes(dbc
0605: .getConstantPool()) + ";";
0606: return "Ljava/lang/Throwable;";
0607: }
0608:
0609: public void mergeJumps(DismantleBytecode dbc) {
0610:
0611: if (!needToMerge)
0612: return;
0613: needToMerge = false;
0614: boolean stackUpdated = false;
0615: if (!isTop()
0616: && (convertJumpToOneZeroState == 3 || convertJumpToZeroOneState == 3)) {
0617: pop();
0618: Item top = new Item("I");
0619: top.setCouldBeZero(true);
0620: push(top);
0621: convertJumpToOneZeroState = convertJumpToZeroOneState = 0;
0622: stackUpdated = true;
0623: }
0624:
0625: List<Item> jumpEntry = null;
0626: if (jumpEntryLocations.get(dbc.getPC()))
0627: jumpEntry = jumpEntries.get(dbc.getPC());
0628: if (jumpEntry != null) {
0629: setReachOnlyByBranch(false);
0630: List<Item> jumpStackEntry = jumpStackEntries.get(dbc
0631: .getPC());
0632:
0633: if (DEBUG2) {
0634: System.out.println("XXXXXXX " + isReachOnlyByBranch());
0635: System.out.println("merging lvValues at jump target "
0636: + dbc.getPC()
0637: + " -> "
0638: + Integer.toString(System
0639: .identityHashCode(jumpEntry), 16) + " "
0640: + jumpEntry);
0641: System.out.println(" current lvValues " + lvValues);
0642: System.out.println(" merging stack entry "
0643: + jumpStackEntry);
0644: System.out.println(" current stack values " + stack);
0645:
0646: }
0647: if (isTop()) {
0648: lvValues = new ArrayList<Item>(jumpEntry);
0649: if (jumpStackEntry != null)
0650: stack = new ArrayList<Item>(jumpStackEntry);
0651: else
0652: stack.clear();
0653: setTop(false);
0654: return;
0655: }
0656: if (isReachOnlyByBranch()) {
0657: setTop(false);
0658: lvValues = new ArrayList<Item>(jumpEntry);
0659: if (!stackUpdated) {
0660: if (jumpStackEntry != null)
0661: stack = new ArrayList<Item>(jumpStackEntry);
0662: else
0663: stack.clear();
0664: }
0665:
0666: } else {
0667: setTop(false);
0668: mergeLists(lvValues, jumpEntry, false);
0669: if (!stackUpdated && jumpStackEntry != null)
0670: mergeLists(stack, jumpStackEntry, false);
0671: }
0672: if (DEBUG)
0673: System.out.println(" merged lvValues " + lvValues);
0674: } else if (isReachOnlyByBranch() && !stackUpdated) {
0675: stack.clear();
0676:
0677: for (CodeException e : dbc.getCode().getExceptionTable()) {
0678: if (e.getHandlerPC() == dbc.getPC()) {
0679: push(new Item(getExceptionSig(dbc, e)));
0680: setReachOnlyByBranch(false);
0681: setTop(false);
0682: return;
0683:
0684: }
0685: }
0686: setTop(true);
0687: }
0688:
0689: }
0690:
0691: int convertJumpToOneZeroState = 0;
0692: int convertJumpToZeroOneState = 0;
0693:
0694: private void setLastUpdate(int reg, int pc) {
0695: while (lastUpdate.size() <= reg)
0696: lastUpdate.add(0);
0697: lastUpdate.set(reg, pc);
0698: }
0699:
0700: public int getLastUpdate(int reg) {
0701: if (lastUpdate.size() <= reg)
0702: return 0;
0703: return lastUpdate.get(reg);
0704: }
0705:
0706: public int getNumLastUpdates() {
0707: return lastUpdate.size();
0708: }
0709:
0710: public void sawOpcode(DismantleBytecode dbc, int seen) {
0711: int register;
0712: String signature;
0713: Item it, it2, it3;
0714: Constant cons;
0715: if (dbc.isRegisterStore())
0716: setLastUpdate(dbc.getRegisterOperand(), dbc.getPC());
0717: mergeJumps(dbc);
0718: needToMerge = true;
0719: try {
0720: if (isTop()) {
0721: encountedTop = true;
0722: return;
0723: }
0724: switch (seen) {
0725: case ICONST_1:
0726: convertJumpToOneZeroState = 1;
0727: break;
0728: case GOTO:
0729: if (convertJumpToOneZeroState == 1
0730: && dbc.getBranchOffset() == 4)
0731: convertJumpToOneZeroState = 2;
0732: else
0733: convertJumpToOneZeroState = 0;
0734: break;
0735: case ICONST_0:
0736: if (convertJumpToOneZeroState == 2)
0737: convertJumpToOneZeroState = 3;
0738: else
0739: convertJumpToOneZeroState = 0;
0740: break;
0741: default:
0742: convertJumpToOneZeroState = 0;
0743:
0744: }
0745: switch (seen) {
0746: case ICONST_0:
0747: convertJumpToZeroOneState = 1;
0748: break;
0749: case GOTO:
0750: if (convertJumpToZeroOneState == 1
0751: && dbc.getBranchOffset() == 4)
0752: convertJumpToZeroOneState = 2;
0753: else
0754: convertJumpToZeroOneState = 0;
0755: break;
0756: case ICONST_1:
0757: if (convertJumpToZeroOneState == 2)
0758: convertJumpToZeroOneState = 3;
0759: else
0760: convertJumpToZeroOneState = 0;
0761: break;
0762: default:
0763: convertJumpToZeroOneState = 0;
0764: }
0765:
0766: switch (seen) {
0767: case ALOAD:
0768: pushByLocalObjectLoad(dbc, dbc.getRegisterOperand());
0769: break;
0770:
0771: case ALOAD_0:
0772: case ALOAD_1:
0773: case ALOAD_2:
0774: case ALOAD_3:
0775: pushByLocalObjectLoad(dbc, seen - ALOAD_0);
0776: break;
0777:
0778: case DLOAD:
0779: pushByLocalLoad("D", dbc.getRegisterOperand());
0780: break;
0781:
0782: case DLOAD_0:
0783: case DLOAD_1:
0784: case DLOAD_2:
0785: case DLOAD_3:
0786: pushByLocalLoad("D", seen - DLOAD_0);
0787: break;
0788:
0789: case FLOAD:
0790: pushByLocalLoad("F", dbc.getRegisterOperand());
0791: break;
0792:
0793: case FLOAD_0:
0794: case FLOAD_1:
0795: case FLOAD_2:
0796: case FLOAD_3:
0797: pushByLocalLoad("F", seen - FLOAD_0);
0798: break;
0799:
0800: case ILOAD:
0801: pushByLocalLoad("I", dbc.getRegisterOperand());
0802: break;
0803:
0804: case ILOAD_0:
0805: case ILOAD_1:
0806: case ILOAD_2:
0807: case ILOAD_3:
0808: pushByLocalLoad("I", seen - ILOAD_0);
0809: break;
0810:
0811: case LLOAD:
0812: pushByLocalLoad("J", dbc.getRegisterOperand());
0813: break;
0814:
0815: case LLOAD_0:
0816: case LLOAD_1:
0817: case LLOAD_2:
0818: case LLOAD_3:
0819: pushByLocalLoad("J", seen - LLOAD_0);
0820: break;
0821:
0822: case GETSTATIC: {
0823: FieldAnnotation field = FieldAnnotation
0824: .fromReferencedField(dbc);
0825: Item i = new Item(dbc.getSigConstantOperand(), field,
0826: Integer.MAX_VALUE);
0827: if (field.getFieldName().equals("separator")
0828: && field.getClassName().equals("java.io.File")) {
0829: i.setSpecialKind(Item.FILE_SEPARATOR_STRING);
0830: }
0831:
0832: push(i);
0833: break;
0834: }
0835:
0836: case LDC:
0837: case LDC_W:
0838: case LDC2_W:
0839: cons = dbc.getConstantRefOperand();
0840: pushByConstant(dbc, cons);
0841: break;
0842:
0843: case INSTANCEOF:
0844: pop();
0845: push(new Item("I"));
0846: break;
0847: case IFEQ:
0848: case IFNE:
0849: case IFLT:
0850: case IFLE:
0851: case IFGT:
0852: case IFGE:
0853: case IFNONNULL:
0854: case IFNULL:
0855: seenTransferOfControl = true;
0856: {
0857: Item top = pop();
0858:
0859: // if we see a test comparing a special negative value with 0,
0860: // reset all other such values on the opcode stack
0861: if (top.valueCouldBeNegative()
0862: && (seen == IFLT || seen == IFLE
0863: || seen == IFGT || seen == IFGE)) {
0864: int specialKind = top.getSpecialKind();
0865: for (Item item : stack)
0866: if (item != null
0867: && item.getSpecialKind() == specialKind)
0868: item.setSpecialKind(0);
0869: for (Item item : lvValues)
0870: if (item != null
0871: && item.getSpecialKind() == specialKind)
0872: item.setSpecialKind(0);
0873:
0874: }
0875: }
0876: addJumpValue(dbc.getPC(), dbc.getBranchTarget());
0877:
0878: break;
0879: case LOOKUPSWITCH:
0880:
0881: case TABLESWITCH:
0882: seenTransferOfControl = true;
0883: setReachOnlyByBranch(true);
0884: pop();
0885: addJumpValue(dbc.getPC(), dbc.getBranchTarget());
0886: int pc = dbc.getBranchTarget() - dbc.getBranchOffset();
0887: for (int offset : dbc.getSwitchOffsets())
0888: addJumpValue(dbc.getPC(), offset + pc);
0889:
0890: break;
0891: case ARETURN:
0892: case DRETURN:
0893: case FRETURN:
0894:
0895: case IRETURN:
0896: case LRETURN:
0897:
0898: seenTransferOfControl = true;
0899: setReachOnlyByBranch(true);
0900: pop();
0901: break;
0902: case MONITORENTER:
0903: case MONITOREXIT:
0904: case POP:
0905: case PUTSTATIC:
0906: pop();
0907: break;
0908:
0909: case IF_ACMPEQ:
0910: case IF_ACMPNE:
0911: case IF_ICMPEQ:
0912: case IF_ICMPNE:
0913: case IF_ICMPLT:
0914: case IF_ICMPLE:
0915: case IF_ICMPGT:
0916: case IF_ICMPGE:
0917:
0918: {
0919: seenTransferOfControl = true;
0920: pop(2);
0921: int branchTarget = dbc.getBranchTarget();
0922: addJumpValue(dbc.getPC(), branchTarget);
0923: break;
0924: }
0925:
0926: case POP2:
0927: it = pop();
0928: if (it.getSize() == 1)
0929: pop();
0930: break;
0931: case PUTFIELD:
0932: pop(2);
0933: break;
0934:
0935: case IALOAD:
0936: case SALOAD:
0937: pop(2);
0938: push(new Item("I"));
0939: break;
0940:
0941: case DUP:
0942: handleDup();
0943: break;
0944:
0945: case DUP2:
0946: handleDup2();
0947: break;
0948:
0949: case DUP_X1:
0950: handleDupX1();
0951: break;
0952:
0953: case DUP_X2:
0954:
0955: handleDupX2();
0956: break;
0957:
0958: case DUP2_X1:
0959: handleDup2X1();
0960: break;
0961:
0962: case DUP2_X2:
0963: handleDup2X2();
0964: break;
0965:
0966: case IINC:
0967: register = dbc.getRegisterOperand();
0968: it = getLVValue(register);
0969: it2 = new Item("I", dbc.getIntConstant());
0970: pushByIntMath(dbc, IADD, it2, it);
0971: pushByLocalStore(register);
0972: break;
0973:
0974: case ATHROW:
0975: pop();
0976: seenTransferOfControl = true;
0977: setReachOnlyByBranch(true);
0978: setTop(true);
0979: break;
0980:
0981: case CHECKCAST: {
0982: String castTo = dbc.getClassConstantOperand();
0983:
0984: if (castTo.charAt(0) != '[')
0985: castTo = "L" + castTo + ";";
0986: it = new Item(pop());
0987: it.signature = castTo;
0988: push(it);
0989:
0990: break;
0991:
0992: }
0993: case NOP:
0994: break;
0995: case RET:
0996: case RETURN:
0997: seenTransferOfControl = true;
0998: setReachOnlyByBranch(true);
0999: break;
1000:
1001: case GOTO:
1002: case GOTO_W:
1003: seenTransferOfControl = true;
1004: setReachOnlyByBranch(true);
1005: addJumpValue(dbc.getPC(), dbc.getBranchTarget());
1006: stack.clear();
1007: setTop(true);
1008:
1009: break;
1010:
1011: case SWAP:
1012: handleSwap();
1013: break;
1014:
1015: case ICONST_M1:
1016: case ICONST_0:
1017: case ICONST_1:
1018: case ICONST_2:
1019: case ICONST_3:
1020: case ICONST_4:
1021: case ICONST_5:
1022: push(new Item("I", (seen - ICONST_0)));
1023: break;
1024:
1025: case LCONST_0:
1026: case LCONST_1:
1027: push(new Item("J", (long) (seen - LCONST_0)));
1028: break;
1029:
1030: case DCONST_0:
1031: case DCONST_1:
1032: push(new Item("D", (double) (seen - DCONST_0)));
1033: break;
1034:
1035: case FCONST_0:
1036: case FCONST_1:
1037: case FCONST_2:
1038: push(new Item("F", (float) (seen - FCONST_0)));
1039: break;
1040:
1041: case ACONST_NULL:
1042: push(new Item());
1043: break;
1044:
1045: case ASTORE:
1046: case DSTORE:
1047: case FSTORE:
1048: case ISTORE:
1049: case LSTORE:
1050: pushByLocalStore(dbc.getRegisterOperand());
1051: break;
1052:
1053: case ASTORE_0:
1054: case ASTORE_1:
1055: case ASTORE_2:
1056: case ASTORE_3:
1057: pushByLocalStore(seen - ASTORE_0);
1058: break;
1059:
1060: case DSTORE_0:
1061: case DSTORE_1:
1062: case DSTORE_2:
1063: case DSTORE_3:
1064: pushByLocalStore(seen - DSTORE_0);
1065: break;
1066:
1067: case FSTORE_0:
1068: case FSTORE_1:
1069: case FSTORE_2:
1070: case FSTORE_3:
1071: pushByLocalStore(seen - FSTORE_0);
1072: break;
1073:
1074: case ISTORE_0:
1075: case ISTORE_1:
1076: case ISTORE_2:
1077: case ISTORE_3:
1078: pushByLocalStore(seen - ISTORE_0);
1079: break;
1080:
1081: case LSTORE_0:
1082: case LSTORE_1:
1083: case LSTORE_2:
1084: case LSTORE_3:
1085: pushByLocalStore(seen - LSTORE_0);
1086: break;
1087:
1088: case GETFIELD: {
1089: Item item = pop();
1090: int reg = item.getRegisterNumber();
1091: push(new Item(dbc.getSigConstantOperand(),
1092: FieldAnnotation.fromReferencedField(dbc), reg));
1093: }
1094: break;
1095:
1096: case ARRAYLENGTH: {
1097: pop();
1098: Item v = new Item("I");
1099: v.setSpecialKind(Item.NON_NEGATIVE);
1100: push(v);
1101: }
1102: break;
1103:
1104: case BALOAD: {
1105: pop(2);
1106: Item v = new Item("I");
1107: v.setSpecialKind(Item.SIGNED_BYTE);
1108: push(v);
1109: break;
1110: }
1111: case CALOAD:
1112: pop(2);
1113: push(new Item("I"));
1114: break;
1115:
1116: case DALOAD:
1117: pop(2);
1118: push(new Item("D"));
1119: break;
1120:
1121: case FALOAD:
1122: pop(2);
1123: push(new Item("F"));
1124: break;
1125:
1126: case LALOAD:
1127: pop(2);
1128: push(new Item("J"));
1129: break;
1130:
1131: case AASTORE:
1132: case BASTORE:
1133: case CASTORE:
1134: case DASTORE:
1135: case FASTORE:
1136: case IASTORE:
1137: case LASTORE:
1138: case SASTORE:
1139: pop(3);
1140: break;
1141:
1142: case BIPUSH:
1143: case SIPUSH:
1144: push(new Item("I", (Integer) dbc.getIntConstant()));
1145: break;
1146:
1147: case IADD:
1148: case ISUB:
1149: case IMUL:
1150: case IDIV:
1151: case IAND:
1152: case IOR:
1153: case IXOR:
1154: case ISHL:
1155: case ISHR:
1156: case IREM:
1157: case IUSHR:
1158: it = pop();
1159: it2 = pop();
1160: pushByIntMath(dbc, seen, it2, it);
1161: break;
1162:
1163: case INEG:
1164: it = pop();
1165: if (it.getConstant() instanceof Integer) {
1166: push(new Item("I", (Integer) (-(Integer) it
1167: .getConstant())));
1168: } else {
1169: push(new Item("I"));
1170: }
1171: break;
1172:
1173: case LNEG:
1174: it = pop();
1175: if (it.getConstant() instanceof Long) {
1176: push(new Item("J",
1177: (Long) (-(Long) it.getConstant())));
1178: } else {
1179: push(new Item("J"));
1180: }
1181: break;
1182: case FNEG:
1183: it = pop();
1184: if (it.getConstant() instanceof Float) {
1185: push(new Item("F", (Float) (-(Float) it
1186: .getConstant())));
1187: } else {
1188: push(new Item("F"));
1189: }
1190: break;
1191: case DNEG:
1192: it = pop();
1193: if (it.getConstant() instanceof Double) {
1194: push(new Item("D", (Double) (-(Double) it
1195: .getConstant())));
1196: } else {
1197: push(new Item("D"));
1198: }
1199: break;
1200:
1201: case LADD:
1202: case LSUB:
1203: case LMUL:
1204: case LDIV:
1205: case LAND:
1206: case LOR:
1207: case LXOR:
1208: case LSHL:
1209: case LSHR:
1210: case LREM:
1211: case LUSHR:
1212:
1213: it = pop();
1214: it2 = pop();
1215: pushByLongMath(seen, it2, it);
1216: break;
1217:
1218: case LCMP:
1219: handleLcmp();
1220: break;
1221:
1222: case FCMPG:
1223: case FCMPL:
1224: handleFcmp(seen);
1225: break;
1226:
1227: case DCMPG:
1228: case DCMPL:
1229: handleDcmp(seen);
1230: break;
1231:
1232: case FADD:
1233: case FSUB:
1234: case FMUL:
1235: case FDIV:
1236: case FREM:
1237: it = pop();
1238: it2 = pop();
1239: pushByFloatMath(seen, it, it2);
1240: break;
1241:
1242: case DADD:
1243: case DSUB:
1244: case DMUL:
1245: case DDIV:
1246: case DREM:
1247: it = pop();
1248: it2 = pop();
1249: pushByDoubleMath(seen, it, it2);
1250: break;
1251:
1252: case I2B:
1253: it = pop();
1254: if (it.getConstant() != null) {
1255: it = new Item("I", (byte) constantToInt(it));
1256: } else {
1257: it = new Item("I");
1258: }
1259: it.setSpecialKind(Item.SIGNED_BYTE);
1260: push(it);
1261: break;
1262:
1263: case I2C:
1264: it = pop();
1265: if (it.getConstant() != null) {
1266: it = new Item("I", (char) constantToInt(it));
1267: } else {
1268: it = new Item("I");
1269: }
1270: it.setSpecialKind(Item.NON_NEGATIVE);
1271: push(it);
1272: break;
1273:
1274: case I2L:
1275: case D2L:
1276: case F2L: {
1277: it = pop();
1278: Item newValue;
1279: if (it.getConstant() != null) {
1280: newValue = new Item("J", constantToLong(it));
1281: } else {
1282: newValue = new Item("J");
1283: }
1284: newValue.setSpecialKind(it.getSpecialKind());
1285: push(newValue);
1286: }
1287: break;
1288:
1289: case I2S:
1290: it = pop();
1291: if (it.getConstant() != null) {
1292: push(new Item("I", (short) constantToInt(it)));
1293: } else {
1294: push(new Item("I"));
1295: }
1296: break;
1297:
1298: case L2I:
1299: case D2I:
1300: case F2I:
1301: it = pop();
1302: if (it.getConstant() != null) {
1303: push(new Item("I", constantToInt(it)));
1304: } else {
1305: push(new Item("I"));
1306: }
1307: break;
1308:
1309: case L2F:
1310: case D2F:
1311: case I2F:
1312: it = pop();
1313: if (it.getConstant() != null) {
1314: push(new Item("F", (Float) (constantToFloat(it))));
1315: } else {
1316: push(new Item("F"));
1317: }
1318: break;
1319:
1320: case F2D:
1321: case I2D:
1322: case L2D:
1323: it = pop();
1324: if (it.getConstant() != null) {
1325: push(new Item("D", constantToDouble(it)));
1326: } else {
1327: push(new Item("D"));
1328: }
1329: break;
1330:
1331: case NEW:
1332: pushBySignature("L" + dbc.getClassConstantOperand()
1333: + ";");
1334: break;
1335:
1336: case NEWARRAY:
1337: pop();
1338: signature = "["
1339: + BasicType
1340: .getType((byte) dbc.getIntConstant())
1341: .getSignature();
1342: pushBySignature(signature);
1343: break;
1344:
1345: // According to the VM Spec 4.4.1, anewarray and multianewarray
1346: // can refer to normal class/interface types (encoded in
1347: // "internal form"), or array classes (encoded as signatures
1348: // beginning with "[").
1349:
1350: case ANEWARRAY:
1351: pop();
1352: signature = dbc.getClassConstantOperand();
1353: if (!signature.startsWith("[")) {
1354: signature = "[L" + signature + ";";
1355: }
1356: pushBySignature(signature);
1357: break;
1358:
1359: case MULTIANEWARRAY:
1360: int dims = dbc.getIntConstant();
1361: while ((dims--) > 0) {
1362: pop();
1363: }
1364: signature = dbc.getClassConstantOperand();
1365: if (!signature.startsWith("[")) {
1366: dims = dbc.getIntConstant();
1367: signature = Util.repeat("[", dims) + "L"
1368: + signature + ";";
1369: }
1370: pushBySignature(signature);
1371: break;
1372:
1373: case AALOAD:
1374: pop();
1375: it = pop();
1376: pushBySignature(it.getElementSignature());
1377: break;
1378:
1379: case JSR:
1380: seenTransferOfControl = true;
1381: setReachOnlyByBranch(false);
1382: push(new Item("")); // push return address on stack
1383: addJumpValue(dbc.getPC(), dbc.getBranchTarget());
1384: pop();
1385: if (dbc.getBranchOffset() < 0) {
1386: // OK, backwards JSRs are weird; reset the stack.
1387: int stackSize = stack.size();
1388: stack.clear();
1389: for (int i = 0; i < stackSize; i++)
1390: stack.add(new Item());
1391: }
1392: setTop(false);
1393: break;
1394:
1395: case INVOKEINTERFACE:
1396: case INVOKESPECIAL:
1397: case INVOKESTATIC:
1398: case INVOKEVIRTUAL:
1399: processMethodCall(dbc, seen);
1400: break;
1401:
1402: default:
1403: throw new UnsupportedOperationException("OpCode "
1404: + OPCODE_NAMES[seen] + " not supported ");
1405: }
1406: }
1407:
1408: catch (RuntimeException e) {
1409: //If an error occurs, we clear the stack and locals. one of two things will occur.
1410: //Either the client will expect more stack items than really exist, and so they're condition check will fail,
1411: //or the stack will resync with the code. But hopefully not false positives
1412:
1413: String msg = "Error processing opcode "
1414: + OPCODE_NAMES[seen] + " @ " + dbc.getPC() + " in "
1415: + dbc.getFullyQualifiedMethodName();
1416: AnalysisContext.logError(msg, e);
1417: if (DEBUG)
1418: e.printStackTrace();
1419: clear();
1420: } finally {
1421: if (DEBUG) {
1422: System.out.println(dbc.getNextPC() + "pc : "
1423: + OPCODE_NAMES[seen] + " stack depth: "
1424: + getStackDepth());
1425: System.out.println(this );
1426: }
1427: }
1428: }
1429:
1430: /**
1431: * @param it
1432: * @return
1433: */
1434: private int constantToInt(Item it) {
1435: return ((Number) it.getConstant()).intValue();
1436: }
1437:
1438: /**
1439: * @param it
1440: * @return
1441: */
1442: private float constantToFloat(Item it) {
1443: return ((Number) it.getConstant()).floatValue();
1444: }
1445:
1446: /**
1447: * @param it
1448: * @return
1449: */
1450: private double constantToDouble(Item it) {
1451: return ((Number) it.getConstant()).doubleValue();
1452: }
1453:
1454: /**
1455: * @param it
1456: * @return
1457: */
1458: private long constantToLong(Item it) {
1459: return ((Number) it.getConstant()).longValue();
1460: }
1461:
1462: /**
1463: * handle dcmp
1464: *
1465: */
1466: private void handleDcmp(int opcode) {
1467: Item it;
1468: Item it2;
1469:
1470: it = pop();
1471:
1472: it2 = pop();
1473: if ((it.getConstant() != null) && it2.getConstant() != null) {
1474: double d = (Double) it.getConstant();
1475: double d2 = (Double) it.getConstant();
1476: if (Double.isNaN(d) || Double.isNaN(d2)) {
1477: if (opcode == DCMPG)
1478: push(new Item("I", (Integer) (1)));
1479: else
1480: push(new Item("I", (Integer) (-1)));
1481: }
1482: if (d2 < d)
1483: push(new Item("I", (Integer) (-1)));
1484: else if (d2 > d)
1485: push(new Item("I", (Integer) 1));
1486: else
1487: push(new Item("I", (Integer) 0));
1488: } else {
1489: push(new Item("I"));
1490: }
1491:
1492: }
1493:
1494: /**
1495: * handle fcmp
1496: *
1497: */
1498: private void handleFcmp(int opcode) {
1499: Item it;
1500: Item it2;
1501: it = pop();
1502: it2 = pop();
1503: if ((it.getConstant() != null) && it2.getConstant() != null) {
1504: float f = (Float) it.getConstant();
1505: float f2 = (Float) it.getConstant();
1506: if (Float.isNaN(f) || Float.isNaN(f2)) {
1507: if (opcode == FCMPG)
1508: push(new Item("I", (Integer) (1)));
1509: else
1510: push(new Item("I", (Integer) (-1)));
1511: }
1512: if (f2 < f)
1513: push(new Item("I", (Integer) (-1)));
1514: else if (f2 > f)
1515: push(new Item("I", (Integer) (1)));
1516: else
1517: push(new Item("I", (Integer) (0)));
1518: } else {
1519: push(new Item("I"));
1520: }
1521: }
1522:
1523: /**
1524: * handle lcmp
1525: */
1526: private void handleLcmp() {
1527: Item it;
1528: Item it2;
1529:
1530: it = pop();
1531: it2 = pop();
1532: if ((it.getConstant() != null) && it2.getConstant() != null) {
1533: long l = (Long) it.getConstant();
1534: long l2 = (Long) it.getConstant();
1535: if (l2 < l)
1536: push(new Item("I", (Integer) (-1)));
1537: else if (l2 > l)
1538: push(new Item("I", (Integer) (1)));
1539: else
1540: push(new Item("I", (Integer) (0)));
1541: } else {
1542: push(new Item("I"));
1543: }
1544:
1545: }
1546:
1547: /**
1548: * handle swap
1549: */
1550: private void handleSwap() {
1551: Item i1 = pop();
1552: Item i2 = pop();
1553: push(i1);
1554: push(i2);
1555: }
1556:
1557: /**
1558: * handleDup
1559: */
1560: private void handleDup() {
1561: Item it;
1562: it = pop();
1563: push(it);
1564: push(it);
1565: }
1566:
1567: /**
1568: * handle dupX1
1569: */
1570: private void handleDupX1() {
1571: Item it;
1572: Item it2;
1573: it = pop();
1574: it2 = pop();
1575: push(it);
1576: push(it2);
1577: push(it);
1578: }
1579:
1580: /**
1581: * handle dup2
1582: */
1583: private void handleDup2() {
1584: Item it, it2;
1585: it = pop();
1586: if (it.getSize() == 2) {
1587: push(it);
1588: push(it);
1589: } else {
1590: it2 = pop();
1591: push(it2);
1592: push(it);
1593: push(it2);
1594: push(it);
1595: }
1596: }
1597:
1598: /**
1599: * handle Dup2x1
1600: */
1601: private void handleDup2X1() {
1602: String signature;
1603: Item it;
1604: Item it2;
1605: Item it3;
1606:
1607: it = pop();
1608:
1609: it2 = pop();
1610: signature = it.getSignature();
1611: if (signature.equals("J") || signature.equals("D")) {
1612: push(it);
1613: push(it2);
1614: push(it);
1615: } else {
1616: it3 = pop();
1617: push(it2);
1618: push(it);
1619: push(it3);
1620: push(it2);
1621: push(it);
1622: }
1623: }
1624:
1625: private void handleDup2X2() {
1626: String signature;
1627: Item it = pop();
1628: Item it2 = pop();
1629:
1630: if (it.isWide()) {
1631: if (it2.isWide()) {
1632: push(it);
1633: push(it2);
1634: push(it);
1635: } else {
1636: Item it3 = pop();
1637: push(it);
1638: push(it3);
1639: push(it2);
1640: push(it);
1641: }
1642: } else {
1643: Item it3 = pop();
1644: if (it3.isWide()) {
1645: push(it2);
1646: push(it);
1647: push(it3);
1648: push(it2);
1649: push(it);
1650: } else {
1651: Item it4 = pop();
1652: push(it2);
1653: push(it);
1654: push(it4);
1655: push(it3);
1656: push(it2);
1657: push(it);
1658: }
1659: }
1660: }
1661:
1662: /**
1663: * Handle DupX2
1664: */
1665: private void handleDupX2() {
1666: String signature;
1667: Item it;
1668: Item it2;
1669: Item it3;
1670: it = pop();
1671: it2 = pop();
1672: signature = it2.getSignature();
1673: if (signature.equals("J") || signature.equals("D")) {
1674: push(it);
1675: push(it2);
1676: push(it);
1677: } else {
1678: it3 = pop();
1679: push(it);
1680: push(it3);
1681: push(it2);
1682: push(it);
1683: }
1684: }
1685:
1686: private void processMethodCall(DismantleBytecode dbc, int seen) {
1687: String clsName = dbc.getClassConstantOperand();
1688: String methodName = dbc.getNameConstantOperand();
1689: String signature = dbc.getSigConstantOperand();
1690: String appenderValue = null;
1691: boolean sawUnknownAppend = false;
1692: Item sbItem = null;
1693:
1694: //TODO: stack merging for trinaries kills the constant.. would be nice to maintain.
1695: if ("java/lang/StringBuffer".equals(clsName)
1696: || "java/lang/StringBuilder".equals(clsName)) {
1697: if ("<init>".equals(methodName)) {
1698: if ("(Ljava/lang/String;)V".equals(signature)) {
1699: Item i = getStackItem(0);
1700: appenderValue = (String) i.getConstant();
1701: } else if ("()V".equals(signature)) {
1702: appenderValue = "";
1703: }
1704: } else if ("toString".equals(methodName)
1705: && getStackDepth() >= 1) {
1706: Item i = getStackItem(0);
1707: appenderValue = (String) i.getConstant();
1708: } else if ("append".equals(methodName)) {
1709: if (signature.indexOf("II)") == -1
1710: && getStackDepth() >= 2) {
1711: sbItem = getStackItem(1);
1712: Item i = getStackItem(0);
1713: Object sbVal = sbItem.getConstant();
1714: Object sVal = i.getConstant();
1715: if ((sbVal != null) && (sVal != null)) {
1716: appenderValue = sbVal + sVal.toString();
1717: } else if (sbItem.registerNumber >= 0) {
1718: OpcodeStack.Item item = getLVValue(sbItem.registerNumber);
1719: if (item != null)
1720: item.constValue = null;
1721: }
1722: } else if (signature.startsWith("([CII)")) {
1723: sawUnknownAppend = true;
1724: sbItem = getStackItem(3);
1725: if (sbItem.registerNumber >= 0) {
1726: OpcodeStack.Item item = getLVValue(sbItem.registerNumber);
1727: if (item != null)
1728: item.constValue = null;
1729: }
1730: } else {
1731: sawUnknownAppend = true;
1732: }
1733: }
1734: } else if (seen == INVOKESPECIAL
1735: && clsName.equals("java/io/FileOutputStream")
1736: && methodName.equals("<init>")
1737: && (signature.equals("(Ljava/io/File;Z)V") || signature
1738: .equals("(Ljava/lang/String;Z)V"))) {
1739: OpcodeStack.Item item = getStackItem(0);
1740: Object value = item.getConstant();
1741: if (value instanceof Integer
1742: && ((Integer) value).intValue() == 1) {
1743: pop(3);
1744: Item top = getStackItem(0);
1745: if (top.signature.equals("Ljava/io/FileOutputStream;")) {
1746: top.setSpecialKind(Item.FILE_OPENED_IN_APPEND_MODE);
1747: top.source = XFactory.createReferencedXMethod(dbc);
1748: }
1749: return;
1750: }
1751: } else if (seen == INVOKESPECIAL
1752: && clsName.equals("java/io/BufferedOutputStream")
1753: && methodName.equals("<init>")
1754: && signature.equals("(Ljava/io/OutputStream;)V")) {
1755: OpcodeStack.Item item = getStackItem(0);
1756:
1757: if (getStackItem(0).getSpecialKind() == Item.FILE_OPENED_IN_APPEND_MODE
1758: && getStackItem(2).signature
1759: .equals("Ljava/io/BufferedOutputStream;")) {
1760:
1761: pop(2);
1762: Item top = getStackItem(0);
1763: top.setSpecialKind(Item.FILE_OPENED_IN_APPEND_MODE);
1764: top.source = XFactory.createReferencedXMethod(dbc);
1765: return;
1766: }
1767: }
1768: pushByInvoke(dbc, seen != INVOKESTATIC);
1769:
1770: if ((sawUnknownAppend || appenderValue != null)
1771: && getStackDepth() > 0) {
1772: Item i = this .getStackItem(0);
1773: i.constValue = appenderValue;
1774: if (sbItem != null) {
1775: i.registerNumber = sbItem.registerNumber;
1776: i.source = sbItem.source;
1777: i.userValue = sbItem.userValue;
1778: if (sbItem.registerNumber >= 0)
1779: setLVValue(sbItem.registerNumber, i);
1780: }
1781: return;
1782: }
1783:
1784: if ((clsName.equals("java/util/Random") || clsName
1785: .equals("java/security/SecureRandom"))
1786: && methodName.equals("nextInt")
1787: && signature.equals("()I")) {
1788: Item i = pop();
1789: i.setSpecialKind(Item.RANDOM_INT);
1790: i.source = XFactory.createReferencedXMethod(dbc);
1791: push(i);
1792: }
1793: if (clsName.equals("java/lang/Math")
1794: && methodName.equals("abs")) {
1795: Item i = pop();
1796: i.setSpecialKind(Item.MATH_ABS);
1797: i.source = XFactory.createReferencedXMethod(dbc);
1798: push(i);
1799: } else if (seen == INVOKEVIRTUAL
1800: && methodName.equals("hashCode")
1801: && signature.equals("()I") || seen == INVOKESTATIC
1802: && clsName.equals("java/lang/System")
1803: && methodName.equals("identityHashCode")
1804: && signature.equals("(Ljava/lang/Object;)I")) {
1805: Item i = pop();
1806: i.setSpecialKind(Item.HASHCODE_INT);
1807: i.source = XFactory.createReferencedXMethod(dbc);
1808: push(i);
1809: } else if (!signature.endsWith(")V")) {
1810: Item i = pop();
1811: i.source = XFactory.createReferencedXMethod(dbc);
1812: push(i);
1813: }
1814:
1815: }
1816:
1817: private void mergeLists(List<Item> mergeInto, List<Item> mergeFrom,
1818: boolean errorIfSizesDoNotMatch) {
1819: // merge stacks
1820: int intoSize = mergeInto.size();
1821: int fromSize = mergeFrom.size();
1822: if (errorIfSizesDoNotMatch && intoSize != fromSize) {
1823: if (DEBUG2) {
1824: System.out.println("Bad merging items");
1825: System.out.println("current items: " + mergeInto);
1826: System.out.println("jump items: " + mergeFrom);
1827: }
1828: } else {
1829: if (DEBUG2) {
1830: if (intoSize == fromSize)
1831: System.out.println("Merging items");
1832: else
1833: System.out.println("Bad merging items");
1834: System.out.println("current items: " + mergeInto);
1835: System.out.println("jump items: " + mergeFrom);
1836: }
1837:
1838: for (int i = 0; i < Math.min(intoSize, fromSize); i++)
1839: mergeInto.set(i, Item.merge(mergeInto.get(i), mergeFrom
1840: .get(i)));
1841: if (DEBUG2) {
1842: System.out.println("merged items: " + mergeInto);
1843: }
1844: }
1845: }
1846:
1847: public void clear() {
1848: stack.clear();
1849: lvValues.clear();
1850: }
1851:
1852: boolean encountedTop;
1853: boolean backwardsBranch;
1854: BitSet exceptionHandlers = new BitSet();
1855: private Map<Integer, List<Item>> jumpEntries = new HashMap<Integer, List<Item>>();
1856: private Map<Integer, List<Item>> jumpStackEntries = new HashMap<Integer, List<Item>>();
1857: private BitSet jumpEntryLocations = new BitSet();
1858:
1859: static class JumpInfo {
1860: final Map<Integer, List<Item>> jumpEntries;
1861: final Map<Integer, List<Item>> jumpStackEntries;
1862: final BitSet jumpEntryLocations;
1863:
1864: JumpInfo(Map<Integer, List<Item>> jumpEntries,
1865: Map<Integer, List<Item>> jumpStackEntries,
1866: BitSet jumpEntryLocations) {
1867: this .jumpEntries = jumpEntries;
1868: this .jumpStackEntries = jumpStackEntries;
1869: this .jumpEntryLocations = jumpEntryLocations;
1870: }
1871: }
1872:
1873: public static class JumpInfoFactory extends
1874: AnalysisFactory<JumpInfo> {
1875:
1876: public JumpInfoFactory() {
1877: super ("Jump info for opcode stack", JumpInfo.class);
1878: }
1879:
1880: public JumpInfo analyze(IAnalysisCache analysisCache,
1881: MethodDescriptor descriptor)
1882: throws CheckedAnalysisException {
1883: Method method = analysisCache.getMethodAnalysis(
1884: Method.class, descriptor);
1885: JavaClass jclass = getJavaClass(analysisCache, descriptor
1886: .getClassDescriptor());
1887:
1888: Code code = method.getCode();
1889: final OpcodeStack stack = new OpcodeStack();
1890: if (code == null) {
1891: return null;
1892: }
1893: DismantleBytecode branchAnalysis = new DismantleBytecode() {
1894: @Override
1895: public void sawOpcode(int seen) {
1896: stack.sawOpcode(this , seen);
1897: }
1898: };
1899: branchAnalysis.setupVisitorForClass(jclass);
1900: int oldCount = 0;
1901: while (true) {
1902: stack.resetForMethodEntry0(ClassName
1903: .toSlashedClassName(jclass.getClassName()),
1904: method);
1905: branchAnalysis.doVisitMethod(method);
1906: int newCount = stack.jumpEntries.size();
1907: if (newCount == oldCount || !stack.encountedTop
1908: || !stack.backwardsBranch)
1909: break;
1910: oldCount = newCount;
1911: }
1912:
1913: return new JumpInfo(stack.jumpEntries,
1914: stack.jumpStackEntries, stack.jumpEntryLocations);
1915: }
1916: }
1917:
1918: private void addJumpValue(int from, int target) {
1919: if (DEBUG)
1920: System.out.println("Set jump entry at " + methodName + ":"
1921: + target + "pc to " + stack + " : " + lvValues);
1922:
1923: if (from >= target)
1924: backwardsBranch = true;
1925: List<Item> atTarget = jumpEntries.get(target);
1926: if (atTarget == null) {
1927: if (DEBUG)
1928: System.out.println("Was null");
1929:
1930: jumpEntries.put(target, new ArrayList<Item>(lvValues));
1931: jumpEntryLocations.set(target);
1932: if (stack.size() > 0) {
1933: jumpStackEntries
1934: .put(target, new ArrayList<Item>(stack));
1935: }
1936: return;
1937: }
1938: mergeLists(atTarget, lvValues, false);
1939: List<Item> stackAtTarget = jumpStackEntries.get(target);
1940: if (stack.size() > 0 && stackAtTarget != null)
1941: mergeLists(stackAtTarget, stack, false);
1942: if (DEBUG)
1943: System.out.println("merge target for " + methodName + ":"
1944: + target + "pc is " + atTarget);
1945: }
1946:
1947: private String methodName;
1948: DismantleBytecode v;
1949:
1950: public void learnFrom(JumpInfo info) {
1951: jumpEntries = new HashMap<Integer, List<Item>>(info.jumpEntries);
1952: jumpStackEntries = new HashMap<Integer, List<Item>>(
1953: info.jumpStackEntries);
1954: jumpEntryLocations = (BitSet) info.jumpEntryLocations.clone();
1955: }
1956:
1957: public void initialize() {
1958: setTop(false);
1959: jumpEntries.clear();
1960: jumpStackEntries.clear();
1961: jumpEntryLocations.clear();
1962: encountedTop = false;
1963: backwardsBranch = false;
1964: lastUpdate.clear();
1965: convertJumpToOneZeroState = convertJumpToZeroOneState = 0;
1966: setReachOnlyByBranch(false);
1967: }
1968:
1969: public int resetForMethodEntry(final DismantleBytecode v) {
1970: this .v = v;
1971: initialize();
1972:
1973: int result = resetForMethodEntry0(v);
1974: Code code = v.getMethod().getCode();
1975: if (code == null)
1976: return result;
1977:
1978: if (useIterativeAnalysis) {
1979: IAnalysisCache analysisCache = Global.getAnalysisCache();
1980: XMethod xMethod = XFactory.createXMethod(v.getThisClass(),
1981: v.getMethod());
1982: try {
1983: JumpInfo jump = analysisCache.getMethodAnalysis(
1984: JumpInfo.class, xMethod.getMethodDescriptor());
1985: if (jump != null) {
1986: learnFrom(jump);
1987: }
1988: } catch (CheckedAnalysisException e) {
1989: AnalysisContext.logError(
1990: "Error getting jump information", e);
1991: }
1992: }
1993:
1994: return result;
1995:
1996: }
1997:
1998: private int resetForMethodEntry0(PreorderVisitor v) {
1999: return resetForMethodEntry0(v.getClassName(), v.getMethod());
2000: }
2001:
2002: private int resetForMethodEntry0(@SlashedClassName
2003: String className, Method m) {
2004: methodName = m.getName();
2005:
2006: if (DEBUG)
2007: System.out.println(" --- ");
2008: String signature = m.getSignature();
2009: stack.clear();
2010: lvValues.clear();
2011: top = false;
2012: encountedTop = false;
2013: backwardsBranch = false;
2014:
2015: setReachOnlyByBranch(false);
2016: seenTransferOfControl = false;
2017: exceptionHandlers.clear();
2018: Code code = m.getCode();
2019: if (code != null) {
2020: CodeException[] exceptionTable = code.getExceptionTable();
2021: if (exceptionTable != null)
2022: for (CodeException ex : exceptionTable)
2023: exceptionHandlers.set(ex.getHandlerPC());
2024: }
2025: if (DEBUG)
2026: System.out.println(" --- " + className + " " + m.getName()
2027: + " " + signature);
2028: Type[] argTypes = Type.getArgumentTypes(signature);
2029: int reg = 0;
2030: if (!m.isStatic()) {
2031: Item it = new Item("L" + className + ";");
2032: it.setInitialParameter(true);
2033: it.registerNumber = reg;
2034: setLVValue(reg, it);
2035: reg += it.getSize();
2036: }
2037: for (Type argType : argTypes) {
2038: Item it = new Item(argType.getSignature());
2039: it.registerNumber = reg;
2040: it.setInitialParameter(true);
2041: setLVValue(reg, it);
2042: reg += it.getSize();
2043: }
2044: return reg;
2045: }
2046:
2047: public int getStackDepth() {
2048: return stack.size();
2049: }
2050:
2051: public Item getStackItem(int stackOffset) {
2052: if (stackOffset < 0 || stackOffset >= stack.size()) {
2053: AnalysisContext.logError("Can't get stack offset "
2054: + stackOffset + " from " + stack.toString() + " @ "
2055: + v.getPC() + " in "
2056: + v.getFullyQualifiedMethodName(),
2057: new IllegalArgumentException());
2058: return new Item("Lfindbugs/OpcodeStackError;");
2059:
2060: }
2061: int tos = stack.size() - 1;
2062: int pos = tos - stackOffset;
2063: try {
2064: return stack.get(pos);
2065: } catch (ArrayIndexOutOfBoundsException e) {
2066: throw new ArrayIndexOutOfBoundsException(
2067: "Requested item at offset " + stackOffset
2068: + " in a stack of size " + stack.size()
2069: + ", made request for position " + pos);
2070: }
2071: }
2072:
2073: private Item pop() {
2074: return stack.remove(stack.size() - 1);
2075: }
2076:
2077: private void pop(int count) {
2078: while ((count--) > 0)
2079: pop();
2080: }
2081:
2082: private void push(Item i) {
2083: stack.add(i);
2084: }
2085:
2086: private void pushByConstant(DismantleBytecode dbc, Constant c) {
2087:
2088: if (c instanceof ConstantClass)
2089: push(new Item("Ljava/lang/Class;", ((ConstantClass) c)
2090: .getConstantValue(dbc.getConstantPool())));
2091: else if (c instanceof ConstantInteger)
2092: push(new Item("I", (Integer) (((ConstantInteger) c)
2093: .getBytes())));
2094: else if (c instanceof ConstantString) {
2095: int s = ((ConstantString) c).getStringIndex();
2096: push(new Item("Ljava/lang/String;", getStringFromIndex(dbc,
2097: s)));
2098: } else if (c instanceof ConstantFloat)
2099: push(new Item("F", (Float) (((ConstantFloat) c).getBytes())));
2100: else if (c instanceof ConstantDouble)
2101: push(new Item("D", (Double) (((ConstantDouble) c)
2102: .getBytes())));
2103: else if (c instanceof ConstantLong)
2104: push(new Item("J", (Long) (((ConstantLong) c).getBytes())));
2105: else
2106: throw new UnsupportedOperationException(
2107: "Constant type not expected");
2108: }
2109:
2110: private void pushByLocalObjectLoad(DismantleBytecode dbc,
2111: int register) {
2112: Method m = dbc.getMethod();
2113: LocalVariableTable lvt = m.getLocalVariableTable();
2114: if (lvt != null) {
2115: LocalVariable lv = LVTHelper.getLocalVariableAtPC(lvt,
2116: register, dbc.getPC());
2117: if (lv != null) {
2118: String signature = lv.getSignature();
2119: pushByLocalLoad(signature, register);
2120: return;
2121: }
2122: }
2123: pushByLocalLoad("", register);
2124: }
2125:
2126: private void pushByIntMath(DismantleBytecode dbc, int seen,
2127: Item lhs, Item rhs) {
2128: Item newValue = new Item("I");
2129: if (lhs == null || rhs == null) {
2130: push(newValue);
2131: return;
2132: }
2133:
2134: try {
2135: if (DEBUG)
2136: System.out.println("pushByIntMath: "
2137: + rhs.getConstant() + " " + lhs.getConstant());
2138:
2139: if ((rhs.getConstant() != null)
2140: && lhs.getConstant() != null) {
2141: Integer lhsValue = (Integer) lhs.getConstant();
2142: Integer rhsValue = (Integer) rhs.getConstant();
2143: if (seen == IADD)
2144: newValue = new Item("I", lhsValue + rhsValue);
2145: else if (seen == ISUB)
2146: newValue = new Item("I", lhsValue - rhsValue);
2147: else if (seen == IMUL)
2148: newValue = new Item("I", lhsValue * rhsValue);
2149: else if (seen == IDIV)
2150: newValue = new Item("I", lhsValue / rhsValue);
2151: else if (seen == IAND) {
2152: newValue = new Item("I", lhsValue & rhsValue);
2153: if ((rhsValue & 0xff) == 0 && rhsValue != 0
2154: || (lhsValue & 0xff) == 0 && lhsValue != 0)
2155: newValue.specialKind = Item.LOW_8_BITS_CLEAR;
2156:
2157: } else if (seen == IOR)
2158: newValue = new Item("I", lhsValue | rhsValue);
2159: else if (seen == IXOR)
2160: newValue = new Item("I", lhsValue ^ rhsValue);
2161: else if (seen == ISHL) {
2162: newValue = new Item("I", lhsValue << rhsValue);
2163: if (rhsValue >= 8)
2164: newValue.specialKind = Item.LOW_8_BITS_CLEAR;
2165: } else if (seen == ISHR)
2166: newValue = new Item("I", lhsValue >> rhsValue);
2167: else if (seen == IREM)
2168: newValue = new Item("I", lhsValue % rhsValue);
2169: else if (seen == IUSHR)
2170: newValue = new Item("I", lhsValue >>> rhsValue);
2171: } else if (rhs.getConstant() != null && seen == ISHL
2172: && (Integer) rhs.getConstant() >= 8)
2173: newValue.specialKind = Item.LOW_8_BITS_CLEAR;
2174: else if (lhs.getConstant() != null && seen == IAND) {
2175: int value = (Integer) lhs.getConstant();
2176: if (value == 0)
2177: newValue = new Item("I", 0);
2178: else if ((value & 0xff) == 0)
2179: newValue.specialKind = Item.LOW_8_BITS_CLEAR;
2180: else if (value >= 0)
2181: newValue.specialKind = Item.NON_NEGATIVE;
2182: } else if (rhs.getConstant() != null && seen == IAND) {
2183: int value = (Integer) rhs.getConstant();
2184: if (value == 0)
2185: newValue = new Item("I", 0);
2186: else if ((value & 0xff) == 0)
2187: newValue.specialKind = Item.LOW_8_BITS_CLEAR;
2188: else if (value >= 0)
2189: newValue.specialKind = Item.NON_NEGATIVE;
2190: }
2191: } catch (ArithmeticException e) {
2192: assert true; // ignore it
2193: } catch (RuntimeException e) {
2194: String msg = "Error processing2 " + lhs
2195: + OPCODE_NAMES[seen] + rhs + " @ " + dbc.getPC()
2196: + " in " + dbc.getFullyQualifiedMethodName();
2197: AnalysisContext.logError(msg, e);
2198:
2199: }
2200: if (lhs.specialKind == Item.INTEGER_SUM
2201: && rhs.getConstant() != null) {
2202: int rhsValue = (Integer) rhs.getConstant();
2203: if (seen == IDIV && rhsValue == 2 || seen == ISHR
2204: && rhsValue == 1)
2205: newValue.specialKind = Item.AVERAGE_COMPUTED_USING_DIVISION;
2206: }
2207: if (seen == IADD && newValue.specialKind == 0
2208: && lhs.getConstant() == null
2209: && rhs.getConstant() == null)
2210: newValue.specialKind = Item.INTEGER_SUM;
2211: if (seen == IREM && lhs.specialKind == Item.HASHCODE_INT)
2212: newValue.specialKind = Item.HASHCODE_INT_REMAINDER;
2213: if (seen == IREM && lhs.specialKind == Item.RANDOM_INT)
2214: newValue.specialKind = Item.RANDOM_INT_REMAINDER;
2215: if (DEBUG)
2216: System.out.println("push: " + newValue);
2217: push(newValue);
2218: }
2219:
2220: private void pushByLongMath(int seen, Item lhs, Item rhs) {
2221: Item newValue = new Item("J");
2222: try {
2223:
2224: if ((rhs.getConstant() != null)
2225: && lhs.getConstant() != null) {
2226:
2227: Long lhsValue = ((Long) lhs.getConstant());
2228: if (seen == LSHL) {
2229: newValue = new Item("J", lhsValue << ((Number) rhs
2230: .getConstant()).intValue());
2231: if (((Number) rhs.getConstant()).intValue() >= 8)
2232: newValue.specialKind = Item.LOW_8_BITS_CLEAR;
2233: } else if (seen == LSHR)
2234: newValue = new Item("J", lhsValue >> ((Number) rhs
2235: .getConstant()).intValue());
2236: else if (seen == LUSHR)
2237: newValue = new Item("J", lhsValue >>> ((Number) rhs
2238: .getConstant()).intValue());
2239:
2240: else {
2241: Long rhsValue = ((Long) rhs.getConstant());
2242: if (seen == LADD)
2243: newValue = new Item("J", lhsValue + rhsValue);
2244: else if (seen == LSUB)
2245: newValue = new Item("J", lhsValue - rhsValue);
2246: else if (seen == LMUL)
2247: newValue = new Item("J", lhsValue * rhsValue);
2248: else if (seen == LDIV)
2249: newValue = new Item("J", lhsValue / rhsValue);
2250: else if (seen == LAND) {
2251: newValue = new Item("J", lhsValue & rhsValue);
2252: if ((rhsValue & 0xff) == 0 && rhsValue != 0
2253: || (lhsValue & 0xff) == 0
2254: && lhsValue != 0)
2255: newValue.specialKind = Item.LOW_8_BITS_CLEAR;
2256: } else if (seen == LOR)
2257: newValue = new Item("J", lhsValue | rhsValue);
2258: else if (seen == LXOR)
2259: newValue = new Item("J", lhsValue ^ rhsValue);
2260: else if (seen == LREM)
2261: newValue = new Item("J", lhsValue % rhsValue);
2262: }
2263: } else if (rhs.getConstant() != null && seen == LSHL
2264: && ((Integer) rhs.getConstant()) >= 8)
2265: newValue.specialKind = Item.LOW_8_BITS_CLEAR;
2266: else if (lhs.getConstant() != null && seen == LAND
2267: && (((Long) lhs.getConstant()) & 0xff) == 0)
2268: newValue.specialKind = Item.LOW_8_BITS_CLEAR;
2269: else if (rhs.getConstant() != null && seen == LAND
2270: && (((Long) rhs.getConstant()) & 0xff) == 0)
2271: newValue.specialKind = Item.LOW_8_BITS_CLEAR;
2272: } catch (RuntimeException e) {
2273: // ignore it
2274: }
2275: push(newValue);
2276: }
2277:
2278: private void pushByFloatMath(int seen, Item it, Item it2) {
2279: Item result;
2280: int specialKind = Item.FLOAT_MATH;
2281: if ((it.getConstant() instanceof Float)
2282: && it2.getConstant() instanceof Float) {
2283: if (seen == FADD)
2284: result = new Item("F", ((Float) it2.getConstant())
2285: + ((Float) it.getConstant()));
2286: else if (seen == FSUB)
2287: result = new Item("F", ((Float) it2.getConstant())
2288: - ((Float) it.getConstant()));
2289: else if (seen == FMUL)
2290: result = new Item("F", ((Float) it2.getConstant())
2291: * ((Float) it.getConstant()));
2292: else if (seen == FDIV)
2293: result = new Item("F", ((Float) it2.getConstant())
2294: / ((Float) it.getConstant()));
2295: else if (seen == FREM)
2296: result = new Item("F", ((Float) it2.getConstant())
2297: % ((Float) it.getConstant()));
2298: else
2299: result = new Item("F");
2300: } else {
2301: result = new Item("F");
2302: if (seen == DDIV)
2303: specialKind = Item.NASTY_FLOAT_MATH;
2304: }
2305: result.setSpecialKind(specialKind);
2306: push(result);
2307: }
2308:
2309: private void pushByDoubleMath(int seen, Item it, Item it2) {
2310: Item result;
2311: int specialKind = Item.FLOAT_MATH;
2312: if ((it.getConstant() instanceof Double)
2313: && it2.getConstant() instanceof Double) {
2314: if (seen == DADD)
2315: result = new Item("D", ((Double) it2.getConstant())
2316: + ((Double) it.getConstant()));
2317: else if (seen == DSUB)
2318: result = new Item("D", ((Double) it2.getConstant())
2319: - ((Double) it.getConstant()));
2320: else if (seen == DMUL)
2321: result = new Item("D", ((Double) it2.getConstant())
2322: * ((Double) it.getConstant()));
2323: else if (seen == DDIV)
2324: result = new Item("D", ((Double) it2.getConstant())
2325: / ((Double) it.getConstant()));
2326: else if (seen == DREM)
2327: result = new Item("D", ((Double) it2.getConstant())
2328: % ((Double) it.getConstant()));
2329: else
2330: result = new Item("D"); //?
2331: } else {
2332: result = new Item("D");
2333: if (seen == DDIV)
2334: specialKind = Item.NASTY_FLOAT_MATH;
2335: }
2336: result.setSpecialKind(specialKind);
2337: push(result);
2338: }
2339:
2340: private void pushByInvoke(DismantleBytecode dbc, boolean popThis) {
2341: String signature = dbc.getSigConstantOperand();
2342: pop(PreorderVisitor.getNumberArguments(signature)
2343: + (popThis ? 1 : 0));
2344: pushBySignature(Type.getReturnType(signature).getSignature());
2345: }
2346:
2347: private String getStringFromIndex(DismantleBytecode dbc, int i) {
2348: ConstantUtf8 name = (ConstantUtf8) dbc.getConstantPool()
2349: .getConstant(i);
2350: return name.getBytes();
2351: }
2352:
2353: private void pushBySignature(String s) {
2354: if ("V".equals(s))
2355: return;
2356: push(new Item(s, (Object) null));
2357: }
2358:
2359: private void pushByLocalStore(int register) {
2360: Item it = pop();
2361: if (it.getRegisterNumber() != register) {
2362: for (Item i : lvValues)
2363: if (i != null) {
2364: if (i.registerNumber == register)
2365: i.registerNumber = -1;
2366: if (i.fieldLoadedFromRegister == register)
2367: i.fieldLoadedFromRegister = -1;
2368: }
2369: for (Item i : stack)
2370: if (i != null) {
2371: if (i.registerNumber == register)
2372: i.registerNumber = -1;
2373: if (i.fieldLoadedFromRegister == register)
2374: i.fieldLoadedFromRegister = -1;
2375: }
2376: }
2377: setLVValue(register, it);
2378: }
2379:
2380: private void pushByLocalLoad(String signature, int register) {
2381: Item it = getLVValue(register);
2382:
2383: if (it == null) {
2384: Item item = new Item(signature);
2385: item.registerNumber = register;
2386: push(item);
2387: } else if (it.getRegisterNumber() >= 0)
2388: push(it);
2389: else {
2390: push(new Item(it, register));
2391: }
2392: }
2393:
2394: private void setLVValue(int index, Item value) {
2395: int addCount = index - lvValues.size() + 1;
2396: while ((addCount--) > 0)
2397: lvValues.add(null);
2398: if (!useIterativeAnalysis && seenTransferOfControl)
2399: value = Item.merge(value, lvValues.get(index));
2400: lvValues.set(index, value);
2401: }
2402:
2403: private Item getLVValue(int index) {
2404: if (index >= lvValues.size())
2405: return new Item();
2406:
2407: return lvValues.get(index);
2408: }
2409:
2410: /**
2411: * @param top The top to set.
2412: */
2413: private void setTop(boolean top) {
2414: if (top) {
2415: if (!this .top)
2416: this .top = true;
2417: } else if (this .top)
2418: this .top = false;
2419: }
2420:
2421: /**
2422: * @return Returns the top.
2423: */
2424: public boolean isTop() {
2425: if (top)
2426: return true;
2427: return false;
2428: }
2429:
2430: /**
2431: * @param reachOnlyByBranch The reachOnlyByBranch to set.
2432: */
2433: void setReachOnlyByBranch(boolean reachOnlyByBranch) {
2434: if (reachOnlyByBranch)
2435: setTop(true);
2436: this .reachOnlyByBranch = reachOnlyByBranch;
2437: }
2438:
2439: /**
2440: * @return Returns the reachOnlyByBranch.
2441: */
2442: boolean isReachOnlyByBranch() {
2443: return reachOnlyByBranch;
2444: }
2445: }
2446:
2447: // vim:ts=4
|