diff --git a/jode/jode/bytecode/BasicBlockReader.java b/jode/jode/bytecode/BasicBlockReader.java index 24ab8da..80af89c 100644 --- a/jode/jode/bytecode/BasicBlockReader.java +++ b/jode/jode/bytecode/BasicBlockReader.java @@ -256,7 +256,7 @@ class BasicBlockReader implements Opcodes { if (!alwaysJump) succs[succLength] = getSuccBlock(info.nextAddr); - blocks[blockNr].setCode(Arrays.asList(instrs), succs); + blocks[blockNr].setCode(instrs, succs); } void convert() throws ClassFormatException { @@ -331,7 +331,9 @@ class BasicBlockReader implements Opcodes { if (slot >= maxLocals) throw new ClassFormatException ("Invalid local slot "+slot); - instr = new SlotInstruction(wideopcode, slot); + LocalVariableInfo lvi + = LocalVariableInfo.getInfo(slot); + instr = new SlotInstruction(wideopcode, lvi); length = 4; if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_BYTECODE) != 0) @@ -345,7 +347,9 @@ class BasicBlockReader implements Opcodes { if (slot >= maxLocals-1) throw new ClassFormatException ("Invalid local slot "+slot); - instr = new SlotInstruction(wideopcode, slot); + LocalVariableInfo lvi + = LocalVariableInfo.getInfo(slot); + instr = new SlotInstruction(wideopcode, lvi); length = 4; if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_BYTECODE) != 0) @@ -358,7 +362,9 @@ class BasicBlockReader implements Opcodes { if (slot >= maxLocals) throw new ClassFormatException ("Invalid local slot "+slot); - instr = new SlotInstruction(wideopcode, slot); + LocalVariableInfo lvi + = LocalVariableInfo.getInfo(slot); + instr = new SlotInstruction(wideopcode, lvi); length = 4; if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_BYTECODE) != 0) @@ -370,8 +376,10 @@ class BasicBlockReader implements Opcodes { if (slot >= maxLocals) throw new ClassFormatException ("Invalid local slot "+slot); + LocalVariableInfo lvi + = LocalVariableInfo.getInfo(slot); int incr = input.readShort(); - instr = new IncInstruction(wideopcode, slot, incr); + instr = new IncInstruction(wideopcode, lvi, incr); length = 6; if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_BYTECODE) != 0) @@ -399,8 +407,10 @@ class BasicBlockReader implements Opcodes { if (slot >= maxLocals) throw new ClassFormatException ("Invalid local slot "+slot); + LocalVariableInfo lvi + = LocalVariableInfo.getInfo(slot); instr = new SlotInstruction - (opc_iload + (opcode-opc_iload_0)/4, slot); + (opc_iload + (opcode-opc_iload_0)/4, lvi); length = 1; break; } @@ -414,8 +424,10 @@ class BasicBlockReader implements Opcodes { if (slot >= maxLocals) throw new ClassFormatException ("Invalid local slot "+slot); + LocalVariableInfo lvi + = LocalVariableInfo.getInfo(slot); instr = new SlotInstruction - (opc_istore + (opcode-opc_istore_0)/4, slot); + (opc_istore + (opcode-opc_istore_0)/4, lvi); length = 1; break; } @@ -427,8 +439,10 @@ class BasicBlockReader implements Opcodes { if (slot >= maxLocals-1) throw new ClassFormatException ("Invalid local slot "+slot); + LocalVariableInfo lvi + = LocalVariableInfo.getInfo(slot); instr = new SlotInstruction - (opc_lstore + (opcode-opc_lstore_0)/4, slot); + (opc_lstore + (opcode-opc_lstore_0)/4, lvi); length = 1; break; } @@ -438,7 +452,9 @@ class BasicBlockReader implements Opcodes { if (slot >= maxLocals) throw new ClassFormatException ("Invalid local slot "+slot); - instr = new SlotInstruction(opcode, slot); + LocalVariableInfo lvi + = LocalVariableInfo.getInfo(slot); + instr = new SlotInstruction(opcode, lvi); length = 2; if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_BYTECODE) != 0) @@ -451,7 +467,9 @@ class BasicBlockReader implements Opcodes { if (slot >= maxLocals - 1) throw new ClassFormatException ("Invalid local slot "+slot); - instr = new SlotInstruction(opcode, slot); + LocalVariableInfo lvi + = LocalVariableInfo.getInfo(slot); + instr = new SlotInstruction(opcode, lvi); length = 2; if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_BYTECODE) != 0) @@ -463,7 +481,9 @@ class BasicBlockReader implements Opcodes { if (slot >= maxLocals) throw new ClassFormatException ("Invalid local slot "+slot); - instr = new SlotInstruction(opcode, slot); + LocalVariableInfo lvi + = LocalVariableInfo.getInfo(slot); + instr = new SlotInstruction(opcode, lvi); length = 2; if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_BYTECODE) != 0) @@ -535,8 +555,10 @@ class BasicBlockReader implements Opcodes { if (slot >= maxLocals) throw new ClassFormatException ("Invalid local slot "+slot); + LocalVariableInfo lvi + = LocalVariableInfo.getInfo(slot); int incr = input.readByte(); - instr = new IncInstruction(opcode, slot, incr); + instr = new IncInstruction(opcode, lvi, incr); length = 3; if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_BYTECODE) != 0) @@ -958,3 +980,4 @@ class BasicBlockReader implements Opcodes { } } } + diff --git a/jode/jode/bytecode/BasicBlockWriter.java b/jode/jode/bytecode/BasicBlockWriter.java index 5f3198e..780c80c 100644 --- a/jode/jode/bytecode/BasicBlockWriter.java +++ b/jode/jode/bytecode/BasicBlockWriter.java @@ -89,11 +89,10 @@ class BasicBlockWriter implements Opcodes { int blockNr = block.getBlockNr(); LocalVariableInfo[] life = (LocalVariableInfo[]) atStart[blockNr].clone(); - for (Iterator iter = block.getInstructions().iterator(); - iter.hasNext() ; ) { - Instruction instr = (Instruction) iter.next(); - if (instr.hasLocal()) { - LocalVariableInfo lvi = instr.getLocalInfo(); + Instruction[] instrs = block.getInstructions(); + for (int i = 0; i < instrs.length; i++) { + if (instrs[i].hasLocal()) { + LocalVariableInfo lvi = instrs[i].getLocalInfo(); int slot = lvi.getSlot(); if (life[slot] != null && life[slot] != lvi) @@ -162,10 +161,9 @@ class BasicBlockWriter implements Opcodes { } } - int size = block.getInstructions().size(); - for (int k = 0; k < size; k++) { - Instruction instr - = (Instruction) block.getInstructions().get(k); + Instruction[] instrs = block.getInstructions(); + for (int k = 0; k < instrs.length; k++) { + Instruction instr = instrs[k]; if (instr.hasLocal()) { LocalVariableInfo lvi = instr.getLocalInfo(); int slot = lvi.getSlot(); @@ -227,12 +225,11 @@ class BasicBlockWriter implements Opcodes { next_block: for (int i = 0; i < blocks.length; i++) { blockAddr[i] = addr; - List instructions = blocks[i].getInstructions(); - int size = instructions.size(); - instrLength[i] = new int[size]; + Instruction[] instrs = blocks[i].getInstructions(); + instrLength[i] = new int[instrs.length]; Block[] succs = blocks[i].getSuccs(); - for (int j = 0; j < size; j++) { - Instruction instr = (Instruction) instructions.get(j); + for (int j = 0; j < instrs.length; j++) { + Instruction instr = instrs[j]; if (instr.hasLineNr()) lntCount++; @@ -637,10 +634,10 @@ class BasicBlockWriter implements Opcodes { Block[] succs = blocks[i].getSuccs(); if (addr != blockAddr[i]) throw new InternalError("Address calculation broken!"); - List instructions = blocks[i].getInstructions(); - int size = instructions.size(); + Instruction[] instructions = blocks[i].getInstructions(); + int size = instructions.length; for (int j = 0; j < size; j++) { - Instruction instr = (Instruction) instructions.get(j); + Instruction instr = instructions[j]; if (instr.hasLineNr()) { lnt[lntPtr++] = (short) addr; lnt[lntPtr++] = (short) instr.getLineNr(); diff --git a/jode/jode/bytecode/BasicBlocks.java b/jode/jode/bytecode/BasicBlocks.java index ad7464b..6e8db2e 100644 --- a/jode/jode/bytecode/BasicBlocks.java +++ b/jode/jode/bytecode/BasicBlocks.java @@ -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 * 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 import java.util.ArrayList; +import java.util.Arrays; import java.util.Iterator; import java.util.NoSuchElementException; ///#enddef @@ -36,22 +37,37 @@ import java.lang.UnsupportedOperationException; ///#enddef /** - *
This class gives another representation of the byte code of a - * method. The instructions are splitted into BasicBlocks, each an - * array of consecutive Instructions. It is not allowed that a goto - * jumps inside a basic block.
+ *Represents the byte code of a method in form of basic blocks. A + * basic block is a bunch of instructions, that must always execute in + * sequential order. Every basic block is represented by an Block + * object.
* - *All jumps must be at the end of the block. A conditional jump - * may be followed by a single goto, but there must not be any other - * jumps. If there is now unconditional jump at the end, the block - * implicitely flows into the next one.
+ *All jump instructions must be at the end of the block, and the
+ * jump instructions doesn't have to remember where they jump to.
+ * Instead this information is stored inside the blocks. See
+ * Block
for details.
Try block must span over some consecutive BasicBlocks and there - * catches must jump to the start of an basic block.
+ *A subroutine block, i.e. a block where some jsr instructions may
+ * jump to, must store its return address in a local variable
+ * immediately. There must be exactly one block with the
+ * corresponding opc_ret
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.
Deadcode will not be included in the BasicBlock, also - * BasicBlocks consisting of a single jump will be optimized away.
+ *Exception Handlers are represented by the Handler class. Their + * start/end range must span over some consecutive BasicBlocks and + * there handler must be another basic block.
* + *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.
+ * + *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.
+ * + * @see jode.bytecode.Block * @see jode.bytecode.Instruction */ public class BasicBlocks extends BinaryInfo { @@ -121,39 +137,6 @@ public class BasicBlocks extends BinaryInfo { 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 * exception handlers. @@ -215,7 +198,7 @@ public class BasicBlocks extends BinaryInfo { } private BasicBlockReader reader; - public void read(ConstantPool cp, + void read(ConstantPool cp, DataInputStream input, int howMuch) throws IOException { if ((GlobalOptions.debuggingFlags @@ -231,7 +214,7 @@ public class BasicBlocks extends BinaryInfo { dumpCode(GlobalOptions.err); } - protected void readAttribute(String name, int length, ConstantPool cp, + void readAttribute(String name, int length, ConstantPool cp, DataInputStream input, int howMuch) throws IOException { if (howMuch >= ClassInfo.ALMOSTALL @@ -248,7 +231,8 @@ public class BasicBlocks extends BinaryInfo { void reserveSmallConstants(GrowableConstantPool gcp) { for (int i=0; i < blocks.length; i++) { next_instr: - for (Iterator iter = blocks[i].getInstructions().iterator(); + for (Iterator iter + = Arrays.asList(blocks[i].getInstructions()).iterator(); iter.hasNext(); ) { Instruction instr = (Instruction) iter.next(); if (instr.getOpcode() == Opcodes.opc_ldc) { @@ -293,7 +277,7 @@ public class BasicBlocks extends BinaryInfo { writeAttributes(gcp, output); bbw = null; } - + public void dumpCode(PrintWriter output) { output.println(methodInfo.getName()+methodInfo.getType()+":"); if (startBlock == null) diff --git a/jode/jode/bytecode/BinaryInfo.java b/jode/jode/bytecode/BinaryInfo.java index a2d3e44..c808232 100644 --- a/jode/jode/bytecode/BinaryInfo.java +++ b/jode/jode/bytecode/BinaryInfo.java @@ -34,10 +34,26 @@ import java.util.Iterator; /** + *Represents a container for user specified attributes.
* - * @author Jochen Hoenicke + *Java bytecode is extensible: Classes, Methods and Fields may + * have any number of attributes. Every attribute has a name and some + * unformatted data.
+ * + *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.
+ * + *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.
+ * + * @author Jochen Hoenicke */ -class BinaryInfo { +public class BinaryInfo { private Map unknownAttributes = null; void skipAttributes(DataInputStream input) throws IOException { @@ -140,8 +156,9 @@ class BinaryInfo { } } - public void dropAttributes() { - unknownAttributes = null; + void drop(int keep) { + if (keep < ClassInfo.ALL) + unknownAttributes = null; } void prepareAttributes(GrowableConstantPool gcp) { @@ -178,7 +195,7 @@ class BinaryInfo { } } - public int getAttributeSize() { + int getAttributeSize() { int size = 2; /* attribute count */ if (unknownAttributes != null) { Iterator i = unknownAttributes.values().iterator(); @@ -188,31 +205,55 @@ class BinaryInfo { 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) { if (unknownAttributes != null) return (byte[]) unknownAttributes.get(name); return null; } + /** + * Gets all non standard attributes + */ public Iterator getAttributes() { if (unknownAttributes != null) return unknownAttributes.values().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) 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) { if (unknownAttributes != null) return (byte[]) unknownAttributes.remove(name); return null; } + /** + * Removes all non standard attribute. + */ public void removeAllAttributes() { unknownAttributes = null; } } + + diff --git a/jode/jode/bytecode/Block.java b/jode/jode/bytecode/Block.java index 2ebb456..3e4dd20 100644 --- a/jode/jode/bytecode/Block.java +++ b/jode/jode/bytecode/Block.java @@ -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 * it under the terms of the GNU General Public License as published by @@ -28,12 +28,48 @@ import java.util.Iterator; ///#enddef /** - * Represents a single basic block. It contains a list of - * instructions, the successor blocks and the exception handlers for - * this block. The last Instruction, and only the last, may be a - * conditional jump, a tableswitch or a jsr. + *Represents a single basic block. It contains a list of + * instructions and the successor blocks.
* - * @author Jochen Hoenicke */ + *All jump instructions must be at the end of the block. These
+ * jump instructions are opc_lookupswitch
,
+ * opc_if
xxx, opc_jsr
, opc_ret
,
+ * opc_
xreturn
and opc_return
.
+ * An opc_goto
is implicit if the basic block doesn't end
+ * with a jump instructions, or if it ends with an conditional jump or
+ * jsr.
The jump instructions don't remember their destinations, instead + * the Block does it. This are the successor block. There are + * several cases:
+ * + *opc_lookupswitch
with
+ * n
values. Then there must be n+1
+ * successors where the first n
successors correspond to
+ * the values and the last successor is the default successor.opc_if
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. opc_jsr
, then there must be two
+ * successors: The first one is the subroutine, the second is the next
+ * block after the subroutine. opc_
xreturn or
+ * opc_ret
, then there must no successor at all. If any successor is null
it represents end of
+ * method, i.e. a return instruction. You can also use
+ * null
successors for conditional jumps and switch
+ * instruction. You normally shouldn't use opc_return
+ * instructions. They are only necessary, if you want to return with
+ * a non-empty stack.
NONE
or anything that load
accepts.
* @see #load
@@ -1080,7 +1097,7 @@ public final class ClassInfo extends BinaryInfo implements Comparable {
return;
if (modified) {
System.err.println("Dropping info between " + keep + " and "
- + status + " in modified class" + this + ".");
+ + status + " in modified class " + this + ".");
Thread.dumpStack();
return;
}
@@ -1101,23 +1118,21 @@ public final class ClassInfo extends BinaryInfo implements Comparable {
methods = null;
status = keep;
} 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)
/* We don't drop non-public declarations, since this
* is not worth it.
*/
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;
- super.dropAttributes();
- }
+ super.drop(keep);
status = keep;
}
@@ -1129,6 +1144,10 @@ public final class ClassInfo extends BinaryInfo implements Comparable {
return name;
}
+ public boolean isGuessed() {
+ return isGuessed;
+ }
+
/**
* Returns the java class name of a class, without package or
* outer classes. This is null for an anonymous class. For other
diff --git a/jode/jode/bytecode/ClassPath.java b/jode/jode/bytecode/ClassPath.java
index bf13df5..e6c1c6e 100644
--- a/jode/jode/bytecode/ClassPath.java
+++ b/jode/jode/bytecode/ClassPath.java
@@ -156,7 +156,7 @@ public class ClassPath {
private class LocalPath extends Path {
private File dir;
- private LocalPath(File path) {
+ public LocalPath(File path) {
dir = path;
}
@@ -253,7 +253,7 @@ public class ClassPath {
} while (name.length() > 0);
}
- private ZipPath(ZipFile zipfile, String prefix) {
+ public ZipPath(ZipFile zipfile, String prefix) {
this.file = zipfile;
this.prefix = prefix;
@@ -264,7 +264,7 @@ public class ClassPath {
}
}
- private ZipPath(byte[] zipcontents, String prefix)
+ public ZipPath(byte[] zipcontents, String prefix)
throws IOException
{
this.contents = zipcontents;
@@ -354,9 +354,9 @@ public class ClassPath {
}
private class URLPath extends Path {
- URL base;
+ private URL base;
- private URLPath(URL base) {
+ public URLPath(URL base) {
this.base = base;
}
diff --git a/jode/jode/bytecode/ConstantInstruction.java b/jode/jode/bytecode/ConstantInstruction.java
index f91d456..16e319b 100644
--- a/jode/jode/bytecode/ConstantInstruction.java
+++ b/jode/jode/bytecode/ConstantInstruction.java
@@ -24,27 +24,17 @@ import jode.util.StringQuoter;
* This class represents an instruction in the byte code.
*
*/
-public class ConstantInstruction extends Instruction {
+class ConstantInstruction extends Instruction {
/**
* The typesignature of the class/array.
*/
private Object constant;
- /**
- * Standard constructor: creates an opcode with parameter and
- * 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");
+ ConstantInstruction(int opcode, Object constant) {
+ super(opcode);
this.constant = constant;
}
- public ConstantInstruction(int opcode, Object constant) {
- this(opcode, constant, -1);
- }
-
public final Object getConstant()
{
return constant;
@@ -61,4 +51,3 @@ public class ConstantInstruction extends Instruction {
? StringQuoter.quote((String) constant) : constant);
}
}
-
diff --git a/jode/jode/bytecode/FieldInfo.java b/jode/jode/bytecode/FieldInfo.java
index e5568cf..6da18a9 100644
--- a/jode/jode/bytecode/FieldInfo.java
+++ b/jode/jode/bytecode/FieldInfo.java
@@ -44,10 +44,10 @@ public final class FieldInfo extends BinaryInfo implements Comparable {
this.modifier = modifier;
}
- protected void readAttribute(String name, int length,
- ConstantPool cp,
- DataInputStream input,
- int howMuch) throws IOException {
+ void readAttribute(String name, int length,
+ ConstantPool cp,
+ DataInputStream input,
+ int howMuch) throws IOException {
if (howMuch >= ClassInfo.DECLARATIONS
&& name.equals("ConstantValue")) {
if (length != 2)
@@ -68,19 +68,19 @@ public final class FieldInfo extends BinaryInfo implements Comparable {
} else
super.readAttribute(name, length, cp, input, howMuch);
}
-
- public void read(ConstantPool constantPool,
- DataInputStream input, int howMuch) throws IOException {
+
+ void read(ConstantPool constantPool,
+ DataInputStream input, int howMuch) throws IOException {
modifier = input.readUnsignedShort();
name = constantPool.getUTF8(input.readUnsignedShort());
typeSig = constantPool.getUTF8(input.readUnsignedShort());
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(typeSig);
if (constant != null) {
@@ -108,8 +108,8 @@ public final class FieldInfo extends BinaryInfo implements Comparable {
return count;
}
- public void writeKnownAttributes(GrowableConstantPool gcp,
- DataOutputStream output)
+ void writeKnownAttributes(GrowableConstantPool gcp,
+ DataOutputStream output)
throws IOException {
if (constant != null) {
output.writeShort(gcp.putUTF8("ConstantValue"));
@@ -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 {
output.writeShort(modifier);
output.writeShort(constantPool.putUTF8(name));
@@ -140,8 +140,10 @@ public final class FieldInfo extends BinaryInfo implements Comparable {
writeAttributes(constantPool, output);
}
- public void dropBody() {
- super.dropAttributes();
+ void drop(int keep) {
+ if (keep < ClassInfo.DECLARATIONS)
+ constant = null;
+ super.drop(keep);
}
public String getName() {
diff --git a/jode/jode/bytecode/Handler.java b/jode/jode/bytecode/Handler.java
index 9fa38b1..5751e0d 100644
--- a/jode/jode/bytecode/Handler.java
+++ b/jode/jode/bytecode/Handler.java
@@ -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
* it under the terms of the GNU General Public License as published by
diff --git a/jode/jode/bytecode/IncInstruction.java b/jode/jode/bytecode/IncInstruction.java
index ceb8fe7..d51cd2b 100644
--- a/jode/jode/bytecode/IncInstruction.java
+++ b/jode/jode/bytecode/IncInstruction.java
@@ -23,28 +23,18 @@ package jode.bytecode;
* This class represents an instruction in the byte code.
*
*/
-public class IncInstruction extends SlotInstruction {
+class IncInstruction extends SlotInstruction {
/**
* The amount of 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.
*/
- public IncInstruction(int opcode, int slot, int increment) {
- this(opcode, slot, increment, -1);
+ IncInstruction(int opcode, LocalVariableInfo lvi, int increment) {
+ super(opcode, lvi);
+ this.increment = increment;
}
/**
diff --git a/jode/jode/bytecode/Instruction.java b/jode/jode/bytecode/Instruction.java
index 501edbc..2adfb05 100644
--- a/jode/jode/bytecode/Instruction.java
+++ b/jode/jode/bytecode/Instruction.java
@@ -22,6 +22,20 @@ package jode.bytecode;
/**
* 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:
+ * + * [iflda]load_x -> [iflda]load + * [iflda]store_x -> [iflda]store + * [ifa]const_xx, ldc_w -> ldc + * [dl]const_xx -> ldc2_w + * wide opcode -> opcode + * tableswitch -> lookupswitch + * [a]newarray -> multianewarray + **/ public class Instruction implements Opcodes{ /** @@ -32,80 +46,173 @@ public class Instruction implements Opcodes{ */ 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 -// * usages of this field: -// *
-// * [iflda]load_x -> [iflda]load -// * [iflda]store_x -> [iflda]store -// * [ifa]const_xx, ldc_w -> ldc -// * [dl]const_xx -> ldc2_w -// * wide opcode -> opcode -// * tableswitch -> lookupswitch -// * [a]newarray -> multianewarray -// *-// */ -// 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); -// } -// } + /** + * Creates a new switch Instruction. + * @param opcode the opcode of this instruction must be opc_lookupswitch. + * @param values an array containing the different cases. + * @exception IllegalArgumentException if opcode is not opc_lookupswitch. + */ + public static Instruction forOpcode(int opcode, int[] values) { + if (opcode == opc_lookupswitch) + return new SwitchInstruction(opcode, values); + throw new IllegalArgumentException("Instruction has no values"); + } /** - * Standard constructor: creates an opcode with parameter and - * lineNr. + * Creates a new increment Instruction. + * @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) { - if (stackDelta.charAt(opcode) == '\177') - throw new IllegalArgumentException("Unknown opcode: "+opcode); - this.lineAndOpcode = (lineNr << 8) | opcode; + public static Instruction forOpcode(int opcode, + LocalVariableInfo lvi, int increment) { + if (opcode == opc_iinc) + 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. */ - public Instruction(int opcode) { - this(opcode, -1); + Instruction(int opcode) { + this.lineAndOpcode = (-1 << 8) | opcode; } /** @@ -263,6 +370,12 @@ public class Instruction implements Opcodes{ 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() { return toString(); } @@ -276,6 +389,6 @@ public class Instruction implements Opcodes{ * \177 if opcode is illegal, or 8*stack_push + stack_pop otherwise * 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"; } diff --git a/jode/jode/bytecode/MethodInfo.java b/jode/jode/bytecode/MethodInfo.java index 520049e..f4227e0 100644 --- a/jode/jode/bytecode/MethodInfo.java +++ b/jode/jode/bytecode/MethodInfo.java @@ -47,7 +47,7 @@ public final class MethodInfo extends BinaryInfo implements Comparable { void readAttribute(String name, int length, ConstantPool cp, 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.read(cp, input, howMuch); } 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 { output.writeShort(modifier); output.writeShort(constantPool.putUTF8(name)); @@ -151,9 +151,14 @@ public final class MethodInfo extends BinaryInfo implements Comparable { writeAttributes(constantPool, output); } - public void dropBody() { - basicblocks = null; - super.dropAttributes(); + void drop(int keep) { + if (keep < ClassInfo.DECLARATIONS) + exceptions = null; + if (keep < ClassInfo.NODEBUG) + basicblocks = null; + else + basicblocks.drop(keep); + super.drop(keep); } public String getName() { diff --git a/jode/jode/bytecode/ReferenceInstruction.java b/jode/jode/bytecode/ReferenceInstruction.java index cc1ec71..271d198 100644 --- a/jode/jode/bytecode/ReferenceInstruction.java +++ b/jode/jode/bytecode/ReferenceInstruction.java @@ -23,26 +23,12 @@ package jode.bytecode; * This class represents an instruction that needs a reference, i.e. * a method invocation or field access instruction. */ -public final class ReferenceInstruction extends Instruction { +class ReferenceInstruction extends Instruction { 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) { - this(opcode, ref, -1); + super(opcode); + this.reference = ref; } public final Reference getReference() @@ -67,8 +53,7 @@ public final class ReferenceInstruction extends Instruction { /*{ require { poppush != null && poppush.length == 2 :: "poppush must be an array of two ints" } } */ { - Reference ref = getReference(); - String typeSig = ref.getType(); + String typeSig = reference.getType(); int opcode = getOpcode(); switch (opcode) { case opc_invokevirtual: diff --git a/jode/jode/bytecode/SlotInstruction.java b/jode/jode/bytecode/SlotInstruction.java index b232837..02246e9 100644 --- a/jode/jode/bytecode/SlotInstruction.java +++ b/jode/jode/bytecode/SlotInstruction.java @@ -23,36 +23,14 @@ package jode.bytecode; * This class represents an instruction in the byte code. * */ -public class SlotInstruction extends Instruction { +class SlotInstruction extends Instruction { 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) { - this(opcode, lvi, -1); - } - - /** - */ - public SlotInstruction(int opcode, int slot) { - this(opcode, LocalVariableInfo.getInfo(slot), -1); + super(opcode); + this.lvi = lvi; } public boolean isStore() { diff --git a/jode/jode/bytecode/SwitchInstruction.java b/jode/jode/bytecode/SwitchInstruction.java index b37440f..8e22e0a 100644 --- a/jode/jode/bytecode/SwitchInstruction.java +++ b/jode/jode/bytecode/SwitchInstruction.java @@ -24,7 +24,7 @@ import jode.util.StringQuoter; * This class represents an instruction in the byte code. * */ -public class SwitchInstruction extends Instruction { +class SwitchInstruction extends Instruction { /** * The values for this switch. */ @@ -34,20 +34,11 @@ public class SwitchInstruction extends Instruction { * Standard constructor: creates an opcode with parameter and * lineNr. */ - public SwitchInstruction(int opcode, int[] values, int lineNr) { - super(opcode, lineNr); - if (opcode != opc_lookupswitch) - throw new IllegalArgumentException("Instruction is no switch"); + SwitchInstruction(int opcode, int[] values) { + super(opcode); this.values = values; } - /** - * Creates a simple opcode, without any parameters. - */ - public SwitchInstruction(int opcode, int[] values) { - this(opcode, values, -1); - } - public final int[] getValues() { return values; diff --git a/jode/jode/bytecode/TypeDimensionInstruction.java b/jode/jode/bytecode/TypeDimensionInstruction.java index b077f3b..4281481 100644 --- a/jode/jode/bytecode/TypeDimensionInstruction.java +++ b/jode/jode/bytecode/TypeDimensionInstruction.java @@ -20,32 +20,18 @@ 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. */ 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) { - this(opcode, type, dimension, -1); + super(opcode, type); + this.dimension = dimension; } /** diff --git a/jode/jode/bytecode/TypeInstruction.java b/jode/jode/bytecode/TypeInstruction.java index abce932..37719e7 100644 --- a/jode/jode/bytecode/TypeInstruction.java +++ b/jode/jode/bytecode/TypeInstruction.java @@ -23,29 +23,15 @@ package jode.bytecode; * This class represents an instruction in the byte code. * */ -public class TypeInstruction extends Instruction { +class TypeInstruction extends Instruction { /** * The typesignature of the class/array. */ 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) { - this(opcode, typeSig, -1); + super(opcode); + this.typeSig = typeSig; } public final String getClazzType() diff --git a/jode/jode/bytecode/package.html b/jode/jode/bytecode/package.html index 1ae5b55..64409b9 100644 --- a/jode/jode/bytecode/package.html +++ b/jode/jode/bytecode/package.html @@ -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"); ClassInfo clazz = path.getClassInfo("my.new.Class"); - clazz.setModifiers(Modifiers.PUBLIC); + clazz.setModifiers(Modifier.PUBLIC); clazz.setSourceFile("Class.pl"); clazz.set... clazz.write(zipOutputStream);