001: package org.hansel;
002:
003: import java.util.Iterator;
004: import java.util.List;
005:
006: import org.hansel.stack.BinaryOperatorEntry;
007: import org.hansel.stack.HanselValue;
008: import org.hansel.stack.PrefixOpEntry;
009: import org.objectweb.asm.Opcodes;
010: import org.objectweb.asm.Type;
011: import org.objectweb.asm.tree.AbstractInsnNode;
012: import org.objectweb.asm.tree.FieldInsnNode;
013: import org.objectweb.asm.tree.IntInsnNode;
014: import org.objectweb.asm.tree.LdcInsnNode;
015: import org.objectweb.asm.tree.LocalVariableNode;
016: import org.objectweb.asm.tree.MethodInsnNode;
017: import org.objectweb.asm.tree.MultiANewArrayInsnNode;
018: import org.objectweb.asm.tree.TypeInsnNode;
019: import org.objectweb.asm.tree.VarInsnNode;
020: import org.objectweb.asm.tree.analysis.SourceInterpreter;
021: import org.objectweb.asm.tree.analysis.Value;
022:
023: public final class HanselInterpreter extends SourceInterpreter {
024: private static final int PRECEDENCE_CAST = 1;
025: private static final int PRECEDENCE_UNARY_MINUS = 1;
026: private static final int PRECEDENCE_MUL = 2;
027: private static final int PRECEDENCE_ADD = 3;
028: private static final int PRECEDENCE_SHIFT = 4;
029: private static final int PRECEDENCE_INSTANCEOF = 5;
030: private static final int PRECEDENCE_COMPARE = 5;
031: private static final int PRECEDENCE_AND = 7;
032: private static final int PRECEDENCE_XOR = 8;
033: private static final int PRECEDENCE_OR = 9;
034: //private InsnList instructions;
035: private List localVariables;
036:
037: /** Creates a new instance of HanselInterpreter */
038: public HanselInterpreter(
039: /*InsnList instructions, */List localVariables) {
040: //this.instructions = instructions;
041: this .localVariables = localVariables;
042: //System.out.println("LocalVars: " + localVariables);
043: }
044:
045: public Value binaryOperation(AbstractInsnNode insn, Value value1,
046: Value value2) {
047: switch (insn.getOpcode()) {
048: case Opcodes.PUTFIELD:
049: case Opcodes.IF_ICMPEQ:
050: case Opcodes.IF_ICMPNE:
051: case Opcodes.IF_ICMPLT:
052: case Opcodes.IF_ICMPGE:
053: case Opcodes.IF_ICMPGT:
054: case Opcodes.IF_ICMPLE:
055: case Opcodes.IF_ACMPEQ:
056: case Opcodes.IF_ACMPNE:
057: return null;
058: case Opcodes.LALOAD:
059: case Opcodes.DALOAD:
060: return new HanselValue(value1 + "[" + value2 + "]", false,
061: 2);
062:
063: case Opcodes.IALOAD:
064: case Opcodes.FALOAD:
065: case Opcodes.AALOAD:
066: case Opcodes.CALOAD:
067: case Opcodes.SALOAD:
068: return new HanselValue(value1 + "[" + value2 + "]", false,
069: 1);
070: case Opcodes.BALOAD:
071: return new HanselValue(value1 + "[" + value2 + "]", true, 1);
072: case Opcodes.IADD:
073: case Opcodes.LADD:
074: case Opcodes.FADD:
075: case Opcodes.DADD:
076: return new BinaryOperatorEntry("+", PRECEDENCE_ADD, value1,
077: value2);
078: case Opcodes.ISUB:
079: case Opcodes.LSUB:
080: case Opcodes.FSUB:
081: case Opcodes.DSUB:
082: return new BinaryOperatorEntry("-", PRECEDENCE_ADD, value1,
083: value2);
084: case Opcodes.IMUL:
085: case Opcodes.LMUL:
086: case Opcodes.FMUL:
087: case Opcodes.DMUL:
088: return new BinaryOperatorEntry("*", PRECEDENCE_MUL, value1,
089: value2);
090: case Opcodes.IDIV:
091: case Opcodes.LDIV:
092: case Opcodes.FDIV:
093: case Opcodes.DDIV:
094: return new BinaryOperatorEntry("/", PRECEDENCE_MUL, value1,
095: value2);
096: case Opcodes.IREM:
097: case Opcodes.LREM:
098: case Opcodes.FREM:
099: case Opcodes.DREM:
100: return new BinaryOperatorEntry("%", PRECEDENCE_MUL, value1,
101: value2);
102: case Opcodes.ISHL:
103: case Opcodes.LSHL:
104: return new BinaryOperatorEntry("<<", PRECEDENCE_SHIFT,
105: value1, value2);
106: case Opcodes.ISHR:
107: case Opcodes.LSHR:
108: case Opcodes.IUSHR:
109: case Opcodes.LUSHR:
110: return new BinaryOperatorEntry(">>", PRECEDENCE_SHIFT,
111: value1, value2);
112: case Opcodes.IAND:
113: case Opcodes.LAND:
114: return new BinaryOperatorEntry("&", PRECEDENCE_AND, value1,
115: value2);
116: case Opcodes.IOR:
117: case Opcodes.LOR:
118: return new BinaryOperatorEntry("|", PRECEDENCE_OR, value1,
119: value2);
120: case Opcodes.IXOR:
121: case Opcodes.LXOR:
122: return new BinaryOperatorEntry("^", PRECEDENCE_XOR, value1,
123: value2);
124: case Opcodes.LCMP:
125: case Opcodes.FCMPL:
126: case Opcodes.FCMPG:
127: case Opcodes.DCMPL:
128: case Opcodes.DCMPG:
129: return new BinaryOperatorEntry("<", PRECEDENCE_COMPARE,
130: value1, value2, 1);
131:
132: default:
133: throw failure(insn);
134: }
135: }
136:
137: private HanselValue findLocalVar(int index, AbstractInsnNode insn) {
138: Iterator it = localVariables.iterator();
139: //int insnIndex = instructions.indexOf(insn);
140:
141: while (it.hasNext()) {
142: LocalVariableNode lvn = (LocalVariableNode) it.next();
143:
144: // TODO: FixMe....
145: if ((lvn.index == index) /*&&
146: (insnIndex > instructions.indexOf(lvn.start)) &&
147: (insnIndex < instructions.indexOf(lvn.end))*/) {
148: //System.err.println("Returning local var for: " + index + " " + lvn.desc + " " + getSize(lvn.desc));
149: return new HanselValue(lvn.name, isBool(lvn.desc),
150: getSize(lvn.desc));
151: }
152: }
153:
154: return new HanselValue("Unknown local: " + index, false, 1);
155: }
156:
157: private int getSize(String desc) {
158: return Type.getType(desc).getSize();
159: }
160:
161: private boolean isBool(String desc) {
162: return isBool(Type.getType(desc));
163: }
164:
165: private boolean isBool(Type type) {
166: return type.equals(Type.BOOLEAN_TYPE);
167: }
168:
169: public Value copyOperation(AbstractInsnNode insn, Value value) {
170: if (insn instanceof VarInsnNode) {
171: return findLocalVar(((VarInsnNode) insn).var, insn);
172: }
173:
174: switch (insn.getOpcode()) {
175: case Opcodes.DUP:
176: case Opcodes.DUP_X1:
177: case Opcodes.DUP_X2:
178: case Opcodes.DUP2:
179: case Opcodes.DUP2_X1:
180: case Opcodes.DUP2_X2:
181: case Opcodes.SWAP:
182: return value;
183:
184: case Opcodes.ISTORE:
185: case Opcodes.LSTORE:
186: case Opcodes.FSTORE:
187: case Opcodes.DSTORE:
188: case Opcodes.ASTORE:
189: return HanselValue.DONT_CARE;
190: default:
191: throw failure(insn);
192: }
193: }
194:
195: public Value merge(Value v, Value w) {
196: return v;
197: }
198:
199: private HanselValue multiANewArray(MultiANewArrayInsnNode node,
200: List values) {
201: String result = node.desc;
202:
203: for (int i = 0; i < values.size(); i++) {
204: result += "[" + values.get(i) + "]";
205: }
206:
207: return new HanselValue(result, false, 1);
208: }
209:
210: private HanselValue invokeMethod(MethodInsnNode node, List values) {
211: String result = "";
212: int start = 0;
213:
214: if (node.getOpcode() != Opcodes.INVOKESTATIC) {
215: start = 1;
216: result = values.get(0) + ".";
217: }
218:
219: result += node.name + "(";
220: for (int i = start; i < values.size(); i++) {
221: result += values.get(i);
222: if (i != values.size() - 1) {
223: result += ", ";
224: }
225: }
226:
227: return new HanselValue(result + ")", isBool(Type
228: .getReturnType(node.desc)), Type.getReturnType(
229: node.desc).getSize());
230: }
231:
232: public Value naryOperation(AbstractInsnNode insn, List values) {
233:
234: switch (insn.getOpcode()) {
235: case Opcodes.INVOKESPECIAL:
236: case Opcodes.INVOKEVIRTUAL:
237: case Opcodes.INVOKEINTERFACE:
238: case Opcodes.INVOKESTATIC:
239: return invokeMethod((MethodInsnNode) insn, values);
240: case Opcodes.MULTIANEWARRAY:
241: return multiANewArray((MultiANewArrayInsnNode) insn, values);
242:
243: default:
244: throw failure(insn);
245: }
246: }
247:
248: private IllegalStateException failure(AbstractInsnNode insn) {
249: Thread.dumpStack();
250: return new IllegalStateException("Unknown instruction: "
251: + insn.getOpcode() + " " + insn + " (Class: "
252: + insn.getClass() + ")");
253: }
254:
255: public Value newOperation(AbstractInsnNode insn) {
256: switch (insn.getOpcode()) {
257: case Opcodes.ACONST_NULL:
258: return HanselValue.NULL;
259: case Opcodes.LCONST_0:
260: return HanselValue.ZERO_2;
261: case Opcodes.LCONST_1:
262: return HanselValue.ONE_2;
263: case Opcodes.FCONST_0:
264: return HanselValue.ZERO_1;
265: case Opcodes.FCONST_1:
266: return HanselValue.ONE_1;
267: case Opcodes.FCONST_2:
268: return new HanselValue("2", false, 1);
269: case Opcodes.DCONST_0:
270: return HanselValue.ZERO_2;
271: case Opcodes.DCONST_1:
272: return HanselValue.ONE_1;
273: case Opcodes.ICONST_M1:
274: return new HanselValue("-1", false, 1);
275: case Opcodes.ICONST_0:
276: return HanselValue.ZERO_1;
277: case Opcodes.ICONST_1:
278: return HanselValue.ONE_1;
279: case Opcodes.ICONST_2:
280: return new HanselValue("2", false, 1);
281: case Opcodes.ICONST_3:
282: return new HanselValue("3", false, 1);
283: case Opcodes.ICONST_4:
284: return new HanselValue("4", false, 1);
285: case Opcodes.ICONST_5:
286: return new HanselValue("5", false, 1);
287: case Opcodes.BIPUSH:
288: case Opcodes.SIPUSH:
289: return new HanselValue(String
290: .valueOf(((IntInsnNode) insn).operand), false, 1);
291: case Opcodes.LDC:
292: return formatLDC(((LdcInsnNode) insn).cst);
293: case Opcodes.GETSTATIC:
294: return new HanselValue(((FieldInsnNode) insn).name,
295: isBool(((FieldInsnNode) insn).desc),
296: getSize((((FieldInsnNode) insn).desc)));
297: case Opcodes.JSR:
298: return HanselValue.DONT_CARE;
299: case Opcodes.NEW:
300: return new HanselValue("new " + ((TypeInsnNode) insn).desc
301: + "()", false, 1);
302: default:
303: throw failure(insn);
304: }
305: }
306:
307: private HanselValue formatLDC(Object cst) {
308: if (cst instanceof Type) {
309: Type t = (Type) cst;
310: if (t.getSort() == Type.OBJECT) {
311: String result = t.getClassName();
312: if (result.indexOf('.') > -1) {
313: return new HanselValue(result.substring(result
314: .lastIndexOf('.') + 1)
315: + ".class", false, 1);
316: }
317: }
318: }
319:
320: if ((cst instanceof Double) || (cst instanceof Long)) {
321: return new HanselValue(cst.toString(), false, 2);
322: } else if (cst instanceof String) {
323: return new HanselValue("\"" + cst.toString() + "\"", false,
324: 1);
325: } else {
326: return new HanselValue(cst.toString(), false, 1);
327: }
328: }
329:
330: public Value newValue(Type type) {
331: return HanselValue.DONT_CARE;
332: }
333:
334: public Value ternaryOperation(AbstractInsnNode insn, Value value1,
335: Value value2, Value value3) {
336: switch (insn.getOpcode()) {
337: case Opcodes.AASTORE:
338: case Opcodes.IASTORE:
339: case Opcodes.LASTORE:
340: case Opcodes.FASTORE:
341: case Opcodes.DASTORE:
342: case Opcodes.BASTORE:
343: case Opcodes.CASTORE:
344: case Opcodes.SASTORE:
345: return HanselValue.DONT_CARE;
346: default:
347: throw failure(insn);
348: }
349: }
350:
351: public Value unaryOperation(AbstractInsnNode insn, Value value) {
352: switch (insn.getOpcode()) {
353: case Opcodes.ATHROW:
354: case Opcodes.MONITORENTER:
355: case Opcodes.MONITOREXIT:
356: case Opcodes.IFNULL:
357: case Opcodes.IFNONNULL:
358: case Opcodes.IFEQ:
359: case Opcodes.IFNE:
360: case Opcodes.IFLT:
361: case Opcodes.IFGE:
362: case Opcodes.IFGT:
363: case Opcodes.IFLE:
364: case Opcodes.TABLESWITCH:
365: case Opcodes.LOOKUPSWITCH:
366: case Opcodes.IRETURN:
367: case Opcodes.LRETURN:
368: case Opcodes.FRETURN:
369: case Opcodes.DRETURN:
370: case Opcodes.ARETURN:
371: case Opcodes.PUTSTATIC:
372: // Value is not needed.
373: return null;
374: case Opcodes.IINC:
375: return HanselValue.DONT_CARE;
376: case Opcodes.INEG:
377: case Opcodes.LNEG:
378: case Opcodes.FNEG:
379: case Opcodes.DNEG:
380: return new PrefixOpEntry("-", PRECEDENCE_UNARY_MINUS,
381: (HanselValue) value);
382: case Opcodes.I2L:
383: case Opcodes.F2L:
384: case Opcodes.D2L:
385: return new PrefixOpEntry("(long)", PRECEDENCE_CAST,
386: (HanselValue) value, 2);
387: case Opcodes.I2F:
388: case Opcodes.L2F:
389: case Opcodes.D2F:
390: return new PrefixOpEntry("(float)", PRECEDENCE_CAST,
391: (HanselValue) value, 1);
392: case Opcodes.I2D:
393: case Opcodes.L2D:
394: case Opcodes.F2D:
395: return new PrefixOpEntry("(double)", PRECEDENCE_CAST,
396: (HanselValue) value, 2);
397: case Opcodes.L2I:
398: case Opcodes.F2I:
399: case Opcodes.D2I:
400: return new PrefixOpEntry("(int)", PRECEDENCE_CAST,
401: (HanselValue) value, 1);
402: case Opcodes.I2B:
403: return new PrefixOpEntry("(boolean)", PRECEDENCE_CAST,
404: (HanselValue) value, 1);
405: case Opcodes.I2C:
406: return new PrefixOpEntry("(char)", PRECEDENCE_CAST,
407: (HanselValue) value, 1);
408: case Opcodes.I2S:
409: return new PrefixOpEntry("(short)", PRECEDENCE_CAST,
410: (HanselValue) value, 1);
411: case Opcodes.INSTANCEOF:
412: return new BinaryOperatorEntry("instanceof",
413: PRECEDENCE_INSTANCEOF, (HanselValue) value,
414: new HanselValue(((TypeInsnNode) insn).desc, false,
415: 1), 1);
416: case Opcodes.NEWARRAY:
417: return new HanselValue("new "
418: + getType(((IntInsnNode) insn).operand) + "["
419: + value + "]", false, 1);
420: case Opcodes.ANEWARRAY:
421: return new HanselValue("new " + ((TypeInsnNode) insn).desc
422: + "[" + value + "]", false, 1);
423: case Opcodes.ARRAYLENGTH:
424: return new HanselValue(value + ".length", false, 1);
425: case Opcodes.CHECKCAST:
426: return new PrefixOpEntry("(" + ((TypeInsnNode) insn).desc
427: + ")", PRECEDENCE_CAST, (HanselValue) value, 1);
428: case Opcodes.GETFIELD:
429: return new HanselValue("this."
430: + ((FieldInsnNode) insn).name,
431: isBool(((FieldInsnNode) insn).desc),
432: getSize(((FieldInsnNode) insn).desc));
433:
434: default:
435: throw failure(insn);
436: }
437: }
438:
439: /**
440: * Returns name of primitiv type for operand of newarray.
441: */
442: private String getType(int operand) {
443: switch (operand) {
444: case 4:
445: return "boolean";
446: case 5:
447: return "char";
448: case 6:
449: return "float";
450: case 7:
451: return "double";
452: case 8:
453: return "byte";
454: case 9:
455: return "short";
456: case 10:
457: return "int";
458: case 11:
459: return "long";
460: default:
461: throw new IllegalArgumentException(
462: "Unknown type of newarray: " + operand);
463: }
464: }
465:
466: }
|