package jode; import sun.tools.java.*; import java.lang.reflect.Modifier; import java.util.*; import java.io.*; public class CodeAnalyzer implements Analyzer, Constants { BinaryCode bincode; MethodInstructionHeader methodHeader; int[] references; Hashtable tryAddrs = new Hashtable(); Hashtable catchAddrs = new Hashtable(); Hashtable labels = new Hashtable(); MethodAnalyzer method; public JodeEnvironment env; /** * Get the method. * @return The method to which this code belongs. */ public MethodAnalyzer getMethod() {return method;} void readCode(byte[] code) throws ClassFormatError { InstructionHeader[] instr = new InstructionHeader[code.length]; int returnCount; try { DataInputStream stream = new DataInputStream(new ByteArrayInputStream(code)); for (int addr = 0; addr < code.length; ) { instr[addr] = Opcodes.readOpcode(addr, stream, this); addr = instr[addr].getNextAddr(); } } catch (IOException ex) { throw new ClassFormatError(ex.toString()); } methodHeader = new MethodInstructionHeader(instr); } void setExceptionHandler(BinaryExceptionHandler handler) { /* tryAddrs.put(new Integer(handler.startPC), handler); references[handler.startPC]++; catchAddrs.put(new Integer(handler.handlerPC), handler); references[handler.handlerPC]++; */ } /* Instruction getInstruction(int addr) { return instr[addr]; } void setInstruction(int addr, Instruction i) { instr[addr] = i; } void removeInstruction(int addr) { instr[addr] = null; } */ static int WRONG = -3; static int SPECIAL = -2; static int FIRST = -1; int getPreviousAddr(int addr) { /* int i; for (i = addr-1; i >= 0 && instr[i] == null; i--) {} return i; */ return addr; } int getNextAddr(int addr) { /* return addr + instr[addr].getLength(); */ return addr; } int getPredecessor(int addr) { /* if (references[addr] != 1) return WRONG; if (addr == 0) return FIRST; if (catchAddrs.get(new Integer(addr)) != null) return SPECIAL; int i = getPreviousAddr(addr); if (instr[i].getLength() != addr-i) throw new RuntimeException("length mismatch"); int[] successors = instr[i].getSuccessors(); for (int j=0; j< successors.length; j++) { if (successors[j] == addr) return i; } */ return WRONG; } public void dumpSource(TabbedPrintWriter writer) throws java.io.IOException { InstructionHeader ih; for (ih = methodHeader.getNextInstruction(); ih != null; ih = ih.getNextInstruction()) { ih.dumpSource(writer); } } public CodeAnalyzer(MethodAnalyzer ma, BinaryCode bc, JodeEnvironment e) throws ClassFormatError { method = ma; env = e; bincode = bc; readCode(bincode.getCode()); BinaryExceptionHandler[] handlers = bincode.getExceptionHandlers(); for (int i=0; i 0) { ih = ih.getUniquePredecessor(); ArrayStoreOperator store2 = (ArrayStoreOperator) ih.getInstruction(); ih = ih.getUniquePredecessor(); lastconst = (Expression) ih.getInstruction(); ih = ih.getUniquePredecessor(); Expression indexexpr = (Expression) ih.getInstruction(); ConstOperator indexop = (ConstOperator) indexexpr.getOperator(); if (!MyType.isOfType(indexop.getType(), MyType.tUInt)) return null; int index = Integer.parseInt(indexop.getValue()); if (index > lastindex) return null; while (index < lastindex) { consts[lastindex] = new Expression (new ConstOperator(MyType.tUnknown, ""), new Expression[0]); lastindex--; } consts[lastindex] = lastconst; ih = ih.getUniquePredecessor(); dup = (DupOperator) ih.getInstruction(); if (dup.getDepth() != 0 || dup.getCount() != store.getLValueType().stackSize()) return null; count++; } ih = ih.getUniquePredecessor(); Expression newArrayExpr = (Expression) ih.getInstruction(); NewArrayOperator newArrayOp = (NewArrayOperator) newArrayExpr.getOperator(); type = newArrayOp.getType(); if (newArrayOp.getOperandCount() != 1) return null; Expression countexpr = (Expression) newArrayExpr.getSubExpressions()[0]; ConstOperator countop = (ConstOperator) countexpr.getOperator(); if (!MyType.isOfType(countop.getType(), MyType.tUInt)) return null; if (Integer.parseInt(countop.getValue()) != consts.length) return null; } catch (NullPointerException ex) { return null; } catch (ClassCastException ex) { return null; } Operator op = new ConstantArrayOperator(type, consts.length); ih.combine(4*count+1, new Expression(op, consts)); return ih; } public InstructionHeader createExpression(InstructionHeader ih) { Operator op; Expression exprs[]; int count; try { op = (Operator) ih.getInstruction(); int params = op.getOperandCount(); exprs = new Expression[params]; count = 1; for (int i = params-1; i>=0; i--) { count++; ih = ih.getUniquePredecessor(); exprs[i] = (Expression) ih.getInstruction(); if (exprs[i].isVoid()) { if (i == params-1) return null; Expression e = exprs[i+1].tryToCombine(exprs[i]); if (e == null) return null; i++; exprs[i] = e; } } } catch (NullPointerException ex) { return null; } catch (ClassCastException ex) { return null; } ih.combine(count, new Expression(op, exprs)); return ih; } // public int combineExpressions(int addr) { // int count = 0; // int start = addr; // if (!(instr[addr] instanceof Expression) || // !((Expression)instr[addr]).isVoid()) // return -1; // do { // addr = getNextAddr(addr); // count++; // } while (addr < instr.length && // references[addr] == 1 && // instr[addr] instanceof Expression && // ((Expression)instr[addr]).isVoid()); // Expression[] expr = new Expression[count]; // addr = start; // for (int i=0; i < count; i++) { // expr[i] = (Expression)instr[addr]; // int next = getNextAddr(addr); // instr[addr] = null; // addr = next; // } // instr[start] = new Block(start, addr-start, expr); // return start; // } public InstructionHeader createAssignExpression(InstructionHeader ih) { StoreInstruction store; try { store = (StoreInstruction) ih.getInstruction(); ih = ih.getUniquePredecessor(); DupOperator dup = (DupOperator) ih.getInstruction(); if (dup.getDepth() != store.getLValueOperandCount() && dup.getCount() != store.getLValueType().stackSize()) return null; } catch (NullPointerException ex) { return null; } catch (ClassCastException ex) { return null; } ih.combine(2, new AssignOperator(Operator.ASSIGN_OP, store)); return ih; } public InstructionHeader createLocalPostIncExpression(InstructionHeader ih) { IIncOperator iinc; int op; Type type; try { Expression iincExpr = (Expression) ih.getInstruction(); iinc = (IIncOperator) iincExpr.getOperator(); if (iinc.getOperator() == iinc.ADD_OP + iinc.OPASSIGN_OP) op = Operator.INC_OP; else if (iinc.getOperator() == iinc.NEG_OP + iinc.OPASSIGN_OP) op = Operator.DEC_OP; else return null; if (!iinc.getValue().equals("1") && !iinc.getValue().equals("-1")) return null; if (iinc.getValue().equals("-1")) op ^= 1; ih = ih.getUniquePredecessor(); Expression loadExpr = (Expression) ih.getInstruction(); LocalLoadOperator load = (LocalLoadOperator)loadExpr.getOperator(); if (!iinc.matches(load)) return null; type = MyType.intersection(load.getType(), MyType.tUInt); } catch (NullPointerException ex) { return null; } catch (ClassCastException ex) { return null; } Operator postop = new LocalPostFixOperator(type, op, iinc); ih.combine(2, postop); return ih; } public InstructionHeader createPostIncExpression(InstructionHeader ih) { StoreInstruction store; int op; Type type; try { store = (StoreInstruction) ih.getInstruction(); if (store.getLValueOperandCount() == 0) return null; ih = ih.getUniquePredecessor(); BinaryOperator binOp = (BinaryOperator) ih.getInstruction(); if (binOp.getOperator() == store.ADD_OP) op = Operator.INC_OP; else if (store.getOperator() == store.NEG_OP) op = Operator.DEC_OP; else return null; ih = ih.getUniquePredecessor(); Expression expr = (Expression) ih.getInstruction(); ConstOperator constOp = (ConstOperator) expr.getOperator(); if (!constOp.getValue().equals("1") && !constOp.getValue().equals("-1")) return null; if (constOp.getValue().equals("-1")) op ^= 1; ih = ih.getUniquePredecessor(); DupOperator dup = (DupOperator) ih.getInstruction(); if (dup.getCount() != store.getLValueType().stackSize() || dup.getDepth() != store.getLValueOperandCount()) return null; ih = ih.getUniquePredecessor(); Operator load = (Operator) ih.getInstruction(); if (!store.matches(load)) return null; ih = ih.getUniquePredecessor(); DupOperator dup2 = (DupOperator) ih.getInstruction(); if (dup2.getCount() != store.getLValueOperandCount() || dup2.getDepth() != 0) return null; type = MyType.intersection(load.getType(), store.getLValueType()); } catch (NullPointerException ex) { return null; } catch (ClassCastException ex) { return null; } Operator postop = new PostFixOperator(type, op, store); ih.combine(6, postop); return ih; } public InstructionHeader createAssignOp(InstructionHeader ih) { Expression rightHandSide; StoreInstruction store; BinaryOperator binop; try { store = (StoreInstruction) ih.getInstruction(); ih = ih.getUniquePredecessor(); binop = (BinaryOperator) ih.getInstruction(); if (binop.getOperator() < binop.ADD_OP || binop.getOperator() >= binop.ASSIGN_OP) return null; ih = ih.getUniquePredecessor(); rightHandSide = (Expression) ih.getInstruction(); if (rightHandSide.isVoid()) return null; /* XXX */ ih = ih.getUniquePredecessor(); Operator load = (Operator) ih.getInstruction(); if (!store.matches(load)) return null; ih = ih.getUniquePredecessor(); DupOperator dup = (DupOperator) ih.getInstruction(); if (dup.getDepth() != 0 && dup.getCount() != store.getLValueOperandCount()) return null; } catch (ClassCastException ex) { return null; } catch (NullPointerException ex) { return null; } ih.combine(3, rightHandSide); InstructionHeader storeIH = ih.getNextInstruction(); store.setOperator(store.OPASSIGN_OP+binop.getOperator()); store.setLValueType(MyType.intersection(binop.getType(), store.getLValueType())); storeIH.combine(2, store); return ih; } public InstructionHeader combineNewConstructor(InstructionHeader ih) { InvokeOperator constrCall; Expression exprs[]; try { constrCall = (InvokeOperator) ih.getInstruction(); if (!constrCall.isConstructor()) return null; int params = constrCall.getOperandCount(); exprs = new Expression[params]; for (int i = params-1; i>0; i--) { ih = ih.getUniquePredecessor(); exprs[i] = (Expression) ih.getInstruction(); if (exprs[i].isVoid()) return null; /* XXX */ } ih = ih.getUniquePredecessor(); DupOperator dup = (DupOperator) ih.getInstruction(); if (dup.getCount() != 1 && dup.getDepth() != 0) return null; ih = ih.getUniquePredecessor(); exprs[0] = (Expression) ih.getInstruction(); if (exprs[0].isVoid()) return null; NewOperator op = (NewOperator) exprs[0].getOperator(); if (constrCall.getClassType() != op.getType()) return null; } catch (ClassCastException ex) { return null; } catch (NullPointerException ex) { return null; } ConstructorOperator conOp = new ConstructorOperator(constrCall.getClassType(), constrCall.getField()); ih.combine(exprs.length+2, new Expression(conOp, exprs)); return ih; } public InstructionHeader combineIfGotoExpressions(InstructionHeader ih2) { InstructionHeader ih1; Expression[] e; int operator; try { if (ih2.switchType != MyType.tBoolean) return null; InstructionHeader[] dests2 = ih2.getSuccessors(); /* if ih2.getUniquePredecessor.getOperator().isVoid() XXX */ Vector predec = ih2.getPredecessors(); if (predec.size() != 1) return null; ih1 = (InstructionHeader) predec.elementAt(0); if (ih1.switchType != MyType.tBoolean) return null; InstructionHeader[] dests1 = ih1.getSuccessors(); if (dests1[0] != ih2) return null; if (dests1[1] == dests2[0]) { e = new Expression[2]; operator = Operator.LOG_AND_OP; e[1] = (Expression)ih2.getInstruction(); e[0] = ((Expression)ih2.getInstruction()).negate(); } else if (dests1[1] == dests2[1]) { e = new Expression[2]; operator = Operator.LOG_OR_OP; e[1] = (Expression)ih2.getInstruction(); e[0] = (Expression)ih2.getInstruction(); } else return null; } catch (ClassCastException ex) { return null; } catch (NullPointerException ex) { return null; } Expression cond = new Expression(new BinaryOperator(Type.tBoolean, operator), e); ih1.combineConditional(cond); return ih1; } public InstructionHeader createIfThenElseOperator(InstructionHeader ih) { InstructionHeader ifHeader; Expression e[] = new Expression[3]; InstructionHeader[] succs; try { Vector predec = ih.getPredecessors(); if (predec.size() != 1) return null; ifHeader = (InstructionHeader) predec.elementAt(0); if (ifHeader.switchType != Type.tBoolean) return null; succs = ifHeader.getSuccessors(); if (succs[1] != ih || succs[0].getNextInstruction() != succs[1] || succs[0].getSuccessors().length != 1 || succs[1].getSuccessors().length != 1 || succs[0].getSuccessors()[0] != succs[1].getSuccessors()[0]) return null; e[0] = (Expression) ifHeader.getInstruction(); e[1] = (Expression) succs[0].getInstruction(); e[2] = (Expression) succs[1].getInstruction(); } catch (ClassCastException ex) { return null; } catch (NullPointerException ex) { return null; } IfThenElseOperator iteo = new IfThenElseOperator (MyType.intersection(e[1].getType(),e[2].getType())); ifHeader.instr = new Expression(iteo, e); ifHeader.nextInstruction = ih.nextInstruction; ifHeader.successors = ih.successors; ifHeader.switchType = Type.tVoid; ifHeader.nextInstruction.predecessors.removeElement(succs[0]); ifHeader.nextInstruction.predecessors.removeElement(succs[1]); ifHeader.nextInstruction.predecessors.addElement(ifHeader); return ifHeader; } public void analyze() { InstructionHeader ih, next; for (ih = methodHeader.getNextInstruction(); ih != null; ih = next) { if (env.isVerbose) System.err.print("."); if ((next = removeNop(ih)) != null) continue; if ((next = createExpression(ih)) != null) continue; if ((next = createPostIncExpression(ih)) != null) continue; if ((next = createLocalPostIncExpression(ih)) != null) continue; if ((next = createAssignOp(ih)) != null) continue; if ((next = combineNewConstructor(ih)) != null) continue; if ((next = combineIfGotoExpressions(ih)) != null) continue; if ((next = createIfThenElseOperator(ih)) != null) continue; if ((next = createAssignExpression(ih)) != null) continue; if ((next = createConstantArray(ih)) != null) continue; next = ih.getNextInstruction(); } for (ih = methodHeader.getNextInstruction(); ih != null; ih = ih.getNextInstruction()) { ih.instr = ih.getInstruction().simplify(); } // for (int addr = 0; addr < instr.length; ) { // int nextAddr; // nextAddr = createExpression(addr); // if (nextAddr >= 0) { // addr = nextAddr; // continue; // } // nextAddr = createAssignExpression(addr); // if (nextAddr >= 0) { // addr = nextAddr; // continue; // } // nextAddr = createArrayOpAssign(addr); // if (nextAddr >= 0) { // addr = nextAddr; // continue; // } // nextAddr = createPostIncExpression(addr); // if (nextAddr >= 0) { // addr = nextAddr; // continue; // } // // nextAddr = createIfGotoStatement(addr); // // if (nextAddr >= 0) { // // addr = nextAddr; // // continue; // // } // nextAddr = combineIfGotoExpressions(addr); // if (nextAddr >= 0) { // addr = nextAddr; // continue; // } // nextAddr = combineConditionalExpr(addr); // if (nextAddr >= 0) { // addr = nextAddr; // continue; // } // addr += instr[addr].getLength(); // } // for (int addr = 0; addr < instr.length; ) { // int nextAddr; // nextAddr = combineExpressions(addr); // if (nextAddr >= 0) { // addr = nextAddr; // continue; // } // addr += instr[addr].getLength(); // } } public String getTypeString(Type type) { return type.toString(); } public ClassDefinition getClassDefinition() { return env.getClassDefinition(); } }