Use new BytecodeInfo.

Use new DeadCodeAnalyzer


git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@447 379699f6-c40d-0410-875b-85095c16579e
stable
jochen 26 years ago
parent 1e5706d8f9
commit 4a40e01fac
  1. 183
      jode/jode/decompiler/CodeAnalyzer.java

@ -19,13 +19,11 @@
package jode.decompiler; package jode.decompiler;
import jode.*; import jode.*;
import jode.bytecode.ClassInfo; import jode.bytecode.*;
import jode.bytecode.ConstantPool;
import jode.bytecode.AttributeInfo;
import jode.bytecode.CodeInfo;
import jode.flow.FlowBlock; import jode.flow.FlowBlock;
import jode.flow.TransformExceptionHandlers; import jode.flow.TransformExceptionHandlers;
import java.util.BitSet;
import java.util.Stack; import java.util.Stack;
import java.util.Vector; import java.util.Vector;
import java.util.Enumeration; import java.util.Enumeration;
@ -36,7 +34,7 @@ import java.io.IOException;
public class CodeAnalyzer implements Analyzer { public class CodeAnalyzer implements Analyzer {
FlowBlock methodHeader; FlowBlock methodHeader;
CodeInfo code; BytecodeInfo code;
MethodAnalyzer method; MethodAnalyzer method;
public JodeEnvironment env; public JodeEnvironment env;
@ -50,20 +48,30 @@ public class CodeAnalyzer implements Analyzer {
*/ */
public MethodAnalyzer getMethod() {return method;} public MethodAnalyzer getMethod() {return method;}
public CodeAnalyzer(MethodAnalyzer ma, CodeInfo bc, JodeEnvironment e) public CodeAnalyzer(MethodAnalyzer ma,
throws ClassFormatError AttributeInfo codeattr, JodeEnvironment e)
{ {
code = bc;
method = ma; method = ma;
env = e; env = e;
DataInputStream stream = new DataInputStream
(new ByteArrayInputStream(codeattr.getContents()));
ConstantPool cpool = ma.classAnalyzer.getConstantPool();
code = new BytecodeInfo();
try {
code.read(cpool, stream);
} catch (IOException ex) {
ex.printStackTrace(Decompiler.err);
code = null;
return;
}
if (Decompiler.useLVT) { if (Decompiler.useLVT) {
AttributeInfo attr = code.findAttribute("LocalVariableTable"); AttributeInfo attr = code.findAttribute("LocalVariableTable");
if (attr != null) { if (attr != null) {
if (Decompiler.showLVT) if (Decompiler.showLVT)
Decompiler.err.println("Method: "+ma.getName()); Decompiler.err.println("Method: "+ma.getName());
lvt = new LocalVariableTable(bc.getMaxLocals(), lvt = new LocalVariableTable(code.getMaxLocals(), cpool, attr);
method.classAnalyzer, attr);
} }
} }
@ -73,7 +81,7 @@ public class CodeAnalyzer implements Analyzer {
param[i] = getLocalInfo(0, i); param[i] = getLocalInfo(0, i);
} }
public CodeInfo getCodeInfo() { public BytecodeInfo getBytecodeInfo() {
return code; return code;
} }
@ -81,51 +89,38 @@ public class CodeAnalyzer implements Analyzer {
return methodHeader; return methodHeader;
} }
private final static int SEQUENTIAL = 1; void readCode() {
private final static int PREDECESSORS = 2; /* The adjacent analyzation relies on this */
/** DeadCodeAnalysis.removeDeadCode(code);
* @param code The code array. Handler[] handlers = code.getExceptionHandlers();
* @param handlers The exception handlers.
*/
void readCode(byte[] code, int[] handlers)
throws ClassFormatError
{
ConstantPool cpool = method.classAnalyzer.getConstantPool();
byte[] flags = new byte[code.length];
int[] lengths = new int[code.length];
try {
DataInputStream stream =
new DataInputStream(new ByteArrayInputStream(code));
for (int addr = 0; addr < code.length; ) {
int[] succs = Opcodes.getSizeAndSuccs(addr, stream);
if (succs.length == 2
&& succs[1] == addr + succs[0])
flags[addr] |= SEQUENTIAL;
lengths[addr] = succs[0];
addr += succs[0];
for (int i=1; i<succs.length; i++)
if (succs[i] != addr)
flags[succs[i]] |= PREDECESSORS;
}
} catch (IOException ex) {
ex.printStackTrace(Decompiler.err);
throw new ClassFormatError(ex.getMessage());
}
for (int i=0; i<handlers.length; i += 4) {
int start = handlers[i + 0];
int handler = handlers[i + 2];
if (start < 0) start += 65536;
if (handler < 0) handler += 65536;
flags[start] |= PREDECESSORS;
flags[handler] |= PREDECESSORS;
}
FlowBlock[] instr = new FlowBlock[code.length];
int returnCount; int returnCount;
TransformExceptionHandlers excHandlers; TransformExceptionHandlers excHandlers;
try { {
DataInputStream stream = /* First create a FlowBlock for every block that has a
new DataInputStream(new ByteArrayInputStream(code)); * predecessor other than the previous instruction.
*/
for (Instruction instr = code.getFirstInstr();
instr != null; instr = instr.nextByAddr) {
if (instr.prevByAddr == null
|| instr.prevByAddr.alwaysJumps
|| instr.preds.size() != 1)
instr.tmpInfo = new FlowBlock
(this, instr.addr, instr.length);
else
instr.tmpInfo = null;
}
for (int i=0; i < handlers.length; i++) {
Instruction instr = handlers[i].start;
if (instr.tmpInfo == null)
instr.tmpInfo
= new FlowBlock(this, instr.addr, instr.length);
instr = handlers[i].catcher;
if (instr.tmpInfo == null)
instr.tmpInfo
= new FlowBlock(this, instr.addr, instr.length);
}
/* While we read the opcodes into FlowBlocks /* While we read the opcodes into FlowBlocks
* we try to combine sequential blocks, as soon as we * we try to combine sequential blocks, as soon as we
@ -134,60 +129,59 @@ public class CodeAnalyzer implements Analyzer {
*/ */
int mark = 1000; int mark = 1000;
FlowBlock lastBlock = null; FlowBlock lastBlock = null;
for (int addr = 0; addr < code.length; ) { boolean lastSequential = false;
for (Instruction instr = code.getFirstInstr();
instr != null; instr = instr.nextByAddr) {
jode.flow.StructuredBlock block jode.flow.StructuredBlock block
= Opcodes.readOpcode(cpool, addr, stream, this); = Opcodes.readOpcode(instr, this);
if (jode.Decompiler.isVerbose && addr > mark) { if (jode.Decompiler.isVerbose && instr.addr > mark) {
Decompiler.err.print('.'); Decompiler.err.print('.');
mark += 1000; mark += 1000;
} }
if (lastBlock != null && flags[addr] == SEQUENTIAL) { if (lastSequential && instr.tmpInfo == null
/* Only merge with previous block, if this is sequential,
lastBlock.doSequentialT1(block, lengths[addr]); * too.
* Why? doSequentialT1 does only handle sequential blocks.
*/
&& !instr.alwaysJumps && instr.succs == null) {
lastBlock.doSequentialT1(block, instr.length);
} else { } else {
instr[addr] = new FlowBlock(this, addr,
lengths[addr], block);
lastBlock = ((flags[addr] & SEQUENTIAL) == 0)
? null : instr[addr];
if (instr.tmpInfo == null)
instr.tmpInfo = new FlowBlock
(this, instr.addr, instr.length);
FlowBlock flowBlock = (FlowBlock) instr.tmpInfo;
flowBlock.setBlock(block);
if (lastBlock != null)
lastBlock.setNextByAddr(flowBlock);
instr.tmpInfo = lastBlock = flowBlock;
lastSequential = !instr.alwaysJumps && instr.succs == null;
} }
addr += lengths[addr];
} }
for (int addr=0; addr<instr.length; ) { methodHeader = (FlowBlock) code.getFirstInstr().tmpInfo;
instr[addr].resolveJumps(instr);
addr = instr[addr].getNextAddr();
}
methodHeader = instr[0];
methodHeader.markReachable();
excHandlers = new TransformExceptionHandlers(); excHandlers = new TransformExceptionHandlers();
for (int i=0; i<handlers.length; i += 4) { for (int i=0; i<handlers.length; i++) {
Type type = null; Type type = null;
int start = handlers[i + 0]; FlowBlock start
int end = handlers[i + 1]; = (FlowBlock) handlers[i].start.tmpInfo;
int handler = handlers[i + 2]; int endAddr = handlers[i].end.nextByAddr.addr;
if (start < 0) start += 65536; FlowBlock handler
if (end < 0) end += 65536; = (FlowBlock) handlers[i].catcher.tmpInfo;
if (handler < 0) handler += 65536; if (handlers[i].type != null)
if (handlers[i + 3 ] != 0) type = Type.tClass(handlers[i].type);
type = Type.tClass(cpool.getClassName(handlers[i + 3]));
excHandlers.addHandler(instr[start], end, excHandlers.addHandler(start, endAddr, handler, type);
instr[handler], type);
instr[handler].markReachable();
} }
} catch (IOException ex) {
ex.printStackTrace(Decompiler.err);
throw new ClassFormatError(ex.getMessage());
} }
FlowBlock.removeDeadCode(methodHeader);
if (Decompiler.isVerbose) if (Decompiler.isVerbose)
Decompiler.err.print('-'); Decompiler.err.print('-');
@ -197,9 +191,9 @@ public class CodeAnalyzer implements Analyzer {
public void analyze() public void analyze()
{ {
byte[] codeArray = code.getCode(); if (code == null)
int[] handlers = code.getExceptionHandlers(); return;
readCode(codeArray, handlers); readCode();
if (!Decompiler.usePUSH && methodHeader.mapStackToLocal()) if (!Decompiler.usePUSH && methodHeader.mapStackToLocal())
methodHeader.removePush(); methodHeader.removePush();
if (Decompiler.removeOnetimeLocals) if (Decompiler.removeOnetimeLocals)
@ -226,7 +220,10 @@ public class CodeAnalyzer implements Analyzer {
public void dumpSource(TabbedPrintWriter writer) public void dumpSource(TabbedPrintWriter writer)
throws java.io.IOException throws java.io.IOException
{ {
methodHeader.dumpSource(writer); if (methodHeader != null)
methodHeader.dumpSource(writer);
else
writer.println("COULDN'T DECOMPILE METHOD!");
} }
public LocalInfo getLocalInfo(int addr, int slot) { public LocalInfo getLocalInfo(int addr, int slot) {

Loading…
Cancel
Save