* ConstantInstruction.java,IncInstruction.java,ReferenceInstruction.java,SlotInstruction.java,TypeDimensionInstruction.java,TypeInstruction.java: Class and Constructors no longer public.

* Instruction.java (forOpcode): added method to create instructions.
* SlotInstruction.java,IncInstruction.java: Use a LocalVariableInfo
  entry instead of slot+addr
* BasicBlockReader.java, BasicBlockWriter.java:  Adapted Instruction interface.
* BinaryInfo.java: package private class now.
* BinaryInfo.java,FieldInfo.java,MethodInfo.java: Made some methods
  package private.
* BasicBlocks.java (getAllInstructions): removed.
  (read,readAttribute): no longer protected.
* ClassInfo.java (isGuessed): added.

All classes: bug fixes, etc.


git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@1266 379699f6-c40d-0410-875b-85095c16579e
master
hoenicke 24 years ago
parent ca386721b2
commit 5e6af53990
  1. 47
      jode/jode/bytecode/BasicBlockReader.java
  2. 31
      jode/jode/bytecode/BasicBlockWriter.java
  3. 82
      jode/jode/bytecode/BasicBlocks.java
  4. 51
      jode/jode/bytecode/BinaryInfo.java
  5. 112
      jode/jode/bytecode/Block.java
  6. 61
      jode/jode/bytecode/ClassInfo.java
  7. 10
      jode/jode/bytecode/ClassPath.java
  8. 17
      jode/jode/bytecode/ConstantInstruction.java
  9. 18
      jode/jode/bytecode/FieldInfo.java
  10. 2
      jode/jode/bytecode/Handler.java
  11. 18
      jode/jode/bytecode/IncInstruction.java
  12. 245
      jode/jode/bytecode/Instruction.java
  13. 13
      jode/jode/bytecode/MethodInfo.java
  14. 23
      jode/jode/bytecode/ReferenceInstruction.java
  15. 28
      jode/jode/bytecode/SlotInstruction.java
  16. 15
      jode/jode/bytecode/SwitchInstruction.java
  17. 22
      jode/jode/bytecode/TypeDimensionInstruction.java
  18. 20
      jode/jode/bytecode/TypeInstruction.java
  19. 2
      jode/jode/bytecode/package.html

@ -256,7 +256,7 @@ class BasicBlockReader implements Opcodes {
if (!alwaysJump) if (!alwaysJump)
succs[succLength] = getSuccBlock(info.nextAddr); succs[succLength] = getSuccBlock(info.nextAddr);
blocks[blockNr].setCode(Arrays.asList(instrs), succs); blocks[blockNr].setCode(instrs, succs);
} }
void convert() throws ClassFormatException { void convert() throws ClassFormatException {
@ -331,7 +331,9 @@ class BasicBlockReader implements Opcodes {
if (slot >= maxLocals) if (slot >= maxLocals)
throw new ClassFormatException throw new ClassFormatException
("Invalid local slot "+slot); ("Invalid local slot "+slot);
instr = new SlotInstruction(wideopcode, slot); LocalVariableInfo lvi
= LocalVariableInfo.getInfo(slot);
instr = new SlotInstruction(wideopcode, lvi);
length = 4; length = 4;
if ((GlobalOptions.debuggingFlags if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_BYTECODE) != 0) & GlobalOptions.DEBUG_BYTECODE) != 0)
@ -345,7 +347,9 @@ class BasicBlockReader implements Opcodes {
if (slot >= maxLocals-1) if (slot >= maxLocals-1)
throw new ClassFormatException throw new ClassFormatException
("Invalid local slot "+slot); ("Invalid local slot "+slot);
instr = new SlotInstruction(wideopcode, slot); LocalVariableInfo lvi
= LocalVariableInfo.getInfo(slot);
instr = new SlotInstruction(wideopcode, lvi);
length = 4; length = 4;
if ((GlobalOptions.debuggingFlags if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_BYTECODE) != 0) & GlobalOptions.DEBUG_BYTECODE) != 0)
@ -358,7 +362,9 @@ class BasicBlockReader implements Opcodes {
if (slot >= maxLocals) if (slot >= maxLocals)
throw new ClassFormatException throw new ClassFormatException
("Invalid local slot "+slot); ("Invalid local slot "+slot);
instr = new SlotInstruction(wideopcode, slot); LocalVariableInfo lvi
= LocalVariableInfo.getInfo(slot);
instr = new SlotInstruction(wideopcode, lvi);
length = 4; length = 4;
if ((GlobalOptions.debuggingFlags if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_BYTECODE) != 0) & GlobalOptions.DEBUG_BYTECODE) != 0)
@ -370,8 +376,10 @@ class BasicBlockReader implements Opcodes {
if (slot >= maxLocals) if (slot >= maxLocals)
throw new ClassFormatException throw new ClassFormatException
("Invalid local slot "+slot); ("Invalid local slot "+slot);
LocalVariableInfo lvi
= LocalVariableInfo.getInfo(slot);
int incr = input.readShort(); int incr = input.readShort();
instr = new IncInstruction(wideopcode, slot, incr); instr = new IncInstruction(wideopcode, lvi, incr);
length = 6; length = 6;
if ((GlobalOptions.debuggingFlags if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_BYTECODE) != 0) & GlobalOptions.DEBUG_BYTECODE) != 0)
@ -399,8 +407,10 @@ class BasicBlockReader implements Opcodes {
if (slot >= maxLocals) if (slot >= maxLocals)
throw new ClassFormatException throw new ClassFormatException
("Invalid local slot "+slot); ("Invalid local slot "+slot);
LocalVariableInfo lvi
= LocalVariableInfo.getInfo(slot);
instr = new SlotInstruction instr = new SlotInstruction
(opc_iload + (opcode-opc_iload_0)/4, slot); (opc_iload + (opcode-opc_iload_0)/4, lvi);
length = 1; length = 1;
break; break;
} }
@ -414,8 +424,10 @@ class BasicBlockReader implements Opcodes {
if (slot >= maxLocals) if (slot >= maxLocals)
throw new ClassFormatException throw new ClassFormatException
("Invalid local slot "+slot); ("Invalid local slot "+slot);
LocalVariableInfo lvi
= LocalVariableInfo.getInfo(slot);
instr = new SlotInstruction instr = new SlotInstruction
(opc_istore + (opcode-opc_istore_0)/4, slot); (opc_istore + (opcode-opc_istore_0)/4, lvi);
length = 1; length = 1;
break; break;
} }
@ -427,8 +439,10 @@ class BasicBlockReader implements Opcodes {
if (slot >= maxLocals-1) if (slot >= maxLocals-1)
throw new ClassFormatException throw new ClassFormatException
("Invalid local slot "+slot); ("Invalid local slot "+slot);
LocalVariableInfo lvi
= LocalVariableInfo.getInfo(slot);
instr = new SlotInstruction instr = new SlotInstruction
(opc_lstore + (opcode-opc_lstore_0)/4, slot); (opc_lstore + (opcode-opc_lstore_0)/4, lvi);
length = 1; length = 1;
break; break;
} }
@ -438,7 +452,9 @@ class BasicBlockReader implements Opcodes {
if (slot >= maxLocals) if (slot >= maxLocals)
throw new ClassFormatException throw new ClassFormatException
("Invalid local slot "+slot); ("Invalid local slot "+slot);
instr = new SlotInstruction(opcode, slot); LocalVariableInfo lvi
= LocalVariableInfo.getInfo(slot);
instr = new SlotInstruction(opcode, lvi);
length = 2; length = 2;
if ((GlobalOptions.debuggingFlags if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_BYTECODE) != 0) & GlobalOptions.DEBUG_BYTECODE) != 0)
@ -451,7 +467,9 @@ class BasicBlockReader implements Opcodes {
if (slot >= maxLocals - 1) if (slot >= maxLocals - 1)
throw new ClassFormatException throw new ClassFormatException
("Invalid local slot "+slot); ("Invalid local slot "+slot);
instr = new SlotInstruction(opcode, slot); LocalVariableInfo lvi
= LocalVariableInfo.getInfo(slot);
instr = new SlotInstruction(opcode, lvi);
length = 2; length = 2;
if ((GlobalOptions.debuggingFlags if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_BYTECODE) != 0) & GlobalOptions.DEBUG_BYTECODE) != 0)
@ -463,7 +481,9 @@ class BasicBlockReader implements Opcodes {
if (slot >= maxLocals) if (slot >= maxLocals)
throw new ClassFormatException throw new ClassFormatException
("Invalid local slot "+slot); ("Invalid local slot "+slot);
instr = new SlotInstruction(opcode, slot); LocalVariableInfo lvi
= LocalVariableInfo.getInfo(slot);
instr = new SlotInstruction(opcode, lvi);
length = 2; length = 2;
if ((GlobalOptions.debuggingFlags if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_BYTECODE) != 0) & GlobalOptions.DEBUG_BYTECODE) != 0)
@ -535,8 +555,10 @@ class BasicBlockReader implements Opcodes {
if (slot >= maxLocals) if (slot >= maxLocals)
throw new ClassFormatException throw new ClassFormatException
("Invalid local slot "+slot); ("Invalid local slot "+slot);
LocalVariableInfo lvi
= LocalVariableInfo.getInfo(slot);
int incr = input.readByte(); int incr = input.readByte();
instr = new IncInstruction(opcode, slot, incr); instr = new IncInstruction(opcode, lvi, incr);
length = 3; length = 3;
if ((GlobalOptions.debuggingFlags if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_BYTECODE) != 0) & GlobalOptions.DEBUG_BYTECODE) != 0)
@ -958,3 +980,4 @@ class BasicBlockReader implements Opcodes {
} }
} }
} }

@ -89,11 +89,10 @@ class BasicBlockWriter implements Opcodes {
int blockNr = block.getBlockNr(); int blockNr = block.getBlockNr();
LocalVariableInfo[] life LocalVariableInfo[] life
= (LocalVariableInfo[]) atStart[blockNr].clone(); = (LocalVariableInfo[]) atStart[blockNr].clone();
for (Iterator iter = block.getInstructions().iterator(); Instruction[] instrs = block.getInstructions();
iter.hasNext() ; ) { for (int i = 0; i < instrs.length; i++) {
Instruction instr = (Instruction) iter.next(); if (instrs[i].hasLocal()) {
if (instr.hasLocal()) { LocalVariableInfo lvi = instrs[i].getLocalInfo();
LocalVariableInfo lvi = instr.getLocalInfo();
int slot = lvi.getSlot(); int slot = lvi.getSlot();
if (life[slot] != null if (life[slot] != null
&& life[slot] != lvi) && life[slot] != lvi)
@ -162,10 +161,9 @@ class BasicBlockWriter implements Opcodes {
} }
} }
int size = block.getInstructions().size(); Instruction[] instrs = block.getInstructions();
for (int k = 0; k < size; k++) { for (int k = 0; k < instrs.length; k++) {
Instruction instr Instruction instr = instrs[k];
= (Instruction) block.getInstructions().get(k);
if (instr.hasLocal()) { if (instr.hasLocal()) {
LocalVariableInfo lvi = instr.getLocalInfo(); LocalVariableInfo lvi = instr.getLocalInfo();
int slot = lvi.getSlot(); int slot = lvi.getSlot();
@ -227,12 +225,11 @@ class BasicBlockWriter implements Opcodes {
next_block: next_block:
for (int i = 0; i < blocks.length; i++) { for (int i = 0; i < blocks.length; i++) {
blockAddr[i] = addr; blockAddr[i] = addr;
List instructions = blocks[i].getInstructions(); Instruction[] instrs = blocks[i].getInstructions();
int size = instructions.size(); instrLength[i] = new int[instrs.length];
instrLength[i] = new int[size];
Block[] succs = blocks[i].getSuccs(); Block[] succs = blocks[i].getSuccs();
for (int j = 0; j < size; j++) { for (int j = 0; j < instrs.length; j++) {
Instruction instr = (Instruction) instructions.get(j); Instruction instr = instrs[j];
if (instr.hasLineNr()) if (instr.hasLineNr())
lntCount++; lntCount++;
@ -637,10 +634,10 @@ class BasicBlockWriter implements Opcodes {
Block[] succs = blocks[i].getSuccs(); Block[] succs = blocks[i].getSuccs();
if (addr != blockAddr[i]) if (addr != blockAddr[i])
throw new InternalError("Address calculation broken!"); throw new InternalError("Address calculation broken!");
List instructions = blocks[i].getInstructions(); Instruction[] instructions = blocks[i].getInstructions();
int size = instructions.size(); int size = instructions.length;
for (int j = 0; j < size; j++) { for (int j = 0; j < size; j++) {
Instruction instr = (Instruction) instructions.get(j); Instruction instr = instructions[j];
if (instr.hasLineNr()) { if (instr.hasLineNr()) {
lnt[lntPtr++] = (short) addr; lnt[lntPtr++] = (short) addr;
lnt[lntPtr++] = (short) instr.getLineNr(); lnt[lntPtr++] = (short) instr.getLineNr();

@ -1,4 +1,4 @@
/* BasicBlocks Copyright (C) 1999 Jochen Hoenicke. /* BasicBlocks Copyright (C) 2000 Jochen Hoenicke.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -28,6 +28,7 @@ import java.io.PrintWriter;
///#def COLLECTIONS java.util ///#def COLLECTIONS java.util
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator; import java.util.Iterator;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
///#enddef ///#enddef
@ -36,22 +37,37 @@ import java.lang.UnsupportedOperationException;
///#enddef ///#enddef
/** /**
* <p>This class gives another representation of the byte code of a * <p>Represents the byte code of a method in form of basic blocks. A
* method. The instructions are splitted into BasicBlocks, each an * basic block is a bunch of instructions, that must always execute in
* array of consecutive Instructions. It is not allowed that a goto * sequential order. Every basic block is represented by an Block
* jumps inside a basic block.</p> * object.</p>
* *
* <p>All jumps must be at the end of the block. A conditional jump * <p>All jump instructions must be at the end of the block, and the
* may be followed by a single goto, but there must not be any other * jump instructions doesn't have to remember where they jump to.
* jumps. If there is now unconditional jump at the end, the block * Instead this information is stored inside the blocks. See
* implicitely flows into the next one. </p> * <code>Block</code> for details.</p>
* *
* <p>Try block must span over some consecutive BasicBlocks and there * <p>A subroutine block, i.e. a block where some jsr instructions may
* catches must jump to the start of an basic block. </p> * jump to, must store its return address in a local variable
* immediately. There must be exactly one block with the
* corresponding <code>opc_ret</code> instruction and all blocks that
* belong to this subroutine must point to the ret block. Bytecode
* that doesn't have this condition is automatically transformed on
* reading.</p>
* *
* <p>Deadcode will not be included in the BasicBlock, also * <p>Exception Handlers are represented by the Handler class. Their
* BasicBlocks consisting of a single jump will be optimized away.</p> * start/end range must span over some consecutive BasicBlocks and
* there handler must be another basic block.</p>
* *
* <p>If you want to create or modify the byte code, you must first set
* the basic blocks and then set exception handlers. If you set new
* blocks the previous exception handlers will be removed.</p>
*
* <p>When the code is written to a class file, the blocks are written
* in the given order. Goto and return instructions are inserted as
* necessary, you don't have to care about that.</p>
*
* @see jode.bytecode.Block
* @see jode.bytecode.Instruction */ * @see jode.bytecode.Instruction */
public class BasicBlocks extends BinaryInfo { public class BasicBlocks extends BinaryInfo {
@ -121,39 +137,6 @@ public class BasicBlocks extends BinaryInfo {
return blocks; return blocks;
} }
public Iterator getAllInstructions() {
return new Iterator() {
int blockNr = 0;
Iterator blockIter = getNextIterator();
public boolean hasNext() {
return blockIter != null;
}
public Iterator getNextIterator() {
if (blockNr < blocks.length)
return blocks[blockNr++].getInstructions().iterator();
return null;
}
public Object next() {
Object instr;
try {
instr = blockIter.next();
} catch (NullPointerException ex) {
throw new NoSuchElementException();
}
if (!blockIter.hasNext())
blockIter = getNextIterator();
return instr;
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
/** /**
* @return the exception handlers, or null if the method has no * @return the exception handlers, or null if the method has no
* exception handlers. * exception handlers.
@ -215,7 +198,7 @@ public class BasicBlocks extends BinaryInfo {
} }
private BasicBlockReader reader; private BasicBlockReader reader;
public void read(ConstantPool cp, void read(ConstantPool cp,
DataInputStream input, DataInputStream input,
int howMuch) throws IOException { int howMuch) throws IOException {
if ((GlobalOptions.debuggingFlags if ((GlobalOptions.debuggingFlags
@ -231,7 +214,7 @@ public class BasicBlocks extends BinaryInfo {
dumpCode(GlobalOptions.err); dumpCode(GlobalOptions.err);
} }
protected void readAttribute(String name, int length, ConstantPool cp, void readAttribute(String name, int length, ConstantPool cp,
DataInputStream input, DataInputStream input,
int howMuch) throws IOException { int howMuch) throws IOException {
if (howMuch >= ClassInfo.ALMOSTALL if (howMuch >= ClassInfo.ALMOSTALL
@ -248,7 +231,8 @@ public class BasicBlocks extends BinaryInfo {
void reserveSmallConstants(GrowableConstantPool gcp) { void reserveSmallConstants(GrowableConstantPool gcp) {
for (int i=0; i < blocks.length; i++) { for (int i=0; i < blocks.length; i++) {
next_instr: next_instr:
for (Iterator iter = blocks[i].getInstructions().iterator(); for (Iterator iter
= Arrays.asList(blocks[i].getInstructions()).iterator();
iter.hasNext(); ) { iter.hasNext(); ) {
Instruction instr = (Instruction) iter.next(); Instruction instr = (Instruction) iter.next();
if (instr.getOpcode() == Opcodes.opc_ldc) { if (instr.getOpcode() == Opcodes.opc_ldc) {

@ -34,10 +34,26 @@ import java.util.Iterator;
/** /**
* <p>Represents a container for user specified attributes.</p>
*
* <p>Java bytecode is extensible: Classes, Methods and Fields may
* have any number of attributes. Every attribute has a name and some
* unformatted data.</p>
*
* <p>There are some predefined attributes, even the Code of a Method
* is an attribute. These predefined attributes are all handled by
* this package as appropriate. This methods are only useful for non
* standard attributes.</p>
*
* <p>One application of this attributes are installation classes.
* These classes have a special attribute containing a zip of the
* files that should be installed. There are other possible uses,
* e.g. putting native machine code for some architectures into the
* class.</p>
* *
* @author Jochen Hoenicke * @author Jochen Hoenicke
*/ */
class BinaryInfo { public class BinaryInfo {
private Map unknownAttributes = null; private Map unknownAttributes = null;
void skipAttributes(DataInputStream input) throws IOException { void skipAttributes(DataInputStream input) throws IOException {
@ -140,7 +156,8 @@ class BinaryInfo {
} }
} }
public void dropAttributes() { void drop(int keep) {
if (keep < ClassInfo.ALL)
unknownAttributes = null; unknownAttributes = null;
} }
@ -178,7 +195,7 @@ class BinaryInfo {
} }
} }
public int getAttributeSize() { int getAttributeSize() {
int size = 2; /* attribute count */ int size = 2; /* attribute count */
if (unknownAttributes != null) { if (unknownAttributes != null) {
Iterator i = unknownAttributes.values().iterator(); Iterator i = unknownAttributes.values().iterator();
@ -188,31 +205,55 @@ class BinaryInfo {
return size; return size;
} }
/**
* Finds a non standard attribute with the given name.
* @param name the name of the attribute.
* @return the contents of the attribute, null if not found.
*/
public byte[] findAttribute(String name) { public byte[] findAttribute(String name) {
if (unknownAttributes != null) if (unknownAttributes != null)
return (byte[]) unknownAttributes.get(name); return (byte[]) unknownAttributes.get(name);
return null; return null;
} }
/**
* Gets all non standard attributes
*/
public Iterator getAttributes() { public Iterator getAttributes() {
if (unknownAttributes != null) if (unknownAttributes != null)
return unknownAttributes.values().iterator(); return unknownAttributes.values().iterator();
return Collections.EMPTY_SET.iterator(); return Collections.EMPTY_SET.iterator();
} }
public void setAttribute(String name, byte[] content) { /**
* Adds a new non standard attribute or replaces an old one with the
* same name.
* @param name the name of the attribute.
* @param contents the new contens.
*/
public void setAttribute(String name, byte[] contents) {
if (unknownAttributes == null) if (unknownAttributes == null)
unknownAttributes = new SimpleMap(); unknownAttributes = new SimpleMap();
unknownAttributes.put(name, content); unknownAttributes.put(name, contents);
} }
/**
* Removes a new non standard attribute.
* @param name the name of the attribute.
* @return the old contents of the attribute.
*/
public byte[] removeAttribute(String name) { public byte[] removeAttribute(String name) {
if (unknownAttributes != null) if (unknownAttributes != null)
return (byte[]) unknownAttributes.remove(name); return (byte[]) unknownAttributes.remove(name);
return null; return null;
} }
/**
* Removes all non standard attribute.
*/
public void removeAllAttributes() { public void removeAllAttributes() {
unknownAttributes = null; unknownAttributes = null;
} }
} }

@ -1,4 +1,4 @@
/* Block Copyright (C) 1999 Jochen Hoenicke. /* Block Copyright (C) 2000 Jochen Hoenicke.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -28,12 +28,48 @@ import java.util.Iterator;
///#enddef ///#enddef
/** /**
* Represents a single basic block. It contains a list of * <p>Represents a single basic block. It contains a list of
* instructions, the successor blocks and the exception handlers for * instructions and the successor blocks.</p>
* this block. The last Instruction, and only the last, may be a
* conditional jump, a tableswitch or a jsr.
* *
* @author Jochen Hoenicke */ * <p>All jump instructions must be at the end of the block. These
* jump instructions are <code>opc_lookupswitch</code>,
* <code>opc_if</code>xxx, <code>opc_jsr</code>, <code>opc_ret</code>,
* <code>opc_</code>x<code>return</code> and <code>opc_return</code>.
* An <code>opc_goto</code> is implicit if the basic block doesn't end
* with a jump instructions, or if it ends with an conditional jump or
* jsr.</p>
*
* <p>The jump instructions don't remember their destinations, instead
* the Block does it. This are the successor block. There are
* several cases:</p>
*
* <ul>
* <li>Block ends with <code>opc_lookupswitch</code> with
* <code>n</code> values. Then there must be <code>n+1</code>
* successors where the first <code>n</code> successors correspond to
* the values and the last successor is the default successor.</li>
* <li>Block ends with <code>opc_if</code>xxx, then there must be two
* successors: The first one is the successor if the condition evaluates
* to true, the second one is for the false branch. </li>
* <li>Block ends with <code>opc_jsr</code>, then there must be two
* successors: The first one is the subroutine, the second is the next
* block after the subroutine. </li>
* <li>Block ends with <code>opc_</code>x</code>return</code> or
* <code>opc_ret</code>, then there must no successor at all. </li>
* <li>In any other case there must be exactly one successor.</li>
* </ul>
*
* <p>If any successor is <code>null</code> it represents end of
* method, i.e. a return instruction. You can also use
* <code>null</code> successors for conditional jumps and switch
* instruction. You normally shouldn't use <code>opc_return</code>
* instructions. They are only necessary, if you want to return with
* a non-empty stack. </p>
*
* @author Jochen Hoenicke
* @see jode.bytecode.BasicBlocks
* @see jode.bytecode.Instruction
*/
public final class Block { public final class Block {
/** /**
* The opcodes of the instructions in this block. * The opcodes of the instructions in this block.
@ -55,6 +91,21 @@ public final class Block {
*/ */
int blockNr; int blockNr;
/**
* The blockNr of this block. Set by BasicBlocks.
*/
int lineNr;
/**
* The number of items this block takes from the stack.
*/
int pop;
/**
* The number of items this block puts on the stack.
*/
int push;
/** /**
* Creates a new empty block, with a null successor array. * Creates a new empty block, with a null successor array.
*/ */
@ -68,8 +119,8 @@ public final class Block {
* modified, except that the instructions (but not their opcodes) * modified, except that the instructions (but not their opcodes)
* may be modified. * may be modified.
*/ */
public List getInstructions() { public Instruction[] getInstructions() {
return Arrays.asList(instrs); return instrs;
} }
/** /**
@ -105,35 +156,45 @@ public final class Block {
return blockNr; return blockNr;
} }
private void checkConsistent() { private void initCode() {
/* Check if all instructions are of correct type */
int size = instrs.length; int size = instrs.length;
int depth = 0;
int poppush[] = new int[2];
boolean needGoto = true;
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
instrs[i].getStackPopPush(poppush);
depth += poppush[0];
if (pop < depth)
pop = depth;
depth -= poppush[1];
int opcode = instrs[i].getOpcode(); int opcode = instrs[i].getOpcode();
switch (opcode) { switch (opcode) {
case Opcodes.opc_goto: case Opcodes.opc_goto:
throw new IllegalArgumentException("goto in block"); throw new IllegalArgumentException("goto in block");
case Opcodes.opc_lookupswitch: case Opcodes.opc_lookupswitch:
if (succs == null || succs.length == 0) if (succs.length != instrs[i].getValues().length + 1)
throw new IllegalArgumentException throw new IllegalArgumentException
("no successors for switch"); ("no successors for switch");
if (i != size - 1) if (i != size - 1)
throw new IllegalArgumentException throw new IllegalArgumentException
("switch in the middle!"); ("switch in the middle!");
return; needGoto = false;
break;
case Opcodes.opc_ret: case Opcodes.opc_athrow: case Opcodes.opc_ret: case Opcodes.opc_athrow:
case Opcodes.opc_ireturn: case Opcodes.opc_lreturn: case Opcodes.opc_ireturn: case Opcodes.opc_lreturn:
case Opcodes.opc_freturn: case Opcodes.opc_dreturn: case Opcodes.opc_freturn: case Opcodes.opc_dreturn:
case Opcodes.opc_areturn: case Opcodes.opc_return: case Opcodes.opc_areturn: case Opcodes.opc_return:
if (succs == null || succs.length > 0) if (succs.length != 0)
throw new IllegalArgumentException throw new IllegalArgumentException
("throw or return with successor."); ("throw or return with successor.");
if (i != size - 1) if (i != size - 1)
throw new IllegalArgumentException throw new IllegalArgumentException
("return in the middle!"); ("return in the middle!");
return; needGoto = false;
break;
case Opcodes.opc_ifeq: case Opcodes.opc_ifne: case Opcodes.opc_ifeq: case Opcodes.opc_ifne:
case Opcodes.opc_iflt: case Opcodes.opc_ifge: case Opcodes.opc_iflt: case Opcodes.opc_ifge:
@ -144,29 +205,38 @@ public final class Block {
case Opcodes.opc_if_acmpeq: case Opcodes.opc_if_acmpne: case Opcodes.opc_if_acmpeq: case Opcodes.opc_if_acmpne:
case Opcodes.opc_ifnull: case Opcodes.opc_ifnonnull: case Opcodes.opc_ifnull: case Opcodes.opc_ifnonnull:
case Opcodes.opc_jsr: case Opcodes.opc_jsr:
if (succs == null || succs.length != 2) if (succs.length != 2)
throw new IllegalArgumentException throw new IllegalArgumentException
("successors inappropriate for if/jsr"); ("successors inappropriate for if/jsr");
if (succs[0] == null && opcode == Opcodes.opc_jsr)
throw new IllegalArgumentException
("null successors inappropriate for jsr");
if (i != size - 1) if (i != size - 1)
throw new IllegalArgumentException throw new IllegalArgumentException
("if/jsr in the middle!"); ("if/jsr in the middle!");
return; needGoto = false;
} }
} }
if (succs == null || succs.length != 1) push = pop - depth;
if (needGoto && succs.length != 1)
throw new IllegalArgumentException("no single successor block"); throw new IllegalArgumentException("no single successor block");
} }
public void getStackPopPush (int[] poppush) {
poppush[0] = pop;
poppush[1] = push;
return;
}
/** /**
* Set the code, i.e. instructions and successor blocks. * Set the code, i.e. instructions and successor blocks.
* The instructions must be valid and match the successors. * The instructions must be valid and match the successors.
*/ */
public void setCode(Collection instrs, Block[] succs) { public void setCode(Instruction[] instrs, Block[] succs) {
this.instrs = (Instruction[]) this.instrs = instrs;
instrs.toArray(new Instruction[instrs.size()]);
this.succs = succs; this.succs = succs;
try { try {
checkConsistent(); initCode();
} catch (IllegalArgumentException ex) { } catch (IllegalArgumentException ex) {
dumpCode(jode.GlobalOptions.err); dumpCode(jode.GlobalOptions.err);
throw ex; throw ex;

@ -228,6 +228,7 @@ public final class ClassInfo extends BinaryInfo implements Comparable {
private int status = 0; private int status = 0;
private boolean modified = false; private boolean modified = false;
private boolean isGuessed = false;
private ClassPath classpath; private ClassPath classpath;
private int modifiers = -1; private int modifiers = -1;
@ -291,6 +292,14 @@ public final class ClassInfo extends BinaryInfo implements Comparable {
* @see #load * @see #load
*/ */
public static final int DECLARATIONS = 30; public static final int DECLARATIONS = 30;
/**
* This constant can be used as parameter to load. It specifies
* that everything in the class except debugging information and
* non-standard attributes should be loaded.
*
* @see #load
*/
public static final int NODEBUG = 80;
/** /**
* This constant can be used as parameter to load. It specifies * This constant can be used as parameter to load. It specifies
* that everything in the class except non-standard attributes * that everything in the class except non-standard attributes
@ -574,6 +583,7 @@ public final class ClassInfo extends BinaryInfo implements Comparable {
className = name.substring(dollar+1); className = name.substring(dollar+1);
outerClass = classpath.getClassInfo(declarer.getName()); outerClass = classpath.getClassInfo(declarer.getName());
/* As mentioned above OUTERCLASS is recursive */ /* As mentioned above OUTERCLASS is recursive */
if (outerClass.status < OUTERCLASS)
outerClass.loadFromReflection(declarer, OUTERCLASS); outerClass.loadFromReflection(declarer, OUTERCLASS);
} else { } else {
/* Check if class name ends with $[numeric]$name or /* Check if class name ends with $[numeric]$name or
@ -610,7 +620,6 @@ public final class ClassInfo extends BinaryInfo implements Comparable {
interfaces = new ClassInfo[ifaces.length]; interfaces = new ClassInfo[ifaces.length];
for (int i=0; i<ifaces.length; i++) for (int i=0; i<ifaces.length; i++)
interfaces[i] = classpath.getClassInfo(ifaces[i].getName()); interfaces[i] = classpath.getClassInfo(ifaces[i].getName());
status |= HIERARCHY;
} }
if (howMuch >= PUBLICDECLARATIONS) { if (howMuch >= PUBLICDECLARATIONS) {
Field[] fs; Field[] fs;
@ -670,6 +679,7 @@ public final class ClassInfo extends BinaryInfo implements Comparable {
for (int i = is.length; --i >= 0; ) { for (int i = is.length; --i >= 0; ) {
innerClasses[i] = classpath.getClassInfo(is[i].getName()); innerClasses[i] = classpath.getClassInfo(is[i].getName());
/* As mentioned above OUTERCLASS is loaded recursive */ /* As mentioned above OUTERCLASS is loaded recursive */
if (innerClasses[i].status < OUTERCLASS)
innerClasses[i].loadFromReflection(is[i], OUTERCLASS); innerClasses[i].loadFromReflection(is[i], OUTERCLASS);
} }
} else } else
@ -1002,8 +1012,11 @@ public final class ClassInfo extends BinaryInfo implements Comparable {
throw new IllegalStateException(name); throw new IllegalStateException(name);
if (status >= howMuch) if (status >= howMuch)
return; return;
if (classpath.loadClass(this, howMuch)) if (classpath.loadClass(this, howMuch)) {
if (status < howMuch)
throw new IllegalStateException("state = "+status);
return; return;
}
throw new FileNotFoundException(name); throw new FileNotFoundException(name);
} }
@ -1025,16 +1038,18 @@ public final class ClassInfo extends BinaryInfo implements Comparable {
*/ */
public void guess(int howMuch) public void guess(int howMuch)
{ {
if (howMuch >= OUTERCLASS && status < OUTERCLASS) { if (howMuch <= status)
throw new IllegalStateException("status = "+status);
isGuessed = true;
if (howMuch >= OUTERCLASS) {
modifiers = Modifier.PUBLIC | 0x20;
int dollar = name.lastIndexOf('$'); int dollar = name.lastIndexOf('$');
if (dollar == -1) { if (dollar == -1) {
/* normal class */ /* normal class */
} else if (Character.isDigit(name.charAt(dollar+1))) { } else if (Character.isDigit(name.charAt(dollar+1))) {
/* anonymous class */ /* anonymous class */
modifiers = Modifier.PUBLIC | 0x20;
methodScoped = true; methodScoped = true;
} else { } else {
modifiers = Modifier.PUBLIC | 0x20;
className = name.substring(dollar+1); className = name.substring(dollar+1);
int prevDollar = name.lastIndexOf('$', dollar); int prevDollar = name.lastIndexOf('$', dollar);
if (prevDollar >= 0 if (prevDollar >= 0
@ -1045,22 +1060,24 @@ public final class ClassInfo extends BinaryInfo implements Comparable {
outerClass = classpath.getClassInfo outerClass = classpath.getClassInfo
(name.substring(0, prevDollar)); (name.substring(0, prevDollar));
} else { } else {
/* inner class */ /* inner class, we assume it is static, so we don't
modifiers = Modifier.PUBLIC | 0x20; * get an exception when we search for the this$0
* parameter in an constructor invocation.
*/
modifiers |= Modifier.STATIC;
outerClass = classpath.getClassInfo outerClass = classpath.getClassInfo
(name.substring(0, dollar)); (name.substring(0, dollar));
} }
} }
} }
if (howMuch >= HIERARCHY && status < HIERARCHY) { if (howMuch >= HIERARCHY) {
modifiers = Modifier.PUBLIC | 0x20;
if (name.equals("java.lang.Object")) if (name.equals("java.lang.Object"))
superclass = null; superclass = null;
else else
superclass = classpath.getClassInfo("java.lang.Object"); superclass = classpath.getClassInfo("java.lang.Object");
interfaces = new ClassInfo[0]; interfaces = new ClassInfo[0];
} }
if (howMuch >= PUBLICDECLARATIONS && status < PUBLICDECLARATIONS) { if (howMuch >= PUBLICDECLARATIONS) {
methods = new MethodInfo[0]; methods = new MethodInfo[0];
fields = new FieldInfo[0]; fields = new FieldInfo[0];
innerClasses = new ClassInfo[0]; innerClasses = new ClassInfo[0];
@ -1070,7 +1087,7 @@ public final class ClassInfo extends BinaryInfo implements Comparable {
/** /**
* This is the counter part to load. It will drop all * This is the counter part to load. It will drop all
* informations up keep and clean up the memory. * informations bigger than "keep" and clean up the memory.
* @param keep tells how much info we should keep, can be * @param keep tells how much info we should keep, can be
* <code>NONE</code> or anything that <code>load</code> accepts. * <code>NONE</code> or anything that <code>load</code> accepts.
* @see #load * @see #load
@ -1080,7 +1097,7 @@ public final class ClassInfo extends BinaryInfo implements Comparable {
return; return;
if (modified) { if (modified) {
System.err.println("Dropping info between " + keep + " and " System.err.println("Dropping info between " + keep + " and "
+ status + " in modified class" + this + "."); + status + " in modified class " + this + ".");
Thread.dumpStack(); Thread.dumpStack();
return; return;
} }
@ -1101,23 +1118,21 @@ public final class ClassInfo extends BinaryInfo implements Comparable {
methods = null; methods = null;
status = keep; status = keep;
} else { } else {
if (keep < ALMOSTALL && status >= ALMOSTALL) {
for (int i=0; i < fields.length; i++)
fields[i].dropBody();
for (int i=0; i < methods.length; i++)
methods[i].dropBody();
}
if (status >= DECLARATIONS) if (status >= DECLARATIONS)
/* We don't drop non-public declarations, since this /* We don't drop non-public declarations, since this
* is not worth it. * is not worth it.
*/ */
keep = DECLARATIONS; keep = DECLARATIONS;
for (int i=0; i < fields.length; i++)
fields[i].drop(keep);
for (int i=0; i < methods.length; i++)
methods[i].drop(keep);
} }
if (keep < ALMOSTALL && status >= ALMOSTALL) { if (keep < ALMOSTALL)
sourceFile = null; sourceFile = null;
super.dropAttributes(); super.drop(keep);
}
status = keep; status = keep;
} }
@ -1129,6 +1144,10 @@ public final class ClassInfo extends BinaryInfo implements Comparable {
return name; return name;
} }
public boolean isGuessed() {
return isGuessed;
}
/** /**
* Returns the java class name of a class, without package or * Returns the java class name of a class, without package or
* outer classes. This is null for an anonymous class. For other * outer classes. This is null for an anonymous class. For other

@ -156,7 +156,7 @@ public class ClassPath {
private class LocalPath extends Path { private class LocalPath extends Path {
private File dir; private File dir;
private LocalPath(File path) { public LocalPath(File path) {
dir = path; dir = path;
} }
@ -253,7 +253,7 @@ public class ClassPath {
} while (name.length() > 0); } while (name.length() > 0);
} }
private ZipPath(ZipFile zipfile, String prefix) { public ZipPath(ZipFile zipfile, String prefix) {
this.file = zipfile; this.file = zipfile;
this.prefix = prefix; this.prefix = prefix;
@ -264,7 +264,7 @@ public class ClassPath {
} }
} }
private ZipPath(byte[] zipcontents, String prefix) public ZipPath(byte[] zipcontents, String prefix)
throws IOException throws IOException
{ {
this.contents = zipcontents; this.contents = zipcontents;
@ -354,9 +354,9 @@ public class ClassPath {
} }
private class URLPath extends Path { private class URLPath extends Path {
URL base; private URL base;
private URLPath(URL base) { public URLPath(URL base) {
this.base = base; this.base = base;
} }

@ -24,27 +24,17 @@ import jode.util.StringQuoter;
* This class represents an instruction in the byte code. * This class represents an instruction in the byte code.
* *
*/ */
public class ConstantInstruction extends Instruction { class ConstantInstruction extends Instruction {
/** /**
* The typesignature of the class/array. * The typesignature of the class/array.
*/ */
private Object constant; private Object constant;
/** ConstantInstruction(int opcode, Object constant) {
* Standard constructor: creates an opcode with parameter and super(opcode);
* lineNr.
*/
public ConstantInstruction(int opcode, Object constant, int lineNr) {
super(opcode, lineNr);
if (opcode != opc_ldc && opcode != opc_ldc2_w)
throw new IllegalArgumentException("Instruction has no typesig");
this.constant = constant; this.constant = constant;
} }
public ConstantInstruction(int opcode, Object constant) {
this(opcode, constant, -1);
}
public final Object getConstant() public final Object getConstant()
{ {
return constant; return constant;
@ -61,4 +51,3 @@ public class ConstantInstruction extends Instruction {
? StringQuoter.quote((String) constant) : constant); ? StringQuoter.quote((String) constant) : constant);
} }
} }

@ -44,7 +44,7 @@ public final class FieldInfo extends BinaryInfo implements Comparable {
this.modifier = modifier; this.modifier = modifier;
} }
protected void readAttribute(String name, int length, void readAttribute(String name, int length,
ConstantPool cp, ConstantPool cp,
DataInputStream input, DataInputStream input,
int howMuch) throws IOException { int howMuch) throws IOException {
@ -69,7 +69,7 @@ public final class FieldInfo extends BinaryInfo implements Comparable {
super.readAttribute(name, length, cp, input, howMuch); super.readAttribute(name, length, cp, input, howMuch);
} }
public void read(ConstantPool constantPool, void read(ConstantPool constantPool,
DataInputStream input, int howMuch) throws IOException { DataInputStream input, int howMuch) throws IOException {
modifier = input.readUnsignedShort(); modifier = input.readUnsignedShort();
name = constantPool.getUTF8(input.readUnsignedShort()); name = constantPool.getUTF8(input.readUnsignedShort());
@ -77,10 +77,10 @@ public final class FieldInfo extends BinaryInfo implements Comparable {
readAttributes(constantPool, input, howMuch); readAttributes(constantPool, input, howMuch);
} }
public void reserveSmallConstants(GrowableConstantPool gcp) { void reserveSmallConstants(GrowableConstantPool gcp) {
} }
public void prepareWriting(GrowableConstantPool gcp) { void prepareWriting(GrowableConstantPool gcp) {
gcp.putUTF8(name); gcp.putUTF8(name);
gcp.putUTF8(typeSig); gcp.putUTF8(typeSig);
if (constant != null) { if (constant != null) {
@ -108,7 +108,7 @@ public final class FieldInfo extends BinaryInfo implements Comparable {
return count; return count;
} }
public void writeKnownAttributes(GrowableConstantPool gcp, void writeKnownAttributes(GrowableConstantPool gcp,
DataOutputStream output) DataOutputStream output)
throws IOException { throws IOException {
if (constant != null) { if (constant != null) {
@ -132,7 +132,7 @@ public final class FieldInfo extends BinaryInfo implements Comparable {
} }
} }
public void write(GrowableConstantPool constantPool, void write(GrowableConstantPool constantPool,
DataOutputStream output) throws IOException { DataOutputStream output) throws IOException {
output.writeShort(modifier); output.writeShort(modifier);
output.writeShort(constantPool.putUTF8(name)); output.writeShort(constantPool.putUTF8(name));
@ -140,8 +140,10 @@ public final class FieldInfo extends BinaryInfo implements Comparable {
writeAttributes(constantPool, output); writeAttributes(constantPool, output);
} }
public void dropBody() { void drop(int keep) {
super.dropAttributes(); if (keep < ClassInfo.DECLARATIONS)
constant = null;
super.drop(keep);
} }
public String getName() { public String getName() {

@ -1,4 +1,4 @@
/* Handler Copyright (C) 1999 Jochen Hoenicke. /* Handler Copyright (C) 2000 Jochen Hoenicke.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

@ -23,28 +23,18 @@ package jode.bytecode;
* This class represents an instruction in the byte code. * This class represents an instruction in the byte code.
* *
*/ */
public class IncInstruction extends SlotInstruction { class IncInstruction extends SlotInstruction {
/** /**
* The amount of increment. * The amount of increment.
*/ */
private int increment; private int increment;
/**
* Standard constructor: creates an opcode with parameter and
* lineNr.
*/
public IncInstruction(int opcode, int slot, int increment, int lineNr) {
super(opcode, slot, lineNr);
if (opcode != opc_iinc)
throw new IllegalArgumentException("Instruction has no increment");
this.increment = increment;
}
/** /**
* Creates a simple opcode, without any parameters. * Creates a simple opcode, without any parameters.
*/ */
public IncInstruction(int opcode, int slot, int increment) { IncInstruction(int opcode, LocalVariableInfo lvi, int increment) {
this(opcode, slot, increment, -1); super(opcode, lvi);
this.increment = increment;
} }
/** /**

@ -22,6 +22,20 @@ package jode.bytecode;
/** /**
* This class represents an instruction in the byte code. * This class represents an instruction in the byte code.
* *
* We only allow a subset of opcodes. Other opcodes are mapped to
* their simpler version. When writing the bytecode the shortest
* possible bytecode is produced.
*
* The opcodes we map are:
* <pre>
* [iflda]load_x -&gt; [iflda]load
* [iflda]store_x -&gt; [iflda]store
* [ifa]const_xx, ldc_w -&gt; ldc
* [dl]const_xx -&gt; ldc2_w
* wide opcode -&gt; opcode
* tableswitch -&gt; lookupswitch
* [a]newarray -&gt; multianewarray
* </pre>
*/ */
public class Instruction implements Opcodes{ public class Instruction implements Opcodes{
/** /**
@ -32,80 +46,173 @@ public class Instruction implements Opcodes{
*/ */
private int lineAndOpcode; private int lineAndOpcode;
/**
* Creates a new simple Instruction with no parameters. We map
* some opcodes, so you must always use the mapped opcode.
* @param opcode the opcode of this instruction.
* @exception IllegalArgumentException if opcode is not in our subset
* or if opcode needs a parameter. */
public static Instruction forOpcode(int opcode) {
switch (opcode) {
case opc_nop:
case opc_iaload: case opc_laload: case opc_faload:
case opc_daload: case opc_aaload:
case opc_baload: case opc_caload: case opc_saload:
case opc_iastore: case opc_lastore: case opc_fastore:
case opc_dastore: case opc_aastore:
case opc_bastore: case opc_castore: case opc_sastore:
case opc_pop: case opc_pop2:
case opc_dup: case opc_dup_x1: case opc_dup_x2:
case opc_dup2: case opc_dup2_x1: case opc_dup2_x2:
case opc_swap:
case opc_iadd: case opc_ladd: case opc_fadd: case opc_dadd:
case opc_isub: case opc_lsub: case opc_fsub: case opc_dsub:
case opc_imul: case opc_lmul: case opc_fmul: case opc_dmul:
case opc_idiv: case opc_ldiv: case opc_fdiv: case opc_ddiv:
case opc_irem: case opc_lrem: case opc_frem: case opc_drem:
case opc_ineg: case opc_lneg: case opc_fneg: case opc_dneg:
case opc_ishl: case opc_lshl:
case opc_ishr: case opc_lshr:
case opc_iushr: case opc_lushr:
case opc_iand: case opc_land:
case opc_ior: case opc_lor:
case opc_ixor: case opc_lxor:
case opc_i2l: case opc_i2f: case opc_i2d:
case opc_l2i: case opc_l2f: case opc_l2d:
case opc_f2i: case opc_f2l: case opc_f2d:
case opc_d2i: case opc_d2l: case opc_d2f:
case opc_i2b: case opc_i2c: case opc_i2s:
case opc_lcmp: case opc_fcmpl: case opc_fcmpg:
case opc_dcmpl: case opc_dcmpg:
case opc_ireturn: case opc_lreturn:
case opc_freturn: case opc_dreturn: case opc_areturn:
case opc_return:
case opc_athrow:
case opc_arraylength:
case opc_monitorenter: case opc_monitorexit:
case opc_goto:
case opc_jsr:
case opc_ifeq: case opc_ifne:
case opc_iflt: case opc_ifge:
case opc_ifgt: case opc_ifle:
case opc_if_icmpeq: case opc_if_icmpne:
case opc_if_icmplt: case opc_if_icmpge:
case opc_if_icmpgt: case opc_if_icmple:
case opc_if_acmpeq: case opc_if_acmpne:
case opc_ifnull: case opc_ifnonnull:
return new Instruction(opcode);
default:
throw new IllegalArgumentException("Instruction has a parameter");
}
}
/**
* Creates a new ldc Instruction.
* @param opcode the opcode of this instruction.
* @param constant the constant parameter.
* @exception IllegalArgumentException if opcode is not opc_ldc or
* opc_ldc2_w.
*/
public Instruction forOpcode(int opcode, Object constant) {
if (opcode == opc_ldc || opcode == opc_ldc2_w)
return new ConstantInstruction(opcode, constant);
throw new IllegalArgumentException("Instruction has no constant");
}
/**
* Creates a new Instruction with a local variable as parameter.
* @param opcode the opcode of this instruction.
* @param lvi the local variable parameter.
* @exception IllegalArgumentException if opcode is not in our subset
* or if opcode doesn't need a single local variable as parameter.
*/
public static Instruction forOpcode(int opcode, LocalVariableInfo lvi) {
if (opcode == opc_ret
|| opcode >= opc_iload && opcode <= opc_aload
|| opcode >= opc_istore && opcode <= opc_astore)
return new SlotInstruction(opcode, lvi);
throw new IllegalArgumentException("Instruction has no slot");
}
/**
* Creates a new Instruction with reference as parameter.
* @param opcode the opcode of this instruction.
* @param reference the reference parameter.
* @exception IllegalArgumentException if opcode is not in our subset
* or if opcode doesn't need a reference as parameter.
*/
public static Instruction forOpcode(int opcode, Reference reference) {
if (opcode >= opc_getstatic && opcode <= opc_invokeinterface)
return new ReferenceInstruction(opcode, reference);
throw new IllegalArgumentException("Instruction has no reference");
}
/**
* Creates a new Instruction with type signature as parameter.
* @param opcode the opcode of this instruction.
* @param typeSig the type signature parameter.
* @exception IllegalArgumentException if opcode is not in our subset
* or if opcode doesn't need a type signature as parameter.
*/
public static Instruction forOpcode(int opcode, String typeSig) {
switch (opcode) {
case opc_new:
case opc_checkcast:
case opc_instanceof:
return new TypeInstruction(opcode, typeSig);
default:
throw new IllegalArgumentException("Instruction has no type");
}
}
// /** /**
// * Optional object data for this opcode. There are six different * Creates a new switch Instruction.
// * usages of this field: * @param opcode the opcode of this instruction must be opc_lookupswitch.
// * <dl> * @param values an array containing the different cases.
// * <dt>opc_ldc / opc_ldc2_w</dt> * @exception IllegalArgumentException if opcode is not opc_lookupswitch.
// * <dd>The constant of type Integer/Long/Float/Double/String. </dd> */
// * <dt>opc_invokexxx / opc_xxxfield / opc_xxxstatic</dt> public static Instruction forOpcode(int opcode, int[] values) {
// * <dd>The field/method Reference</dd> if (opcode == opc_lookupswitch)
// * <dt>opc_new / opc_checkcast / opc_instanceof</dt> return new SwitchInstruction(opcode, values);
// * <dd>The typesignature of the class/array</dd> throw new IllegalArgumentException("Instruction has no values");
// * <dt>opc_lookupswitch</dt> }
// * <dd>The array of values of type int[]</dd>
// * <dt>opc_multianewarray</dt>
// * <dd>A DoubleParam: intValue contains dimension, objValue contains
// * reference </dd>
// * <dt>opc_[aildf]{load,store}</dt>
// * <dd>The LocalVariableInfo</dd>
// * <dt>opc_iinc</dt>
// * <dd>A DoubleParam: intValue contains count, objValue contains
// * local variable info.</dd>
// * </dl>
// */
// private Object param;
// /**
// * Create a new Instruction suitable for the given opcode. We map
// * some opcodes, so you must always use the mapped opcode.
// * <pre>
// * [iflda]load_x -&gt; [iflda]load
// * [iflda]store_x -&gt; [iflda]store
// * [ifa]const_xx, ldc_w -&gt; ldc
// * [dl]const_xx -&gt; ldc2_w
// * wide opcode -&gt; opcode
// * tableswitch -&gt; lookupswitch
// * [a]newarray -&gt; multianewarray
// * </pre>
// */
// public static Instruction forOpcode(int opcode) {
// if (opcode == opc_iinc)
// return new IncInstruction(opcode);
// else if (opcode == opc_ret
// || opcode >= opc_iload && opcode <= opc_aload
// || opcode >= opc_istore && opcode <= opc_astore)
// return new SlotInstruction(opcode);
// else if (opcode >= opc_getstatic && opcode <= opc_invokeinterface)
// return new ReferenceInstruction(opcode);
// else switch (opcode) {
// case opc_new:
// case opc_checkcast:
// case opc_instanceof:
// return new TypeInstruction(opcode);
// case opc_multianewarray:
// return new TypeDimensionInstruction(opcode);
// default:
// return new Instruction(opcode);
// }
// }
/** /**
* Standard constructor: creates an opcode with parameter and * Creates a new increment Instruction.
* lineNr. * @param opcode the opcode of this instruction.
* @param lvi the local variable parameter.
* @param increment the increment parameter.
* @exception IllegalArgumentException if opcode is not opc_iinc.
*/ */
public Instruction(int opcode, int lineNr) { public static Instruction forOpcode(int opcode,
if (stackDelta.charAt(opcode) == '\177') LocalVariableInfo lvi, int increment) {
throw new IllegalArgumentException("Unknown opcode: "+opcode); if (opcode == opc_iinc)
this.lineAndOpcode = (lineNr << 8) | opcode; return new IncInstruction(opcode, lvi, increment);
throw new IllegalArgumentException("Instruction has no increment");
}
/**
* Creates a new Instruction with type signature and a dimension
* as parameter.
* @param opcode the opcode of this instruction.
* @param typeSig the type signature parameter.
* @param dimension the array dimension parameter.
* @exception IllegalArgumentException if opcode is not
* opc_multianewarray.
*/
public static Instruction forOpcode(int opcode,
String typeSig, int dimension) {
if (opcode == opc_multianewarray)
return new TypeDimensionInstruction(opcode, typeSig, dimension);
throw new IllegalArgumentException("Instruction has no dimension");
} }
/** /**
* Creates a simple opcode, without any parameters. * Creates a simple opcode, without any parameters.
*/ */
public Instruction(int opcode) { Instruction(int opcode) {
this(opcode, -1); this.lineAndOpcode = (-1 << 8) | opcode;
} }
/** /**
@ -263,6 +370,12 @@ public class Instruction implements Opcodes{
poppush[1] = delta >> 3; poppush[1] = delta >> 3;
} }
/**
* Gets a printable representation of the opcode with its
* parameters. This will not include the destination for jump
* instructions, since this information is not stored inside the
* instruction.
*/
public final String getDescription() { public final String getDescription() {
return toString(); return toString();
} }
@ -276,6 +389,6 @@ public class Instruction implements Opcodes{
* \177 if opcode is illegal, or 8*stack_push + stack_pop otherwise * \177 if opcode is illegal, or 8*stack_push + stack_pop otherwise
* The string is created by scripts/createStackDelta.pl * The string is created by scripts/createStackDelta.pl
*/ */
protected final static String stackDelta = final static String stackDelta =
"\000\010\010\010\010\010\010\010\010\020\020\010\010\010\020\020\010\010\010\010\020\010\020\010\020\010\010\010\010\010\020\020\020\020\010\010\010\010\020\020\020\020\010\010\010\010\012\022\012\022\012\012\012\012\001\002\001\002\001\001\001\001\001\002\002\002\002\001\001\001\001\002\002\002\002\001\001\001\001\003\004\003\004\003\003\003\003\001\002\021\032\043\042\053\064\022\012\024\012\024\012\024\012\024\012\024\012\024\012\024\012\024\012\024\012\024\011\022\011\022\012\023\012\023\012\023\012\024\012\024\012\024\000\021\011\021\012\012\022\011\021\021\012\022\012\011\011\011\014\012\012\014\014\001\001\001\001\001\001\002\002\002\002\002\002\002\002\000\000\000\001\001\001\002\001\002\001\000\100\100\100\100\100\100\100\100\177\010\011\011\011\001\011\011\001\001\177\100\001\001\000\000"; "\000\010\010\010\010\010\010\010\010\020\020\010\010\010\020\020\010\010\010\010\020\010\020\010\020\010\010\010\010\010\020\020\020\020\010\010\010\010\020\020\020\020\010\010\010\010\012\022\012\022\012\012\012\012\001\002\001\002\001\001\001\001\001\002\002\002\002\001\001\001\001\002\002\002\002\001\001\001\001\003\004\003\004\003\003\003\003\001\002\021\032\043\042\053\064\022\012\024\012\024\012\024\012\024\012\024\012\024\012\024\012\024\012\024\012\024\011\022\011\022\012\023\012\023\012\023\012\024\012\024\012\024\000\021\011\021\012\012\022\011\021\021\012\022\012\011\011\011\014\012\012\014\014\001\001\001\001\001\001\002\002\002\002\002\002\002\002\000\000\000\001\001\001\002\001\002\001\000\100\100\100\100\100\100\100\100\177\010\011\011\011\001\011\011\001\001\177\100\001\001\000\000";
} }

@ -47,7 +47,7 @@ public final class MethodInfo extends BinaryInfo implements Comparable {
void readAttribute(String name, int length, ConstantPool cp, void readAttribute(String name, int length, ConstantPool cp,
DataInputStream input, int howMuch) throws IOException { DataInputStream input, int howMuch) throws IOException {
if (howMuch >= ClassInfo.ALMOSTALL && name.equals("Code")) { if (howMuch >= ClassInfo.NODEBUG && name.equals("Code")) {
basicblocks = new BasicBlocks(this); basicblocks = new BasicBlocks(this);
basicblocks.read(cp, input, howMuch); basicblocks.read(cp, input, howMuch);
} else if (howMuch >= ClassInfo.DECLARATIONS } else if (howMuch >= ClassInfo.DECLARATIONS
@ -143,7 +143,7 @@ public final class MethodInfo extends BinaryInfo implements Comparable {
} }
} }
public void write(GrowableConstantPool constantPool, void write(GrowableConstantPool constantPool,
DataOutputStream output) throws IOException { DataOutputStream output) throws IOException {
output.writeShort(modifier); output.writeShort(modifier);
output.writeShort(constantPool.putUTF8(name)); output.writeShort(constantPool.putUTF8(name));
@ -151,9 +151,14 @@ public final class MethodInfo extends BinaryInfo implements Comparable {
writeAttributes(constantPool, output); writeAttributes(constantPool, output);
} }
public void dropBody() { void drop(int keep) {
if (keep < ClassInfo.DECLARATIONS)
exceptions = null;
if (keep < ClassInfo.NODEBUG)
basicblocks = null; basicblocks = null;
super.dropAttributes(); else
basicblocks.drop(keep);
super.drop(keep);
} }
public String getName() { public String getName() {

@ -23,26 +23,12 @@ package jode.bytecode;
* This class represents an instruction that needs a reference, i.e. * This class represents an instruction that needs a reference, i.e.
* a method invocation or field access instruction. * a method invocation or field access instruction.
*/ */
public final class ReferenceInstruction extends Instruction { class ReferenceInstruction extends Instruction {
private Reference reference; private Reference reference;
/**
* Standard constructor: creates an opcode with parameter and
* lineNr.
*/
public ReferenceInstruction(int opcode, Reference reference, int lineNr)
{
super(opcode, lineNr);
if (opcode < opc_getstatic || opcode > opc_invokeinterface)
throw new IllegalArgumentException("Instruction has no reference");
this.reference = reference;
}
/**
* Creates a simple opcode, without any parameters.
*/
public ReferenceInstruction(int opcode, Reference ref) { public ReferenceInstruction(int opcode, Reference ref) {
this(opcode, ref, -1); super(opcode);
this.reference = ref;
} }
public final Reference getReference() public final Reference getReference()
@ -67,8 +53,7 @@ public final class ReferenceInstruction extends Instruction {
/*{ require { poppush != null && poppush.length == 2 /*{ require { poppush != null && poppush.length == 2
:: "poppush must be an array of two ints" } } */ :: "poppush must be an array of two ints" } } */
{ {
Reference ref = getReference(); String typeSig = reference.getType();
String typeSig = ref.getType();
int opcode = getOpcode(); int opcode = getOpcode();
switch (opcode) { switch (opcode) {
case opc_invokevirtual: case opc_invokevirtual:

@ -23,36 +23,14 @@ package jode.bytecode;
* This class represents an instruction in the byte code. * This class represents an instruction in the byte code.
* *
*/ */
public class SlotInstruction extends Instruction { class SlotInstruction extends Instruction {
private LocalVariableInfo lvi; private LocalVariableInfo lvi;
/**
*/
public SlotInstruction(int opcode, LocalVariableInfo lvi, int lineNr) {
super(opcode, lineNr);
if (opcode != opc_iinc && opcode != opc_ret
&& (opcode < opc_iload || opcode > opc_aload)
&& (opcode < opc_istore || opcode > opc_astore))
throw new IllegalArgumentException("Instruction has no slot");
this.lvi = lvi;
}
/**
*/
public SlotInstruction(int opcode, int slot, int lineNr) {
this(opcode, LocalVariableInfo.getInfo(slot), lineNr);
}
/** /**
*/ */
public SlotInstruction(int opcode, LocalVariableInfo lvi) { public SlotInstruction(int opcode, LocalVariableInfo lvi) {
this(opcode, lvi, -1); super(opcode);
} this.lvi = lvi;
/**
*/
public SlotInstruction(int opcode, int slot) {
this(opcode, LocalVariableInfo.getInfo(slot), -1);
} }
public boolean isStore() { public boolean isStore() {

@ -24,7 +24,7 @@ import jode.util.StringQuoter;
* This class represents an instruction in the byte code. * This class represents an instruction in the byte code.
* *
*/ */
public class SwitchInstruction extends Instruction { class SwitchInstruction extends Instruction {
/** /**
* The values for this switch. * The values for this switch.
*/ */
@ -34,20 +34,11 @@ public class SwitchInstruction extends Instruction {
* Standard constructor: creates an opcode with parameter and * Standard constructor: creates an opcode with parameter and
* lineNr. * lineNr.
*/ */
public SwitchInstruction(int opcode, int[] values, int lineNr) { SwitchInstruction(int opcode, int[] values) {
super(opcode, lineNr); super(opcode);
if (opcode != opc_lookupswitch)
throw new IllegalArgumentException("Instruction is no switch");
this.values = values; this.values = values;
} }
/**
* Creates a simple opcode, without any parameters.
*/
public SwitchInstruction(int opcode, int[] values) {
this(opcode, values, -1);
}
public final int[] getValues() public final int[] getValues()
{ {
return values; return values;

@ -20,32 +20,18 @@
package jode.bytecode; package jode.bytecode;
/** /**
* This class represents an instruction in the byte code. * This class represents an opc_multianewarray instruction.
* *
*/ */
public class TypeDimensionInstruction extends TypeInstruction { class TypeDimensionInstruction extends TypeInstruction {
/** /**
* The dimension of this multianewarray operation. * The dimension of this multianewarray operation.
*/ */
private int dimension; private int dimension;
/**
* Standard constructor: creates an opcode with parameter and
* lineNr.
*/
public TypeDimensionInstruction(int opcode, String type, int dimension,
int lineNr) {
super(opcode, type, lineNr);
if (opcode != opc_multianewarray)
throw new IllegalArgumentException("Instruction has no dimension");
this.dimension = dimension;
}
/**
* Creates a simple opcode, without any parameters.
*/
public TypeDimensionInstruction(int opcode, String type, int dimension) { public TypeDimensionInstruction(int opcode, String type, int dimension) {
this(opcode, type, dimension, -1); super(opcode, type);
this.dimension = dimension;
} }
/** /**

@ -23,29 +23,15 @@ package jode.bytecode;
* This class represents an instruction in the byte code. * This class represents an instruction in the byte code.
* *
*/ */
public class TypeInstruction extends Instruction { class TypeInstruction extends Instruction {
/** /**
* The typesignature of the class/array. * The typesignature of the class/array.
*/ */
private String typeSig; private String typeSig;
/**
* Standard constructor: creates an opcode with parameter and
* lineNr.
*/
public TypeInstruction(int opcode, String typeSig, int lineNr) {
super(opcode, lineNr);
if (opcode != opc_new && opcode != opc_checkcast
&& opcode != opc_instanceof && opcode != opc_multianewarray)
throw new IllegalArgumentException("Instruction has no typesig");
this.typeSig = typeSig;
}
/**
* Creates a simple opcode, without any parameters.
*/
public TypeInstruction(int opcode, String typeSig) { public TypeInstruction(int opcode, String typeSig) {
this(opcode, typeSig, -1); super(opcode);
this.typeSig = typeSig;
} }
public final String getClazzType() public final String getClazzType()

@ -68,7 +68,7 @@ You can also use this package to create and write new classes:
... ...
ClassPath path = new ClassPath("/usr/lib/java/lib/classes.zip"); ClassPath path = new ClassPath("/usr/lib/java/lib/classes.zip");
ClassInfo clazz = path.getClassInfo("my.new.Class"); ClassInfo clazz = path.getClassInfo("my.new.Class");
clazz.setModifiers(Modifiers.PUBLIC); clazz.setModifiers(Modifier.PUBLIC);
clazz.setSourceFile("Class.pl"); clazz.setSourceFile("Class.pl");
clazz.set... clazz.set...
clazz.write(zipOutputStream); clazz.write(zipOutputStream);

Loading…
Cancel
Save