001: package org.hansel.stack;
002:
003: import java.util.Hashtable;
004: import java.util.SortedSet;
005: import java.util.TreeSet;
006:
007: public class StackFactory {
008: /* private Hashtable result;
009: private InstructionList il;
010: private SortedSet workList;
011: private MethodGen method;
012:
013: public StackFactory(MethodGen method) {
014: this.method = method;
015: this.result = new Hashtable();
016: this.il = method.getInstructionList();
017: this.workList = new TreeSet();
018:
019: SymbolicStack stack = new SymbolicStack(new MethodInfo(method));
020:
021: // Add emthod start
022: workList.add(new WorkListEntry(il.getStart(), stack));
023:
024: // Add exception handlers.
025: CodeExceptionGen[] ceg = method.getExceptionHandlers();
026:
027: for (int i=0; i<ceg.length; i++) {
028: ObjectType excType = new ObjectType("java.lang.Exception");
029: workList.add(new WorkListEntry(ceg[i].getHandlerPC(),
030: stack.push(new StackEntry("Exception",
031: excType))));
032: }
033: }
034:
035: public Hashtable getResult() {
036: return result;
037: }
038:
039: private void addWorkList(InstructionHandle ih, SymbolicStack stack) {
040: WorkListEntry entry = new WorkListEntry(ih, stack);
041: if (!workList.contains(entry)) {
042: workList.add(entry);
043: }
044: }
045:
046: public void calculateMethodStacks() {
047: try {
048: while (workList.size() > 0) {
049: WorkListEntry wle = (WorkListEntry) workList.first();
050: workList.remove(wle);
051:
052: // Execute instruction
053: calculateStackEntries(wle.getInstructionHandle(),
054: wle.getStack());
055:
056: }
057: } catch (NullPointerException e) {
058: logBugWarning(e);
059: } catch (UnsupportedOperationException e) {
060: logBugWarning(e);
061: } catch (EmptyStackException e) {
062: logBugWarning(e);
063: }
064: }
065:
066: private void logBugWarning(Exception e) {
067: System.out.println("WARNING: Found bug while decompiling expression.");
068: System.out.println("This does not change the coverage results.");
069: System.out.println("Class: " + method.getClassName());
070: System.out.println("Method: " + method);
071: System.out.println("Method-Bytecode: " + method.getMethod().getCode());
072: System.out.println("Please report this bug (including the following stacktrace and the compiler you are using)"
073: + " at \n http://sourceforge.net/tracker/?group_id=54171&atid=472899");
074: e.printStackTrace();
075: }
076:
077: private int available(InstructionHandle ih) {
078: int available = 0;
079: while (ih != null) {
080: available++;
081: ih = ih.getNext();
082: }
083:
084: return available;
085: }
086:
087: private boolean isComplexOperator(InstructionHandle[] instrs) {
088: if (!((instrs[1].getInstruction() instanceof ICONST) &&
089: (instrs[2].getInstruction() instanceof GOTO) &&
090: (instrs[3].getInstruction() instanceof ICONST))) {
091: return false;
092: }
093:
094: int value1 = ((ICONST) instrs[1].getInstruction()).getValue().intValue();
095: int value2 = ((ICONST) instrs[3].getInstruction()).getValue().intValue();
096:
097: if ((value1 != 1) || (value2 != 0)) {
098: return false;
099: }
100:
101: if (((IfInstruction) instrs[0].getInstruction()).getTarget() != instrs[3]) {
102: return false;
103: }
104:
105: if (((GOTO) instrs[2].getInstruction()).getTarget() != instrs[4]) {
106: return false;
107: }
108:
109: return true;
110: }
111:
112: private boolean isComplexOperator2(InstructionHandle[] instrs) {
113: if (!((instrs[1].getInstruction() instanceof ICONST) &&
114: (instrs[2].getInstruction() instanceof GOTO) &&
115: (instrs[3].getInstruction() instanceof ICONST))) {
116: return false;
117: }
118:
119: int value1 = ((ICONST) instrs[1].getInstruction()).getValue().intValue();
120: int value2 = ((ICONST) instrs[3].getInstruction()).getValue().intValue();
121:
122: if ((value1 != 0) || (value2 != 1)) {
123: return false;
124: }
125:
126: if (((IfInstruction) instrs[0].getInstruction()).getTarget() != instrs[3]) {
127: return false;
128: }
129:
130: if (((GOTO) instrs[2].getInstruction()).getTarget() != instrs[4]) {
131: return false;
132: }
133:
134: return true;
135: }
136:
137: private void checkComplexOperator(SymbolicStack stack,
138: InstructionHandle ih) {
139: if (!(ih.getInstruction() instanceof IfInstruction)) {
140: return;
141: }
142:
143: if (available(ih) <= 5) {
144: return;
145: }
146:
147: // Special case: Sometimes the compiler translates
148: // boolean arithmetic into a complex set of instructions.
149: // For example !(expression) is translated as
150: // 1: aconst_0
151: // 2: [calculate expression]
152: // 3: ifeq 6
153: // 4: iconst_0
154: // 5: goto 7
155: // 6: iconst_1
156: // 7: following code
157: // This code tries to find these code fragments
158: // and generate the correct stack.
159: InstructionHandle[] instructions = new InstructionHandle[5];
160: instructions[0] = ih;
161: for (int i=1; i<instructions.length; i++) {
162: instructions[i] = instructions[i-1].getNext();
163: }
164:
165: if (isComplexOperator(instructions)) {
166: StackEntry newEntry = new ComplexOr(instructions[1],
167: result,
168: il).getStackEntry();
169:
170: SymbolicStack newStack = stack;
171: int consume = ((IfInstruction) ih.getInstruction()).consumeStack(null);
172: for (int i=0; i<consume; i++) {
173: newStack = newStack.pop();
174: }
175:
176: newStack = newStack.push(newEntry);
177: addWorkList(instructions[4], newStack);
178: }
179: else if (isComplexOperator2(instructions)) {
180: StackEntry newEntry = new ComplexOr(instructions[1],
181: result,
182: il).getStackEntry();
183: newEntry = new NotOp(newEntry);
184:
185: SymbolicStack newStack = stack;
186: int consume = ((IfInstruction) ih.getInstruction()).consumeStack(null);
187: for (int i=0; i<consume; i++) {
188: newStack = newStack.pop();
189: }
190:
191: newStack = newStack.push(newEntry);
192: addWorkList(instructions[4], newStack);
193: }
194: }
195:
196: private void calculateStackEntries(InstructionHandle ih,
197: SymbolicStack stack) {
198: if (result.containsKey(ih)) {
199: // Nothing to do
200: return;
201: } else {
202: result.put(ih, stack);
203: }
204:
205: // Try to resolve complex operators.
206: checkComplexOperator(stack, ih);
207:
208: // Special treatment for jsr, because continueing in the current
209: // execution thread and jumping to the subroutine is handled
210: // differently
211: if (ih.getInstruction() instanceof JsrInstruction) {
212: JsrInstruction jsr = (JsrInstruction) ih.getInstruction();
213: addWorkList(jsr.getTarget(),
214: stack.emptyStack().push(new StackEntry("ReturnAddr",
215: Type.UNKNOWN)));
216: }
217:
218: // Calculate new stack
219: SymbolicStack newStack = null;
220:
221: try {
222: newStack = stack.executeInstruction(ih.getInstruction());
223: } catch (EmptyStackException e) {
224: throw new EmptyStackException("When executing: " + ih.toString());
225: }
226:
227: // Execute all possible paths
228: InstructionHandle[] followUp = getFollowUpInstr(ih);
229: for (int i=0; i<followUp.length; i++) {
230: addWorkList(followUp[i], newStack);
231: }
232: }
233:
234: private InstructionHandle[] getFollowUpInstr(InstructionHandle ih) {
235: Instruction instr = ih.getInstruction();
236:
237: if (instr instanceof Select) {
238: InstructionHandle[] targets = ((Select) instr).getTargets();
239: InstructionHandle[] result = new InstructionHandle[targets.length + 1];
240: System.arraycopy(targets, 0, result, 0, targets.length);
241: result[result.length - 1] = ((Select) instr).getTarget();
242: return result;
243: } else if (instr instanceof IfInstruction) {
244: BranchInstruction bi = ((BranchInstruction) instr);
245:
246: return new InstructionHandle[] {ih.getNext(),
247: bi.getTarget()};
248: } else if (instr instanceof GotoInstruction) {
249: BranchInstruction bi = ((BranchInstruction) instr);
250: return new InstructionHandle[] {bi.getTarget()};
251: } else if ((instr instanceof ReturnInstruction) ||
252: (instr instanceof RET) ||
253: (instr instanceof ATHROW)) {
254: return new InstructionHandle[0];
255: }
256:
257: return new InstructionHandle[] {ih.getNext()};
258: }
259:
260: private class WorkListEntry implements Comparable {
261: private InstructionHandle ih;
262: private SymbolicStack stack;
263:
264: public WorkListEntry(InstructionHandle ih, SymbolicStack stack) {
265: this.ih = ih;
266: this.stack = stack;
267: }
268:
269: public int compareTo(Object o) {
270: return ih.getPosition() - ((WorkListEntry) o).ih.getPosition();
271: }
272:
273: public boolean equals(Object o) {
274: return ih == ((WorkListEntry) o).ih;
275: }
276:
277: public InstructionHandle getInstructionHandle() {
278: return ih;
279: }
280:
281: public SymbolicStack getStack() {
282: return stack;
283: }
284: }*/
285: }
|