From d5a0591d1f40a337b756ad113c50c07dab5798b1 Mon Sep 17 00:00:00 2001 From: hoenicke Date: Tue, 14 Aug 2001 14:25:29 +0000 Subject: [PATCH] Javadoc updates. Changed the broken obfuscator/modules classes so that at least javadoc runs cleanly. git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@1349 379699f6-c40d-0410-875b-85095c16579e --- jode/src/net/sf/jode/bytecode/ClassInfo.java | 269 +++++++++++------- .../modules/LocalizeFieldTransformer.java | 7 +- .../obfuscator/modules/RemovePopAnalyzer.java | 144 +--------- 3 files changed, 173 insertions(+), 247 deletions(-) diff --git a/jode/src/net/sf/jode/bytecode/ClassInfo.java b/jode/src/net/sf/jode/bytecode/ClassInfo.java index 7cd368e..6f9b296 100644 --- a/jode/src/net/sf/jode/bytecode/ClassInfo.java +++ b/jode/src/net/sf/jode/bytecode/ClassInfo.java @@ -47,27 +47,42 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -/** - * Accesses, creates or modifies java bytecode classes or interfaces. - * This class represents a class or interface, it can't be used for - * primitive or array types. Every class/interface is associated with - * a class path, which is used to load the class in memory. +/** + * Represents a class or interface. It can't be used for primitive + * or array types. Every class/interface is associated with a class + * path, which is used to load the class and its dependent classes. * - *

Creating a class

- * You create a new ClassInfo, by calling {@link - * ClassPath#getClassInfo}. The resulting ClassInfo is empty and you - * now have two different possibilities to fill it with informations: - * You load the class from its classpath (from which it was created) - * or you build it from scratch by setting its contents with the - * various setSomething methods. + *

ClassInfo and ClassPath

+ * + * Every ClassInfo instance belongs to a {@link ClassPath}. This + * class path is used to find the class and its dependent classes, + * e.g. the super class. Even if you want to create a class info from + * the scratch you have to associate it with a class path, in which + * the dependent classes are searched. + * + * For every class path and every class name there exists at most one + * class info object with this class name. The only exception is when + * you overwrite a loaded class, e.g. by calling setName(). * - *

Changing a class

- * Even if the class is already filled with information you can change - * it. You can, for example, set another array of methods, change the - * modifiers, or rename the class. Use the various - * setSomething methods. + *

Creating a Class

+ * As you can see, there is no public constructor. Instead you create + * a new ClassInfo, by calling {@link ClassPath#getClassInfo}. + * Multiple calls of this method with the same class name result in + * the same object. The resulting ClassInfo is initially empty and + * you now have three different means to fill it with informations: + * You can {@link #load load} the class from its classpath (from which + * it was created), you can {@link #guess guess} the information + * (useful if the class can't be loaded), or you build it from scratch + * by setting its contents with the various setSomething + * methods. + * + *

Changing a Class

+ * Whether or not the classinfo was already filled with information, + * you can change it. You can, for example, provide another array of + * methods, change the modifiers, or rename the class. Use the + * various setSomething methods. * - *

The components of a class

+ *

The Components of a Class

* A class consists of several components: *
*
name
@@ -94,21 +109,20 @@ import java.lang.reflect.Modifier; *
modifiers
* There is a set of access modifiers (AKA access flags) attached to * each class. They are represented as integers (bitboard) and can - * be conveniently accessed via - * java.lang.reflect.Modifier.

+ * be conveniently accessed via {@link java.lang.reflect.Modifier}. + *
* - * Inner classes can have more modifiers than normal classes. To be - * backwards compatible this was implemented by Sun by having the real - * modifiers for inner classes at a special location, while the old - * location has only the modifiers that were allowed previously. - * This package knows about this and always returns the real modifiers. - * The old modifiers are checked if they match the new extended ones.
- * TODO: Check that reflection returns the new modifiers! + * Inner classes can have more modifiers than normal classes, as + * they can be private, protected or static. These extended modifiers + * are supported, too.
+ * + * TODO: Check that reflection returns the extended modifiers! *
*
superclass
- * Every class except java.lang.Object has a super class. The super class - * is created in the same classpath as the current class. Interfaces - * always have java.lang.Object as their super class. + * Every class except java.lang.Object has a super + * class. The super class is created in the same classpath as the + * current class. Interfaces always have + * java.lang.Object as their super class. *
*
interfaces
* Every class (resp. interfaces) can implement (resp. extend) @@ -118,61 +132,62 @@ import java.lang.reflect.Modifier; * Fields are represented as {@link FieldInfo} objects. *
*
methods
- * Fields are represented as {@link MethodInfo} objects. + * Methods are represented as {@link MethodInfo} objects. *
*
method scoped
* A boolean value; true if this class is an anonymous or method * scoped class. *
*
outer class
- * the class of which this class is the inner class. It returns - * null for package scoped and method scoped classes.
+ * the class in which this class or interface was declared. It + * returns null for package scoped and method scoped classes. *
*
classes
- * the inner classes which is an array of ClassInfo. This doesn't - * include method scoped classes.
+ * the inner classes declared in this class. This doesn't include + * method scoped classes. *
*
source file
* The name of source file. The JVM uses this field when a stack - * trace is produced. + * trace is produced. It may be null if the class was compiled + * without debugging information. *
*
* - *

inner classes

+ *

Inner Classes

* Inner classes are supported as far as the information is present in - * the bytecode. But you can always ignore this inner information, - * and access inner classes by their bytecode name, - * e.g. java.util.Map$Entry. There are four different types - * of classes: + * the bytecode. However, you can always ignore this inner + * information, and access inner classes by their bytecode name, + * e.g. java.util.Map$Entry. There are four different + * types of classes: *
*
normal package scoped classes
* A class is package scoped if, and only if - * getOuterClass() returns null and - * isMethodScoped() returns false. + * {@link #getOuterClass()} returns null and + * {@link #isMethodScoped()} returns false. *
*
class scoped classes (inner classes)
* A class is class scoped if, and only if - * getOuterClass() returns not null. + * {@link #getOuterClass()} returns not null. * - * The bytecode name (getName()) of an inner class is - * in most cases of the form Package.Outer$Inner. But + * The bytecode name ({@link #getName()}) of an inner class is + * in normally of the form Package.Outer$Inner. However, * ClassInfo also supports differently named classes, as long as the * InnerClass attribute is present. The method - * getClassName() returns the name of the inner class + * {@link #getClassName()} returns the name of the inner class * (Inner in the above example). * * You can get all inner classes of a class with the - * getClasses method. + * method {@link #getClasses}. *
*
named method scoped classes
* A class is a named method scoped class if, and only if - * isMethodScoped() returns true and - * getClassName() returns not null. In - * that case getOuterClass() returns null, + * {@link #isMethodScoped()} returns true and + * {@link #getClassName()} returns not null. In + * that case {@link #getOuterClass()} returns null, * too.

* - * The bytecode name (getName()) of an method scoped class is - * in most cases of the form Package.Outer$Number$Inner. But + * The bytecode name ({@link #getName()}) of a method scoped class is + * normally of the form Package.Outer$Number$Inner. However, * ClassInfo also supports differently named classes, as long as the * InnerClass attribute is present.

* @@ -182,16 +197,15 @@ import java.lang.reflect.Modifier; *
*
anonymous classes
* A class is an anonymous class if, and only if - * isMethodScoped() returns true and - * getClassName() returns null. In that - * case getOuterClass() returns null, + * {@link #isMethodScoped()} returns true and + * {@link #getClassName()} returns null. In that + * case {@link #getOuterClass()} returns null, * too.

* - * The bytecode name (getName()) of an method scoped - * class is in most cases of the form - * Package.Outer$Number. But ClassInfo also supports - * differently named classes, as long as the InnerClass attribute is - * present.

+ * The bytecode name ({@link #getName()}) of a method scoped class + * is normally of the form Package.Outer$Number. + * However, ClassInfo also supports differently named classes, as + * long as the InnerClass attribute is present.

* * There's no way to get the anonymous classes of a method, except * by analyzing its instructions. And even that is error prone, since @@ -200,22 +214,21 @@ import java.lang.reflect.Modifier; *
* *
- *

Open Questions

+ *

Open Question

* - * I represent most types as java/lang/String (type + * I represent most types as {@link String} objects (type * signatures); this is convenient since java bytecode does the same. * On the other hand a class type should be represented as - * jode/bytecode/ClassInfo class. There should be a - * method to convert to it, but I need a ClassPath for this. Should - * the method be in ClassInfo (I don't think so), should an instance - * of TypeSignature have a ClassPath as member variable, or should - * getClassInfo() take a ClassPath parameter as it is currently? - * What about arrays, shall we support special ClassInfo's for them, - * as java.lang.Class does? I think the current solution is okay. - *
+ * {@link ClassInfo} object. There is a method in {@link TypeSignature} + * to convert between them, which needs a class path. This is a + * bit difficult to use.
* - * @author Jochen Hoenicke - */ + * However the alternative would be to represents types as ClassInfo + * and create ClassInfo objects for primitive and array types. But + * this contradicts the purpose of this class, which is to read and + * write class files. I think the current solution is okay.
+ * + * @author Jochen Hoenicke */ public final class ClassInfo extends BinaryInfo implements Comparable { private static ClassPath defaultClasspath; @@ -250,16 +263,15 @@ public final class ClassInfo extends BinaryInfo implements Comparable { public static final int NONE = 0; /** * This constant can be used as parameter to load. It specifies - * that at least the outer class information should be loaded, i.e. - * the outer class, the class name. It is the - * only information that is loaded recursively: It is also - * automatically loaded for the outer class and it is loaded for - * all inner and extra classes, if these fields are loaded. - * The reason for the recursive load is simple: In java bytecode - * a class contains the outer class information for all outer, - * inner and extra classes, so we can create this information + * that at least the outer class information should be loaded, + * i.e. the outer class and the java class name. It is the only + * information that is loaded recursively: It is also + * automatically loaded for all classes that are accessed by this + * class. The reason for the recursive load is simple: In java + * bytecode a class contains the outer class information for all + * classes that it accesses, so we can create this information * without the need to read the outer class. We also need this - * information for outer and inner classes when writing a class. + * information when writing a class. * * @see #load */ @@ -355,6 +367,14 @@ public final class ClassInfo extends BinaryInfo implements Comparable { return defaultClasspath.getClassInfo(name); } + /** + * Disable the default constructor. + * @exception InternalError always. + */ + private ClassInfo() throws InternalError { + throw new InternalError(); + } + ClassInfo(String name, ClassPath classpath) { /* Name may be null when reading class with unknown name from * stream. @@ -936,22 +956,21 @@ public final class ClassInfo extends BinaryInfo implements Comparable { } /** - * Loads the contents of a class from the classpath. - * @param howMuch The amount of information that should be read - * in, one of HIERARCHY, - * PUBLICDECLARATIONS, - * DECLARATIONS, ALMOSTALL - * or ALL. + * Loads the contents of a class from its class path. + * @param howMuch The amount of information that should be loaded + * at least, one of {@link #OUTERCLASS}, {@link #HIERARCHY}, {@link + * #PUBLICDECLARATIONS}, {@link #DECLARATIONS}, {@link #NODEBUG}, + * {@link #ALMOSTALL} or {@link #ALL}. Note that more information + * than requested can be loaded if this is convenient. * @exception ClassFormatException if the file doesn't denote a * valid class. * @exception FileNotFoundException if class wasn't found in classpath. - * @exception IOException if an io exception occured. - * @exception IllegalStateException if this ClassInfo was modified. - * @see #HIERARCHY - * @see #PUBLICDECLARATIONS - * @see #DECLARATIONS - * @see #ALMOSTALL - * @see #ALL + * @exception IOException if an io exception occured while reading + * the class. + * @exception SecurityException if a security manager prohibits loading + * the class. + * @exception IllegalStateException if this ClassInfo was modified by + * calling one of the setSomething methods. */ public void load(int howMuch) throws IOException @@ -975,8 +994,8 @@ public final class ClassInfo extends BinaryInfo implements Comparable { * extends java.lang.Object, implements no interfaces and has no * fields, methods or inner classes. * - * @param howMuch The amount of information that should be read, e.g. - * HIERARCHY. + * @param howMuch The amount of information that should be read, + * e.g. {@link #HIERARCHY}. * @see #OUTERCLASS * @see #HIERARCHY * @see #PUBLICDECLARATIONS @@ -1035,9 +1054,11 @@ public final class ClassInfo extends BinaryInfo implements Comparable { /** * This is the counter part to load and guess. It will drop all - * informations bigger than "keep" and clean up the memory. + * informations bigger than "keep" and clean up the memory. Note + * that drop should be used with care if more than one thread + * accesses this ClassInfo. * @param keep tells how much info we should keep, can be - * NONE or anything that load accepts. + * {@link #NONE} or anything that load accepts. * @see #load */ public void drop(int keep) { @@ -1091,6 +1112,11 @@ public final class ClassInfo extends BinaryInfo implements Comparable { return name; } + /** + * Tells whether the information in this class was guessed by a call + * to {@link #guess}. + * @return true if the information was guessed. + */ public boolean isGuessed() { return isGuessed; } @@ -1142,16 +1168,37 @@ public final class ClassInfo extends BinaryInfo implements Comparable { return interfaces; } + /** + * Gets the modifiers of this class, e.g. public or abstract. The + * information is only available if at least {@link #HIERARCHY} is + * loaded. + * @return a bitboard of the modifiers. + * @see Class#getModifiers + * @see Modifier + */ public int getModifiers() { if (modifiers == -1) throw new IllegalStateException("status is "+status); return modifiers; } + /** + * Checks whether this class info represents an interface. The + * information is only available if at least {@link #HIERARCHY} is + * loaded. + * @return true if this class info represents an interface. + */ public boolean isInterface() { return Modifier.isInterface(getModifiers()); } + /** + * Searches for a field with given name and type signature. + * @param name the name of the field. + * @param typeSig the {@link TypeSignature type signature} of the + * field. + * @return the field info for the field. + */ public FieldInfo findField(String name, String typeSig) { if (status < PUBLICDECLARATIONS) throw new IllegalStateException("status is "+status); @@ -1162,6 +1209,13 @@ public final class ClassInfo extends BinaryInfo implements Comparable { return null; } + /** + * Searches for a method with given name and type signature. + * @param name the name of the method. + * @param typeSig the {@link TypeSignature type signature} of the + * method. + * @return the method info for the method. + */ public MethodInfo findMethod(String name, String typeSig) { if (status < PUBLICDECLARATIONS) throw new IllegalStateException("status is "+status); @@ -1172,12 +1226,18 @@ public final class ClassInfo extends BinaryInfo implements Comparable { return null; } + /** + * Gets the methods of this class. + */ public MethodInfo[] getMethods() { if (status < PUBLICDECLARATIONS) throw new IllegalStateException("status is "+status); return methods; } + /** + * Gets the fields (class and member variables) of this class. + */ public FieldInfo[] getFields() { if (status < PUBLICDECLARATIONS) throw new IllegalStateException("status is "+status); @@ -1200,7 +1260,7 @@ public final class ClassInfo extends BinaryInfo implements Comparable { } /** - * Returns true if the class was declared inside a method. + * Tells whether the class was declared inside a method. * This needs the OUTERCLASS information loaded. * @return true if this is a method scoped or an anonymous class, * false otherwise. @@ -1215,11 +1275,12 @@ public final class ClassInfo extends BinaryInfo implements Comparable { } /** - * Returns the inner classes declared in this class. + * Gets the inner classes declared in this class. * This needs at least PUBLICDECLARATION information loaded. * @return an array containing the inner classes, guaranteed != null. * @exception IllegalStateException if PUBLICDECLARATIONS information - * wasn't loaded yet. */ + * wasn't loaded yet. + */ public ClassInfo[] getClasses() { if (status < PUBLICDECLARATIONS) throw new IllegalStateException("status is "+status); @@ -1457,6 +1518,10 @@ public final class ClassInfo extends BinaryInfo implements Comparable { return clazz == this; } + /** + * Returns a string representation of the class. This is just the + * full qualified class name. + */ public String toString() { return name; } diff --git a/jode/src/net/sf/jode/obfuscator/modules/LocalizeFieldTransformer.java b/jode/src/net/sf/jode/obfuscator/modules/LocalizeFieldTransformer.java index a3223e6..3686b1a 100644 --- a/jode/src/net/sf/jode/obfuscator/modules/LocalizeFieldTransformer.java +++ b/jode/src/net/sf/jode/obfuscator/modules/LocalizeFieldTransformer.java @@ -26,10 +26,7 @@ import net.sf.jode.obfuscator.*; */ public class LocalizeFieldTransformer implements CodeTransformer { - public static void transformCode(BytecodeInfo bytecode) { - for (Instruction instr = bytecode.getFirstInstr(); - instr != null; instr = instr.nextByAddr) { - - } + public void transformCode(BasicBlocks bb) { + /* XXX implement */ } } diff --git a/jode/src/net/sf/jode/obfuscator/modules/RemovePopAnalyzer.java b/jode/src/net/sf/jode/obfuscator/modules/RemovePopAnalyzer.java index 364ac2b..8152c8e 100644 --- a/jode/src/net/sf/jode/obfuscator/modules/RemovePopAnalyzer.java +++ b/jode/src/net/sf/jode/obfuscator/modules/RemovePopAnalyzer.java @@ -186,13 +186,13 @@ public class RemovePopAnalyzer implements CodeTransformer, Opcodes { (Instruction.forOpcode(opc_pop)); //DCABD< newInstructions.addFirst (Instruction.forOpcode(opc_dup2_x2)); //DCABDC< - swappedBeforeDup = !swappedBeforeDup //ABDC< + swappedBeforeDup = !swappedBeforeDup; //ABDC< } if (swapBeforeDup) newInstructions.addFirst (Instruction.forOpcode(opc_swap)); - return newPopped + return newPopped; } /** @@ -369,7 +369,7 @@ public class RemovePopAnalyzer implements CodeTransformer, Opcodes { blocks[i].setCode((Instruction[]) newInstructions .toArray(new Instruction[newInstructions.size()]), blocks[i].getSuccs()); - return poppedEntries + return poppedEntries; } /** @@ -399,143 +399,7 @@ public class RemovePopAnalyzer implements CodeTransformer, Opcodes { Instruction instr = oldInstrs[--instrNr]; instr.getStackPopPush(poppush); - for (stackDepth - - /* Check if this instr pushes a popped Entry. */ - boolean pops_a_popped = false; - boolean pops_all_popped = true; - for (int j=0; j < poppush[1]; j++) { - if (poppedEntries.get(j)) - push_a_popped = true; - else - push_all_popped = false; - } - - if (!push_a_popped) { - // Normal case: - // add the instruction and adjust stack depth. - newInstructions.addFirst(instr); - stackDepth += poppush[0] - poppush[1]; - continue; - } - - /* We push an entry, that gets popped later */ - int opcode = instr.getOpcode(); - switch (opcode) { - case opc_dup: - case opc_dup_x1: - case opc_dup_x2: - case opc_dup2: - case opc_dup2_x1: - case opc_dup2_x2: { - int popped = 0; - for (int j = poppush[1] ; j > 0; j--) { - popped <<= 1; - if (poppedEntries.get(--stackDepth)) { - popped |= 1; - poppedEntries.clear(stackDepth); - } - } - popped = movePopsThroughDup(opcode, newInstructions, - popped); - for (int j=0; j < poppush[1]; j++) { - if ((popped & 1) != 0) - poppedEntries.set(stackDepth); - stackDepth++; - popped >>=1; - } - break; - } - - case opc_swap: - if (!push_all_popped) { - // swap the popped status - if (poppedEntries.get(stackDepth - 1)) { - poppedEntries.clear(stackDepth - 1); - poppedEntries.set(stackDepth - 2); - } else { - poppedEntries.set(stackDepth - 1); - poppedEntries.clear(stackDepth - 2); - } - } - - case opc_ldc2_w: - case opc_lload: case opc_dload: - case opc_i2l: case opc_i2d: - case opc_f2l: case opc_f2d: - case opc_ldc: - case opc_iload: case opc_fload: case opc_aload: - case opc_new: - case opc_lneg: case opc_dneg: - case opc_l2d: case opc_d2l: - case opc_laload: case opc_daload: - case opc_ineg: case opc_fneg: - case opc_i2f: case opc_f2i: - case opc_i2b: case opc_i2c: case opc_i2s: - case opc_newarray: case opc_anewarray: - case opc_arraylength: - case opc_instanceof: - case opc_lshl: case opc_lshr: case opc_lushr: - case opc_iaload: case opc_faload: case opc_aaload: - case opc_baload: case opc_caload: case opc_saload: - case opc_iadd: case opc_fadd: - case opc_isub: case opc_fsub: - case opc_imul: case opc_fmul: - case opc_idiv: case opc_fdiv: - case opc_irem: case opc_frem: - case opc_iand: case opc_ior : case opc_ixor: - case opc_ishl: case opc_ishr: case opc_iushr: - case opc_fcmpl: case opc_fcmpg: - case opc_l2i: case opc_l2f: - case opc_d2i: case opc_d2f: - case opc_ladd: case opc_dadd: - case opc_lsub: case opc_dsub: - case opc_lmul: case opc_dmul: - case opc_ldiv: case opc_ddiv: - case opc_lrem: case opc_drem: - case opc_land: case opc_lor : case opc_lxor: - case opc_lcmp: - case opc_dcmpl: case opc_dcmpg: - case opc_getstatic: - case opc_getfield: - case opc_multianewarray: - - /* The simple instructions, that can be removed. */ - if (!push_all_popped) - throw new InternalError("pop half of a long"); - if (poppush[0] < poppush[1]) { - for (int j=0; j < poppush[0] - poppush[1]; j++) - poppedEntries.set(stackDepth++); - } else if (poppush[0] < poppush[1]) { - for (int j=0; j < poppush[0] - poppush[1]; j++) - poppedEntries.clear(--stackDepth); - } - - case opc_invokevirtual: - case opc_invokespecial: - case opc_invokestatic: - case opc_invokeinterface: - case opc_checkcast: - - /* These instructions can't be removed, since - * they have side effects. - */ - if (!push_all_popped) - throw new InternalError("pop half of a long"); - if (poppush[1] == 1) { - poppedEntries.clear(--stackDepth); - newInstructions - .addFirst(Instruction.forOpcode(opc_pop)); - } else { - poppedEntries.clear(--stackDepth); - poppedEntries.clear(--stackDepth); - newInstructions - .addFirst(Instruction.forOpcode(opc_pop2)); - } - newInstructions.addFirst(instr); - default: - throw new InternalError("Unexpected opcode!"); - } + /* XXX handle pops inside a opc_dup */ } block.setCode((Instruction[]) newInstructions .toArray(new Instruction[newInstructions.size()]),