From 600f234a38155ab6530a89bf58e2e39fd32673a0 Mon Sep 17 00:00:00 2001 From: jochen Date: Wed, 30 Sep 1998 10:09:39 +0000 Subject: [PATCH] *** empty log message *** git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@44 379699f6-c40d-0410-875b-85095c16579e --- jode/jode/bytecode/Opcodes.java | 6 +- jode/jode/decompiler/CodeAnalyzer.java | 112 +---- .../decompiler/LocalVariableRangeList.java | 2 +- jode/jode/flow/CreateExpression.java | 2 +- jode/jode/flow/FlowBlock.java | 425 ++++++++++++++++-- 5 files changed, 395 insertions(+), 152 deletions(-) diff --git a/jode/jode/bytecode/Opcodes.java b/jode/jode/bytecode/Opcodes.java index 8f72c1d..0cfbe5c 100644 --- a/jode/jode/bytecode/Opcodes.java +++ b/jode/jode/bytecode/Opcodes.java @@ -202,7 +202,7 @@ public abstract class Opcodes implements RuntimeConstants { return createNormal (ca, addr, 2, new LocalStoreOperator (types[0][opcode-opc_istore], - ca.getLocalInfo(addr, stream.readUnsignedByte()), + ca.getLocalInfo(addr+2, stream.readUnsignedByte()), Operator.ASSIGN_OP)); case opc_istore_0: case opc_istore_1: case opc_istore_2: case opc_istore_3: @@ -217,7 +217,7 @@ public abstract class Opcodes implements RuntimeConstants { return createNormal (ca, addr, 1, new LocalStoreOperator (types[0][(opcode-opc_istore_0)/4], - ca.getLocalInfo(addr, (opcode-opc_istore_0) & 3), + ca.getLocalInfo(addr+1, (opcode-opc_istore_0) & 3), Operator.ASSIGN_OP)); case opc_iastore: case opc_lastore: case opc_fastore: case opc_dastore: case opc_aastore: @@ -481,7 +481,7 @@ public abstract class Opcodes implements RuntimeConstants { (ca, addr, 4, new LocalStoreOperator (types[0][opcode-opc_istore], - ca.getLocalInfo(addr, stream.readUnsignedShort()), + ca.getLocalInfo(addr+4, stream.readUnsignedShort()), Operator.ASSIGN_OP)); case opc_iinc: { int local = stream.readUnsignedShort(); diff --git a/jode/jode/decompiler/CodeAnalyzer.java b/jode/jode/decompiler/CodeAnalyzer.java index 14de8b1..961d194 100644 --- a/jode/jode/decompiler/CodeAnalyzer.java +++ b/jode/jode/decompiler/CodeAnalyzer.java @@ -107,7 +107,7 @@ public class CodeAnalyzer implements Analyzer, Constants { + (method.mdef.isStatic() ? 0 : 1); param = new jode.flow.VariableSet(); for (int i=0; i= li.start+li.length) li = li.next; - if (li == null || li.start > addr+2/*XXX*/) { + if (li == null || li.start > addr+1 /* XXX weired XXX */) { LocalInfo temp = new LocalInfo(slot); return temp; } diff --git a/jode/jode/flow/CreateExpression.java b/jode/jode/flow/CreateExpression.java index 01c2465..934b444 100644 --- a/jode/jode/flow/CreateExpression.java +++ b/jode/jode/flow/CreateExpression.java @@ -105,7 +105,7 @@ public class CreateExpression implements Transformation { } catch (ClassCastException ex) { return false; } - if(jode.Decompiler.isVerbose && params > 0) + if(jode.Decompiler.isVerbose) System.err.print("x"); ((InstructionContainer) flow.lastModified).setInstruction diff --git a/jode/jode/flow/FlowBlock.java b/jode/jode/flow/FlowBlock.java index 124a2c7..74125d0 100644 --- a/jode/jode/flow/FlowBlock.java +++ b/jode/jode/flow/FlowBlock.java @@ -22,6 +22,7 @@ import java.util.*; import jode.TabbedPrintWriter; import jode.Expression; import jode.CodeAnalyzer; +import jode.Decompiler; /** * A flow block is the structure of which the flow graph consists. A @@ -533,42 +534,8 @@ public class FlowBlock { * return_n */ - /** - * Search for an apropriate successor. - * @param prevSucc The successor, that was previously tried. - * @return the successor with smallest address greater than prevSucc - * or null if there isn't any further successor at all. - */ - public FlowBlock getSuccessor(FlowBlock prevSucc) { - /* search successor with smallest addr. */ - Enumeration enum = successors.elements(); - FlowBlock succ = null; - while (enum.hasMoreElements()) { - Jump jump = (Jump) enum.nextElement(); - if (jump == null) - continue; - FlowBlock fb = jump.destination; - if (prevSucc != null && fb.addr <= prevSucc.addr) - continue; - if (succ == null || fb.addr < succ.addr) { -// System.err.println("trying "+fb.getLabel()); - succ = fb; - } - } - return succ; - } - - /** - * Search for an apropriate successor. - * @return the successor with smallest address - * or null if there isn't a successor at all. - */ - public FlowBlock getSuccessor() { - return getSuccessor(null); - } - public void checkConsistent() { - if (!jode.Decompiler.doChecks) + if (!Decompiler.doChecks) return; if (block.outer != null || block.flowBlock != this) { throw new RuntimeException("Inconsistency"); @@ -878,7 +845,7 @@ public class FlowBlock { return true; } - public boolean doT2(Vector triedBlocks) { + public boolean doT2(int start, int end /* Vector triedBlocks */) { /* If there are no jumps to the beginning of this flow block * or if this block has other predecessors with a higher * address, return false. The second condition make sure that @@ -890,7 +857,8 @@ public class FlowBlock { while (preds.hasMoreElements()) { FlowBlock predFlow = (FlowBlock) preds.nextElement(); if (predFlow != null && predFlow != this - && !triedBlocks.contains(predFlow)) { + && predFlow.addr >= start && predFlow.addr < end + /*&& !triedBlocks.contains(predFlow)*/) { // System.err.println("refusing T2 on: "+getLabel()+ // " because of "+predFlow.getLabel()); /* XXX Is this enough to refuse T2 trafo ??? */ @@ -1023,6 +991,389 @@ public class FlowBlock { return true; } + + /** + * Do a T1 transformation with the end_of_method block. + */ + public void mergeEndBlock() { + try{ + checkConsistent(); + } catch (RuntimeException ex) { + ex.printStackTrace(); + try { + jode.TabbedPrintWriter writer = + new jode.TabbedPrintWriter(System.err, " "); + writer.tab(); + block.dumpSource(writer); + } catch (java.io.IOException ioex) { + } + } + + /* First find the innermost block that contains all jumps to the + * END_OF_METHOD block. + */ + Enumeration enum = successors.elements(); + StructuredBlock appendBlock = lastModified; + while(enum.hasMoreElements()) { + Jump jump = (Jump) enum.nextElement(); + if (jump == null || jump.destination != END_OF_METHOD) + continue; + + while (!appendBlock.contains(jump.prev)) { + appendBlock = appendBlock.outer; + if (appendBlock instanceof SequentialBlock + && appendBlock.getSubBlocks()[0] + instanceof RawTryCatchBlock) { + + /* We leave the catch block of a raw-try-catch-block. + * We shall now create the Catch- resp. FinallyBlock. + */ + appendBlock = + createCatchBlock((SequentialBlock)appendBlock); + } + } + /* appendBlock can't be null now, because the + * outermost block contains every structured block. + */ + } + + /* Try to eliminate as many jumps as possible. + */ + + appendBlock = optimizeJumps(END_OF_METHOD, appendBlock); + + enum = successors.elements(); + next_jump: + while (enum.hasMoreElements()) { + Jump jump = (Jump) enum.nextElement(); + + if (jump == null || jump.destination != END_OF_METHOD || + jump.prev == appendBlock) + continue; + + BreakableBlock breakToBlock = null; + for (StructuredBlock surrounder = jump.prev.outer; + surrounder != null && surrounder != appendBlock.outer; + surrounder = surrounder.outer) { + if (surrounder instanceof BreakableBlock) { + if (surrounder.getNextFlowBlock() == END_OF_METHOD) + breakToBlock = (BreakableBlock) surrounder; + + /* We don't want labeled breaks, because we can + * simply return. */ + break; + } + } + StructuredBlock prevBlock = jump.prev; + prevBlock.removeJump(); + + if (breakToBlock == null) + /* The successor is the dummy return instruction, so + * replace the jump with a return. + */ + prevBlock.appendBlock(new ReturnBlock()); + else + prevBlock.appendBlock + (new BreakBlock(breakToBlock, false)); + } + + /* Now remove the jump of the appendBlock if it points to + * successor. + */ + if (appendBlock.jump != null + && appendBlock.jump.destination == END_OF_METHOD) + appendBlock.removeJump(); + + /* transformation succeeded */ + try { + checkConsistent(); + } catch (RuntimeException ex) { + ex.printStackTrace(); + try { + jode.TabbedPrintWriter writer = + new jode.TabbedPrintWriter(System.err, " "); + writer.tab(); + block.dumpSource(writer); + } catch (java.io.IOException ioex) { + } + } + } + + + static Transformation[] exprTrafos = { + new RemoveEmpty(), + new CreateExpression(), + new CreatePostIncExpression(), + new CreateAssignExpression(), + new CreateNewConstructor(), + new CombineIfGotoExpressions(), + new CreateIfThenElseOperator(), + new CreateConstantArray(), + new SimplifyExpression() + }; + + + /** + * Search for an apropriate successor. + * @param prevSucc The successor, that was previously tried. + * @param start The minimum address. + * @param end The maximum address + 1. + * @return the successor with smallest address greater than prevSucc + * or null if there isn't any further successor at all. + */ + FlowBlock getSuccessor(int start, int end) { + /* search successor with smallest addr. */ + Enumeration enum = successors.elements(); + FlowBlock succ = null; + while (enum.hasMoreElements()) { + Jump jump = (Jump) enum.nextElement(); + if (jump == null) + continue; + FlowBlock fb = jump.destination; + if (fb.addr < start || fb.addr >= end || fb == this) + continue; + if (succ == null || fb.addr < succ.addr) { +// System.err.println("trying "+fb.getLabel()); + succ = fb; + } + } + return succ; + } + + /** + * The main analyzation. This calls doT1 and doT2 on apropriate + * regions. + */ + public void analyze() { + analyze(0, Integer.MAX_VALUE); + mergeEndBlock(); + } + +// /** +// * The main analyzation. This calls doT1 and doT2 on apropriate +// * regions. Only blocks whose address lies in the given address +// * range are considered. +// * @param start the start of the address range. +// * @param end the end of the address range. +// */ +// public void analyze(int start, int end) { +// /* XXX optimize */ +// Stack todo = new Stack(); +// FlowBlock flow = this; +// try { +// jode.TabbedPrintWriter writer = null; +// if (Decompiler.isFlowDebugging) { +// writer = new jode.TabbedPrintWriter(System.err, " "); +// } +// analyzation: +// while (true) { + +// if (Decompiler.isFlowDebugging) { +// writer.println("before Transformation: "); +// writer.tab(); +// flow.dumpSource(writer); +// writer.untab(); +// } + +// /* First do some non flow transformations. */ +// int i=0; +// while (i < exprTrafos.length) { +// if (exprTrafos[i].transform(flow)) +// i = 0; +// else +// i++; +// } + +// if (Decompiler.isFlowDebugging) { +// writer.println("after Transformation: "); +// writer.tab(); +// flow.dumpSource(writer); +// writer.untab(); +// } + +// if (flow.doT2(todo)) { + +// if (Decompiler.isFlowDebugging) { +// writer.println("after T2: "); +// writer.tab(); +// flow.dumpSource(writer); +// writer.untab(); +// } + +// /* T2 transformation succeeded. This may +// * make another T1 analysis in the previous +// * block possible. +// */ +// if (!todo.isEmpty()) +// flow = (FlowBlock) todo.pop(); +// } + +// FlowBlock succ = flow.getSuccessor(start, end); +// while (true) { +// if (succ == null) { +// /* the Block has no successor where t1 is applicable. +// * +// * If everything is okay the stack should be empty now, +// * and the program is transformed correctly. +// */ +// if (todo.isEmpty()) +// break analyzation; + +// /* Otherwise pop the last flow block from stack and +// * try another successor. +// */ +// succ = flow; +// flow = (FlowBlock) todo.pop(); +// } else { +// if (succ.block instanceof RawTryCatchBlock) { +// int subStart = succ.addr; +// int subEnd = (subStart >= addr)? end : addr; +// succ.analyze(subStart, subEnd); +// } +// if (flow.doT1(succ)) { +// /* T1 transformation succeeded. */ + +// if (Decompiler.isFlowDebugging) { +// writer.println("after T1: "); +// writer.tab(); +// flow.dumpSource(writer); +// writer.untab(); +// } + +// if (Decompiler.isVerbose) +// System.err.print("."); + +// continue analyzation; +// } else if (!todo.contains(succ) && succ != flow) { +// /* succ wasn't tried before, succeed with +// * successor and put flow on the stack. +// */ +// todo.push(flow); +// flow = succ; +// continue analyzation; +// } +// } + +// /* Try the next successor. +// */ +// succ = flow.getSuccessor(succ.addr+1, end); +// } +// } +// } catch (java.io.IOException ioex) { +// } +// } + + /** + * The main analyzation. This calls doT1 and doT2 on apropriate + * regions. Only blocks whose address lies in the given address + * range are considered. + * @param start the start of the address range. + * @param end the end of the address range. + */ + public boolean analyze(int start, int end) { + try { + jode.TabbedPrintWriter writer = null; + if (Decompiler.isFlowDebugging) + writer = new jode.TabbedPrintWriter(System.err, " "); + + boolean changed = false; + + while (true) { + + if (Decompiler.isFlowDebugging) { + writer.println("before Transformation: "); + writer.tab(); + dumpSource(writer); + writer.untab(); + } + + /* First do some non flow transformations. */ + int i=0; + while (i < exprTrafos.length) { + if (exprTrafos[i].transform(this)) + i = 0; + else + i++; + } + + if (Decompiler.isFlowDebugging) { + writer.println("after Transformation: "); + writer.tab(); + dumpSource(writer); + writer.untab(); + } + + if (doT2(start, end)) { + + if (Decompiler.isFlowDebugging) { + writer.println("after T2: "); + writer.tab(); + dumpSource(writer); + writer.untab(); + } + + /* T2 transformation succeeded. This may + * make another T1 analysis in the previous + * block possible. + */ + if (addr != 0) + return true; + } + + FlowBlock succ = getSuccessor(start, end); + while (true) { + if (succ == null) { + /* the Block has no successor where t1 is applicable. + * Finish this analyzation. + */ + return changed; + } else { + if (succ.block instanceof RawTryCatchBlock) { + int subStart = succ.addr; + int subEnd = (subStart > addr)? end : addr; + succ.analyze(subStart, subEnd); + } + /* Only do T1 transformation if the blocks are + * adjacent. */ + if ((succ.addr == addr+length + || succ.addr+succ.length == addr) + && doT1(succ)) { + /* T1 transformation succeeded. */ + changed = true; + + if (Decompiler.isFlowDebugging) { + writer.println("after T1: "); + writer.tab(); + dumpSource(writer); + writer.untab(); + } + break; + } else { + /* analyze succ, the new region is the + * continous region of + * [start,end) \cap \compl [addr, addr+length) + * where succ.addr lies in. + */ + int newStart = (succ.addr > addr) + ? addr+length : start; + int newEnd = (succ.addr > addr) + ? end : addr; + if (succ.analyze(newStart, newEnd)) + break; + } + } + + /* Try the next successor. + */ + succ = getSuccessor(succ.addr+1, end); + } + } + } catch (java.io.IOException ioex) { + return false; + } + } + + /** * Resolves the destinations of all jumps. */