diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..d39b7ca1 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,17 @@ +# Set the default behavior, in case people don't have core.autocrlf set. +* text=auto + +# Declare OSX files that will always have LF line endings on checkout. +Info.plist text eol=lf + +# Declare script files that will always have LF line endings on checkout. +*.sh text eol=lf + +# Declare script files that will always have CR/LF line endings on checkout. +*.bat text eol=crlf + +# Denote all files that are truly binary and should not be modified. +*.png binary +*.jpg binary +*.gif binary +*.icns binary diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..8808e318 --- /dev/null +++ b/.gitignore @@ -0,0 +1,36 @@ +# Java +*.class + +# JD +debug* + +# Idea +.idea/ +out/ +*.ipr +*.iml +*.iws + +# Eclipse +.settings/ +classes/ +.classpath +.project + +# Mac +.DS_Store + +# Windows +Thumbs.db + +# Maven +log/ +target/ + +# Gradle +.gradle/ +build/ +!gradle/wrapper/* + +# WinMerge +*.bak diff --git a/src/jd/core/CoreConstants.java b/src/jd/core/CoreConstants.java new file mode 100644 index 00000000..4a5ae051 --- /dev/null +++ b/src/jd/core/CoreConstants.java @@ -0,0 +1,9 @@ +package jd.core; + +public class CoreConstants +{ + //public static final String JD_CORE_VERSION = "0.7.1-SNAPSHOT-20140817"; + public static final String JD_CORE_VERSION = "0.7.1"; + + public static final int JAVA_MAGIC_NUMBER = 0xCafeBabe; +} diff --git a/src/jd/core/Decompiler.java b/src/jd/core/Decompiler.java new file mode 100644 index 00000000..c9a6579b --- /dev/null +++ b/src/jd/core/Decompiler.java @@ -0,0 +1,16 @@ +package jd.core; + +import jd.core.loader.Loader; +import jd.core.loader.LoaderException; +import jd.core.preferences.Preferences; +import jd.core.printer.Printer; + + + +public interface Decompiler +{ + public void decompile( + Preferences preferences, Loader loader, + Printer printer, String internalClassPath) + throws LoaderException; +} diff --git a/src/jd/core/loader/Loader.java b/src/jd/core/loader/Loader.java new file mode 100644 index 00000000..3dde6786 --- /dev/null +++ b/src/jd/core/loader/Loader.java @@ -0,0 +1,12 @@ +package jd.core.loader; + +import java.io.DataInputStream; + + + +public interface Loader +{ + public DataInputStream load(String internalPath) throws LoaderException; + + public boolean canLoad(String internalPath); +} diff --git a/src/jd/core/loader/LoaderException.java b/src/jd/core/loader/LoaderException.java new file mode 100644 index 00000000..8f6abec5 --- /dev/null +++ b/src/jd/core/loader/LoaderException.java @@ -0,0 +1,14 @@ +package jd.core.loader; + + +public class LoaderException extends Exception +{ + private static final long serialVersionUID = 9506606333927794L; + + public LoaderException() {} + + public LoaderException(String msg) + { + super(msg); + } +} diff --git a/src/jd/core/model/classfile/Base.java b/src/jd/core/model/classfile/Base.java new file mode 100644 index 00000000..5677718f --- /dev/null +++ b/src/jd/core/model/classfile/Base.java @@ -0,0 +1,84 @@ +package jd.core.model.classfile; + +import jd.core.model.classfile.attribute.Annotation; +import jd.core.model.classfile.attribute.Attribute; +import jd.core.model.classfile.attribute.AttributeConstants; +import jd.core.model.classfile.attribute.AttributeRuntimeAnnotations; +import jd.core.model.classfile.attribute.AttributeSignature; + + +public class Base +{ + public int access_flags; + final public Attribute[] attributes; + + public Base(int access_flags, Attribute[] attributes) + { + this.access_flags = access_flags; + this.attributes = attributes; + } + + public AttributeSignature getAttributeSignature() + { + if (this.attributes != null) + { + for (int i=this.attributes.length-1; i>=0; --i) + if (this.attributes[i].tag == AttributeConstants.ATTR_SIGNATURE) + return (AttributeSignature)this.attributes[i]; + } + + return null; + } + + public boolean containsAttributeDeprecated() + { + if (this.attributes != null) + { + for (int i=this.attributes.length-1; i>=0; --i) + if (this.attributes[i].tag == AttributeConstants.ATTR_DEPRECATED) + return true; + } + + return false; + } + + public boolean containsAnnotationDeprecated(ClassFile classFile) + { + if (this.attributes != null) + { + for (int i=this.attributes.length-1; i>=0; --i) + { + switch (this.attributes[i].tag) + { + case AttributeConstants.ATTR_RUNTIME_INVISIBLE_ANNOTATIONS: + case AttributeConstants.ATTR_RUNTIME_VISIBLE_ANNOTATIONS: + { + Annotation[]annotations = + ((AttributeRuntimeAnnotations)attributes[i]).annotations; + if (containsAnnotationDeprecated(classFile, annotations)) + return true; + } + break; + } + } + } + + return false; + } + + private boolean containsAnnotationDeprecated( + ClassFile classFile, Annotation[] annotations) + { + if (annotations != null) + { + int idsIndex = + classFile.getConstantPool().internalDeprecatedSignatureIndex; + + for (int i=annotations.length-1; i>=0; --i) + if (idsIndex == annotations[i].type_index) + return true; + } + + return false; + } +} diff --git a/src/jd/core/model/classfile/ClassFile.java b/src/jd/core/model/classfile/ClassFile.java new file mode 100644 index 00000000..4a431f36 --- /dev/null +++ b/src/jd/core/model/classfile/ClassFile.java @@ -0,0 +1,426 @@ +package jd.core.model.classfile; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import jd.core.model.classfile.accessor.Accessor; +import jd.core.model.classfile.attribute.Attribute; +import jd.core.model.classfile.attribute.AttributeConstants; +import jd.core.model.classfile.attribute.AttributeInnerClasses; +import jd.core.model.classfile.constant.ConstantClass; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.util.SignatureUtil; +import jd.core.util.StringConstants; + + + +public class ClassFile extends Base +{ + private int minor_version; + private int major_version; + private int this_class; + private int super_class; + + private int interfaces[]; + private Field fields[]; + private Method methods[]; + + private ConstantPool constants; + private String thisClassName; + private String superClassName; + private String internalClassName; + private String internalPackageName; + + private ClassFile outerClass = null; + private Field outerThisField = null; + private ArrayList innerClassFiles = null; + + private Method staticMethod = null; + private List enumValues = null; + private String internalAnonymousClassName; + private Map> accessors; + + // Attention : + // - Dans le cas des instructions Switch+Enum d'Eclipse, la cl� de la map + // est l'indexe du nom de la m�thode + // "static int[] $SWITCH_TABLE$basic$data$TestEnum$enum1()". + // - Dans le cas des instructions Switch+Enum des autres compilateurs, la + // cl� de la map est l'indexe du nom de la classe interne "static class 1" + // contenant le tableau de correspondance + // "$SwitchMap$basic$data$TestEnum$enum1". + private Map> switchMaps; + + public ClassFile(int minor_version, int major_version, + ConstantPool constants, int access_flags, int this_class, + int super_class, int[] interfaces, Field[] fields, + Method[] methods, Attribute[] attributes) + { + super(access_flags, attributes); + + this.minor_version = minor_version; + this.major_version = major_version; + this.this_class = this_class; + this.super_class = super_class; + this.interfaces = interfaces; + this.fields = fields; + this.methods = methods; + + this.constants = constants; + + // internalClassName + this.thisClassName = + this.constants.getConstantClassName(this.this_class); + // internalSuperClassName + this.superClassName = (this.super_class == 0) ? null : + this.constants.getConstantClassName(this.super_class); + // + this.internalClassName = SignatureUtil.CreateTypeName(this.thisClassName); + // internalPackageName + int index = this.thisClassName.lastIndexOf( + StringConstants.INTERNAL_PACKAGE_SEPARATOR); + this.internalPackageName = + (index == -1) ? "" : this.thisClassName.substring(0, index); + + // staticMethod + if (this.methods != null) + { + for (int i=this.methods.length-1; i>=0; --i) + { + Method method = this.methods[i]; + + if (((method.access_flags & ClassFileConstants.ACC_STATIC) != 0) && + (method.name_index == this.constants.classConstructorIndex)) + { + this.staticMethod = method; + break; + } + } + } + + // internalAnonymousClassName + this.internalAnonymousClassName = null; + // accessors + this.accessors = new HashMap>(10); + // SwitchMap for Switch+Enum instructions + this.switchMaps = new HashMap>(); + } + + public ConstantPool getConstantPool() + { + return this.constants; + } + + public int[] getInterfaces() + { + return interfaces; + } + + public int getMajorVersion() + { + return major_version; + } + + public int getMinorVersion() + { + return minor_version; + } + + public int getSuperClassIndex() + { + return super_class; + } + + public int getThisClassIndex() + { + return this_class; + } + + public String getClassName() + { + if (this.outerClass == null) + { + // int index = this.thisClassName.lastIndexOf( + // AnalyzerConstants.INTERNAL_INNER_SEPARATOR); + //if (index != -1) + // return this.thisClassName.substring(index+1); + + int index = this.thisClassName.lastIndexOf( + StringConstants.INTERNAL_PACKAGE_SEPARATOR); + return (index == -1) ? + this.thisClassName : + this.thisClassName.substring(index + 1); + } + else + { + String outerClassName = this.outerClass.getThisClassName(); + + return this.thisClassName.substring( + outerClassName.length() + 1); + } + } + + public String getThisClassName() + { + return this.thisClassName; + } + + public String getSuperClassName() + { + return this.superClassName; + } + + public String getInternalClassName() + { + return this.internalClassName; + } + + public String getInternalPackageName() + { + return this.internalPackageName; + } + + public void setAccessFlags(int access_flags) + { + this.access_flags = access_flags; + } + + public Field[] getFields() + { + return this.fields; + } + + public Method[] getMethods() + { + return this.methods; + } + + public Attribute[] getAttributes() + { + return this.attributes; + } + + public AttributeInnerClasses getAttributeInnerClasses() + { + if (this.attributes != null) + { + for (int i=0; i= this.thisClassName.length())) + return false; + + return Character.isDigit(this.thisClassName.charAt(index+1)); + } + + public boolean isAInnerClass() + { + return this.outerClass != null; + } + public ClassFile getOuterClass() + { + return outerClass; + } + public void setOuterClass(ClassFile outerClass) + { + this.outerClass = outerClass; + + // internalAnonymousClassName + if (isAnonymousClass()) + { + ConstantClass cc = this.constants.getConstantClass(this.super_class); + + if (cc.name_index != this.constants.objectClassNameIndex) + { + // Super class + this.internalAnonymousClassName = this.superClassName; + } + else if ((this.interfaces != null) && (this.interfaces.length > 0)) + { + // Interface + int interfaceIndex = this.interfaces[0]; + this.internalAnonymousClassName = + this.constants.getConstantClassName(interfaceIndex); + } + else + { + this.internalAnonymousClassName = + StringConstants.INTERNAL_OBJECT_CLASS_NAME; + } + } + else + { + this.internalAnonymousClassName = null; + } + } + + public Field getOuterThisField() + { + return outerThisField; + } + public void setOuterThisField(Field outerThisField) + { + this.outerThisField = outerThisField; + } + + public ArrayList getInnerClassFiles() + { + return innerClassFiles; + } + public void setInnerClassFiles(ArrayList innerClassFiles) + { + this.innerClassFiles = innerClassFiles; + } + public ClassFile getInnerClassFile(String internalClassName) + { + if ((this.innerClassFiles != null) && + (internalClassName.length() > this.thisClassName.length()+1) && + (internalClassName.charAt(this.thisClassName.length()) == StringConstants.INTERNAL_INNER_SEPARATOR)) + { + for (int i=this.innerClassFiles.size()-1; i>=0; --i) + if (innerClassFiles.get(i).thisClassName.equals(internalClassName)) + return innerClassFiles.get(i); + } + + return null; + } + + public Field getField(int fieldNameIndex, int fieldDescriptorIndex) + { + if (this.fields != null) + { + for (int i=this.fields.length-1; i>=0; --i) + { + Field field = this.fields[i]; + + if ((fieldNameIndex == field.name_index) && + (fieldDescriptorIndex == field.descriptor_index)) + { + return field; + } + } + } + + return null; + } + public Field getField(String fieldName, String fieldDescriptor) + { + if (this.fields != null) + { + for (int i=this.fields.length-1; i>=0; --i) + { + Field field = this.fields[i]; + + String name = + this.constants.getConstantUtf8(field.name_index); + + if (fieldName.equals(name)) + { + String descriptor = + this.constants.getConstantUtf8(field.descriptor_index); + + if (fieldDescriptor.equals(descriptor)) + return field; + } + } + } + + return null; + } + + public Method getStaticMethod() + { + return staticMethod; + } + public Method getMethod(int methodNameIndex, int methodDescriptorIndex) + { + if (this.methods != null) + { + for (int i=this.methods.length-1; i>=0; --i) + { + Method method = this.methods[i]; + + if ((methodNameIndex == method.name_index) && + (methodDescriptorIndex == method.descriptor_index)) + { + return method; + } + } + } + + return null; + } + public Method getMethod(String methodName, String methodDescriptor) + { + if (this.methods != null) + { + for (int i=this.methods.length-1; i>=0; --i) + { + Method method = this.methods[i]; + + String name = + this.constants.getConstantUtf8(method.name_index); + + if (methodName.equals(name)) + { + String descriptor = + this.constants.getConstantUtf8(method.descriptor_index); + + if (methodDescriptor.equals(descriptor)) + return method; + } + } + } + + return null; + } + + public List getEnumValues() + { + return enumValues; + } + public void setEnumValues(List enumValues) + { + this.enumValues = enumValues; + } + + public String getInternalAnonymousClassName() + { + return internalAnonymousClassName; + } + + public void addAccessor(String name, String descriptor, Accessor accessor) + { + Map map = this.accessors.get(name); + + if (map == null) + { + map = new HashMap(1); + this.accessors.put(name, map); + } + + map.put(descriptor, accessor); + } + + public Accessor getAccessor(String name, String descriptor) + { + Map map = this.accessors.get(name); + return (map == null) ? null : map.get(descriptor); + } + + public Map> getSwitchMaps() + { + return this.switchMaps; + } +} diff --git a/src/jd/core/model/classfile/ClassFileConstants.java b/src/jd/core/model/classfile/ClassFileConstants.java new file mode 100644 index 00000000..ccecc5bc --- /dev/null +++ b/src/jd/core/model/classfile/ClassFileConstants.java @@ -0,0 +1,25 @@ +package jd.core.model.classfile; + + +public class ClassFileConstants +{ + // Access flag for Class, Field, Method, Nested class + public final static short ACC_PUBLIC = 0x0001; // C F M N + public final static short ACC_PRIVATE = 0x0002; // F M N + public final static short ACC_PROTECTED = 0x0004; // F M N + public final static short ACC_STATIC = 0x0008; // F M N + public final static short ACC_FINAL = 0x0010; // C F M N + public final static short ACC_SYNCHRONIZED = 0x0020; // M + public final static short ACC_SUPER = 0x0020; // C + public final static short ACC_VOLATILE = 0x0040; // F + public final static short ACC_BRIDGE = 0x0040; // M + public final static short ACC_TRANSIENT = 0x0080; // F + public final static short ACC_VARARGS = 0x0080; // M + public final static short ACC_NATIVE = 0x0100; // M + public final static short ACC_INTERFACE = 0x0200; // C N + public final static short ACC_ABSTRACT = 0x0400; // C M N + public final static short ACC_STRICT = 0x0800; // M + public final static short ACC_SYNTHETIC = 0x1000; // C F M N + public final static short ACC_ANNOTATION = 0x2000; // C N + public final static short ACC_ENUM = 0x4000; // C F N +} diff --git a/src/jd/core/model/classfile/ConstantPool.java b/src/jd/core/model/classfile/ConstantPool.java new file mode 100644 index 00000000..76cc3bf6 --- /dev/null +++ b/src/jd/core/model/classfile/ConstantPool.java @@ -0,0 +1,387 @@ +package jd.core.model.classfile; + +import java.util.ArrayList; +import java.util.List; + +import jd.core.model.classfile.constant.Constant; +import jd.core.model.classfile.constant.ConstantClass; +import jd.core.model.classfile.constant.ConstantConstant; +import jd.core.model.classfile.constant.ConstantFieldref; +import jd.core.model.classfile.constant.ConstantInteger; +import jd.core.model.classfile.constant.ConstantInterfaceMethodref; +import jd.core.model.classfile.constant.ConstantMethodref; +import jd.core.model.classfile.constant.ConstantNameAndType; +import jd.core.model.classfile.constant.ConstantUtf8; +import jd.core.model.classfile.constant.ConstantValue; +import jd.core.util.IndexToIndexMap; +import jd.core.util.InvalidParameterException; +import jd.core.util.StringConstants; +import jd.core.util.StringToIndexMap; + + +public class ConstantPool +{ + private ArrayList listOfConstants; + private StringToIndexMap constantUtf8ToIndex; + private IndexToIndexMap constantClassToIndex; + + public final int instanceConstructorIndex; + public final int classConstructorIndex; + public final int internalDeprecatedSignatureIndex; + public final int toStringIndex; + public final int valueOfIndex; + public final int appendIndex; + + public final int objectClassIndex; + + public final int objectClassNameIndex; + public final int stringClassNameIndex; + public final int stringBufferClassNameIndex; + public final int stringBuilderClassNameIndex; + + public final int objectSignatureIndex; + + public final int thisLocalVariableNameIndex; + + public final int annotationDefaultAttributeNameIndex; + public final int codeAttributeNameIndex; + public final int constantValueAttributeNameIndex; + public final int deprecatedAttributeNameIndex; + public final int enclosingMethodAttributeNameIndex; + public final int exceptionsAttributeNameIndex; + public final int innerClassesAttributeNameIndex; + public final int lineNumberTableAttributeNameIndex; + public final int localVariableTableAttributeNameIndex; + public final int localVariableTypeTableAttributeNameIndex; + public final int runtimeInvisibleAnnotationsAttributeNameIndex; + public final int runtimeVisibleAnnotationsAttributeNameIndex; + public final int runtimeInvisibleParameterAnnotationsAttributeNameIndex; + public final int runtimeVisibleParameterAnnotationsAttributeNameIndex; + public final int signatureAttributeNameIndex; + public final int sourceFileAttributeNameIndex; + public final int syntheticAttributeNameIndex; + + + + public ConstantPool(Constant[] constants) + { + this.listOfConstants = new ArrayList(); + this.constantUtf8ToIndex = new StringToIndexMap(); + this.constantClassToIndex = new IndexToIndexMap(); + + for (int i=0; i 0) + { + Constant constant = this.listOfConstants.get(index); + + if ((constant == null) || + (constant.tag != ConstantConstant.CONSTANT_NameAndType)) + continue; + + ConstantNameAndType cnat = (ConstantNameAndType)constant; + + if ((cnat.name_index == name_index) && + (cnat.descriptor_index == descriptor_index)) + return index; + } + + ConstantNameAndType cnat = new ConstantNameAndType( + ConstantConstant.CONSTANT_NameAndType, name_index, descriptor_index); + index = this.listOfConstants.size(); + this.listOfConstants.add(cnat); + + return index; + } + + public int addConstantFieldref(int class_index, int name_and_type_index) + { + int index = this.listOfConstants.size(); + + while (--index > 0) + { + Constant constant = this.listOfConstants.get(index); + + if ((constant == null) || + (constant.tag != ConstantConstant.CONSTANT_Fieldref)) + continue; + + ConstantFieldref cfr = (ConstantFieldref)constant; + + if ((cfr.class_index == class_index) && + (cfr.name_and_type_index == name_and_type_index)) + return index; + } + + ConstantFieldref cfr = new ConstantFieldref( + ConstantConstant.CONSTANT_Fieldref, class_index, name_and_type_index); + index = this.listOfConstants.size(); + this.listOfConstants.add(cfr); + + return index; + } + + public int addConstantMethodref(int class_index, int name_and_type_index) + { + return addConstantMethodref( + class_index, name_and_type_index, null, null); + } + + public int addConstantMethodref( + int class_index, int name_and_type_index, + List listOfParameterSignatures, String returnedSignature) + { + int index = this.listOfConstants.size(); + + while (--index > 0) + { + Constant constant = this.listOfConstants.get(index); + + if ((constant == null) || + (constant.tag != ConstantConstant.CONSTANT_Methodref)) + continue; + + ConstantMethodref cmr = (ConstantMethodref)constant; + + if ((cmr.class_index == class_index) && + (cmr.name_and_type_index == name_and_type_index)) + return index; + } + + ConstantMethodref cfr = new ConstantMethodref( + ConstantConstant.CONSTANT_Methodref, class_index, name_and_type_index, + listOfParameterSignatures, returnedSignature); + index = this.listOfConstants.size(); + this.listOfConstants.add(cfr); + + return index; + } + + public String getConstantUtf8(int index) + { + ConstantUtf8 cutf8 = (ConstantUtf8)this.listOfConstants.get(index); + return cutf8.bytes; + } + + public String getConstantClassName(int index) + { + ConstantClass cc = (ConstantClass)this.listOfConstants.get(index); + ConstantUtf8 cutf8 = (ConstantUtf8)this.listOfConstants.get(cc.name_index); + return cutf8.bytes; + } + + public ConstantClass getConstantClass(int index) + { + return (ConstantClass)this.listOfConstants.get(index); + } + + public ConstantFieldref getConstantFieldref(int index) + { + return (ConstantFieldref)this.listOfConstants.get(index); + } + + public ConstantNameAndType getConstantNameAndType(int index) + { + return (ConstantNameAndType)this.listOfConstants.get(index); + } + + public ConstantMethodref getConstantMethodref(int index) + { + return (ConstantMethodref)this.listOfConstants.get(index); + } + + public ConstantInterfaceMethodref getConstantInterfaceMethodref(int index) + { + return (ConstantInterfaceMethodref)this.listOfConstants.get(index); + } + + public ConstantValue getConstantValue(int index) + { + return (ConstantValue)this.listOfConstants.get(index); + } + + public ConstantInteger getConstantInteger(int index) + { + return (ConstantInteger)this.listOfConstants.get(index); + } +} diff --git a/src/jd/core/model/classfile/Field.java b/src/jd/core/model/classfile/Field.java new file mode 100644 index 00000000..b59f7bd1 --- /dev/null +++ b/src/jd/core/model/classfile/Field.java @@ -0,0 +1,82 @@ +package jd.core.model.classfile; + +import jd.core.model.classfile.attribute.Attribute; +import jd.core.model.classfile.attribute.AttributeConstantValue; +import jd.core.model.classfile.attribute.AttributeConstants; +import jd.core.model.classfile.constant.ConstantValue; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.util.UtilConstants; + + +public class Field extends FieldOrMethod +{ + private ValueAndMethod valueAndMethod = null; + /* + * Attributs pour l'affichage des champs synthetique des classes anonymes. + * Champs modifi� par: + * 1) ClassFileAnalyzer.AnalyseAndModifyConstructors(...) pour y placer le + * numero (position) du parametre du constructeur initialisant le champs. + */ + public int anonymousClassConstructorParameterIndex; + /* + * 2) NewInstructionReconstructorBase.InitAnonymousClassConstructorParameterName(...) + * pour y placer l'index du nom du parametre. + * 3) SourceWriterVisitor.writeGetField(...) pour afficher le nom du + * parameter de la classe englobante. + */ + public int outerMethodLocalVariableNameIndex; + + public Field( + int access_flags, int name_index, + int descriptor_index, Attribute[] attributes) + { + super(access_flags, name_index, descriptor_index, attributes); + this.anonymousClassConstructorParameterIndex = UtilConstants.INVALID_INDEX; + this.outerMethodLocalVariableNameIndex = UtilConstants.INVALID_INDEX; + } + + public ConstantValue getConstantValue(ConstantPool constants) + { + if (this.attributes != null) + for(int i=0; i +{ + public int start_pc; + public int length; + public int name_index; + public int signature_index; + final public int index; + public boolean exceptionOrReturnAddress; + // Champ de bits utilis� pour determiner le type de la variable (byte, char, + // short, int). + public int typesBitField; + // Champs utilis� lors de la generation des declarations de variables + // locales (FastDeclarationAnalyzer.Analyze). + public boolean declarationFlag = false; + + public boolean finalFlag = false; + + public LocalVariable( + int start_pc, int length, int name_index, int signature_index, + int index) + { + this(start_pc, length, name_index, signature_index, index, false, 0); + } + + public LocalVariable( + int start_pc, int length, int name_index, int signature_index, + int index, int typesBitSet) + { + this(start_pc, length, name_index, signature_index, index, false, + typesBitSet); + } + + public LocalVariable( + int start_pc, int length, int name_index, int signature_index, + int index, boolean exception) + { + this(start_pc, length, name_index, signature_index, index, exception, 0); + } + + protected LocalVariable( + int start_pc, int length, int name_index, int signature_index, + int index, boolean exceptionOrReturnAddress, int typesBitField) + { + this.start_pc = start_pc; + this.length = length; + this.name_index = name_index; + this.signature_index = signature_index; + this.index = index; + this.exceptionOrReturnAddress = exceptionOrReturnAddress; + this.declarationFlag = exceptionOrReturnAddress; + this.typesBitField = typesBitField; + } + + public void updateRange(int offset) + { + if (offset < this.start_pc) + { + this.length += (this.start_pc - offset); + this.start_pc = offset; + } + + if (offset >= this.start_pc+this.length) + { + this.length = offset - this.start_pc + 1; + } + } + + public void updateSignatureIndex(int signatureIndex) + { + this.signature_index = signatureIndex; + } + + public String toString() + { + return + "LocalVariable{start_pc=" + start_pc + + ", length=" + length + + ", name_index=" + name_index + + ", signature_index=" + signature_index + + ", index=" + index + + "}"; + } + + public int compareTo(LocalVariable other) + { + if (other == null) + return -1; + + if (this.name_index != other.name_index) + return this.name_index - other.name_index; + + if (this.length != other.length) + return this.length - other.length; + + if (this.start_pc != other.start_pc) + return this.start_pc - other.start_pc; + + return this.index - other.index; + } +} diff --git a/src/jd/core/model/classfile/LocalVariables.java b/src/jd/core/model/classfile/LocalVariables.java new file mode 100644 index 00000000..52598596 --- /dev/null +++ b/src/jd/core/model/classfile/LocalVariables.java @@ -0,0 +1,178 @@ +package jd.core.model.classfile; + +import java.util.ArrayList; + +public class LocalVariables +{ + private ArrayList listOfLocalVariables; + + private int indexOfFirstLocalVariable = 0; + + public LocalVariables() + { + this.listOfLocalVariables = new ArrayList(1); + } + + public LocalVariables( + LocalVariable[] localVariableTable, + LocalVariable[] localVariableTypeTable) + { + int length = localVariableTable.length; + + this.listOfLocalVariables = new ArrayList(length); + + for (int i = 0; i < length; i++) + { + LocalVariable localVariable = localVariableTable[i]; + + // Search local variable in 'localVariableTypeTable' + if (localVariableTypeTable != null) + { + int typeLength = localVariableTypeTable.length; + + for (int j=0; j localVariable.start_pc)) || + (lv.index > index) + ) + { + this.listOfLocalVariables.add(i, localVariable); + return; + } + } + + this.listOfLocalVariables.add(localVariable); + } + + public LocalVariable get(int i) + { + return this.listOfLocalVariables.get(i); + } + + public void remove(int i) + { + this.listOfLocalVariables.remove(i); + } + + public String toString() + { + return this.listOfLocalVariables.toString(); + } + + public LocalVariable getLocalVariableAt(int i) + { + return (i >= this.listOfLocalVariables.size()) ? null + : this.listOfLocalVariables.get(i); + } + + public LocalVariable getLocalVariableWithIndexAndOffset(int index, + int offset) + { + int length = this.listOfLocalVariables.size(); + + for (int i = length - 1; i >= 0; --i) { + LocalVariable lv = this.listOfLocalVariables.get(i); + + if ((lv.index == index) && (lv.start_pc <= offset) + && (offset < lv.start_pc + lv.length)) + return lv; + } + + return null; + } + + public boolean containsLocalVariableWithNameIndex(int nameIndex) + { + int length = this.listOfLocalVariables.size(); + + for (int i = length - 1; i >= 0; --i) { + LocalVariable lv = this.listOfLocalVariables.get(i); + + if (lv.name_index == nameIndex) + return true; + } + + return false; + } + + public void removeLocalVariableWithIndexAndOffset(int index, int offset) + { + int length = this.listOfLocalVariables.size(); + + for (int i = length - 1; i >= 0; --i) { + LocalVariable lv = this.listOfLocalVariables.get(i); + + if ((lv.index == index) && (lv.start_pc <= offset) + && (offset < lv.start_pc + lv.length)) + { + this.listOfLocalVariables.remove(i); + break; + } + } + } + + public LocalVariable searchLocalVariableWithIndexAndOffset(int index, + int offset) + { + int length = this.listOfLocalVariables.size(); + + for (int i = length - 1; i >= 0; --i) + { + LocalVariable lv = this.listOfLocalVariables.get(i); + + if ((lv.index == index) && (lv.start_pc <= offset)) + return lv; + } + + return null; + } + + public int size() + { + return this.listOfLocalVariables.size(); + } + + public int getIndexOfFirstLocalVariable() + { + return indexOfFirstLocalVariable; + } + + public void setIndexOfFirstLocalVariable(int indexOfFirstLocalVariable) + { + this.indexOfFirstLocalVariable = indexOfFirstLocalVariable; + } + + public int getMaxLocalVariableIndex() + { + int length = this.listOfLocalVariables.size(); + + return (length == 0) ? + -1 : this.listOfLocalVariables.get(length-1).index; + } +} diff --git a/src/jd/core/model/classfile/Method.java b/src/jd/core/model/classfile/Method.java new file mode 100644 index 00000000..36b64ef3 --- /dev/null +++ b/src/jd/core/model/classfile/Method.java @@ -0,0 +1,195 @@ +package jd.core.model.classfile; + +import java.util.List; + +import jd.core.model.classfile.attribute.Attribute; +import jd.core.model.classfile.attribute.AttributeAnnotationDefault; +import jd.core.model.classfile.attribute.AttributeCode; +import jd.core.model.classfile.attribute.AttributeConstants; +import jd.core.model.classfile.attribute.AttributeExceptions; +import jd.core.model.classfile.attribute.AttributeLocalVariableTable; +import jd.core.model.classfile.attribute.AttributeNumberTable; +import jd.core.model.classfile.attribute.AttributeRuntimeParameterAnnotations; +import jd.core.model.classfile.attribute.CodeException; +import jd.core.model.classfile.attribute.ElementValue; +import jd.core.model.classfile.attribute.LineNumber; +import jd.core.model.classfile.attribute.ParameterAnnotations; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + + +public class Method extends FieldOrMethod +{ + private boolean containsError; + private int[] exceptionIndexes; + private byte[] code; + private LineNumber[] lineNumbers; + private CodeException[] codeExceptions; + private ParameterAnnotations[] visibleParameterAnnotations; + private ParameterAnnotations[] invisibleParameterAnnotations; + private ElementValue defaultAnnotationValue; + private List instructions; + private List fastNodes; + private LocalVariables localVariables; + /** + * Champs permettant l'affichage des parametres des instanciations des + * classes anonymes. + */ + private int superConstructorParameterCount; + + public Method(int access_flags, int name_index, int descriptor_index, + Attribute[] attributes) + { + super(access_flags, name_index, descriptor_index, attributes); + + this.containsError = false; + this.exceptionIndexes = null; + this.code = null; + this.localVariables = null; + this.lineNumbers = null; + this.codeExceptions = null; + this.visibleParameterAnnotations = null; + this.invisibleParameterAnnotations = null; + this.defaultAnnotationValue = null; + this.superConstructorParameterCount = 0; + + if (attributes != null) + { + AttributeCode ac = null; + + for (int i=this.attributes.length-1; i>=0; --i) + { + Attribute attribute = this.attributes[i]; + + switch (attribute.tag) + { + case AttributeConstants.ATTR_EXCEPTIONS: + this.exceptionIndexes = + ((AttributeExceptions)attribute).exception_index_table; + break; + case AttributeConstants.ATTR_CODE: + ac = ((AttributeCode)attributes[i]); + break; + case AttributeConstants.ATTR_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS: + this.visibleParameterAnnotations = + ((AttributeRuntimeParameterAnnotations)attribute).parameter_annotations; + break; + case AttributeConstants.ATTR_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS: + this.invisibleParameterAnnotations = + ((AttributeRuntimeParameterAnnotations)attribute).parameter_annotations; + break; + case AttributeConstants.ATTR_ANNOTATION_DEFAULT: + this.defaultAnnotationValue = + ((AttributeAnnotationDefault)attribute).default_value; + break; + } + } + + if (ac != null) + { + this.code = ac.code; + + // localVariables + AttributeLocalVariableTable alvt = ac.getAttributeLocalVariableTable(); + if ((alvt != null) && (alvt.local_variable_table != null)) + { + AttributeLocalVariableTable alvtt = ac.getAttributeLocalVariableTypeTable(); + LocalVariable[] localVariableTypeTable = + (alvtt == null) ? null : alvtt.local_variable_table; + this.localVariables = new LocalVariables( + alvt.local_variable_table, localVariableTypeTable); + } + + // lineNumbers + AttributeNumberTable ant = ac.getAttributeLineNumberTable(); + this.lineNumbers = (ant == null) ? null : ant.line_number_table; + + // codeExceptions + this.codeExceptions = ac.exception_table; + } + } + } + + public boolean containsError() + { + return containsError; + } + + public void setContainsError(boolean containsError) + { + this.containsError = containsError; + } + + public int[] getExceptionIndexes() + { + return this.exceptionIndexes; + } + + public LocalVariables getLocalVariables() + { + return this.localVariables; + } + + public void setLocalVariables(LocalVariables llv) + { + this.localVariables = llv; + } + + public List getInstructions() + { + return instructions; + } + public void setInstructions(List instructions) + { + this.instructions = instructions; + } + + public List getFastNodes() + { + return fastNodes; + } + public void setFastNodes(List fastNodes) + { + this.fastNodes = fastNodes; + } + + public byte[] getCode() + { + return this.code; + } + + public LineNumber[] getLineNumbers() + { + return lineNumbers; + } + + public CodeException[] getCodeExceptions() + { + return this.codeExceptions; + } + + public ParameterAnnotations[] getVisibleParameterAnnotations() + { + return this.visibleParameterAnnotations; + } + + public ParameterAnnotations[] getInvisibleParameterAnnotations() + { + return this.invisibleParameterAnnotations; + } + + public ElementValue getDefaultAnnotationValue() + { + return this.defaultAnnotationValue; + } + + public int getSuperConstructorParameterCount() + { + return superConstructorParameterCount; + } + + public void setSuperConstructorParameterCount(int count) + { + this.superConstructorParameterCount = count; + } +} diff --git a/src/jd/core/model/classfile/accessor/Accessor.java b/src/jd/core/model/classfile/accessor/Accessor.java new file mode 100644 index 00000000..0343179a --- /dev/null +++ b/src/jd/core/model/classfile/accessor/Accessor.java @@ -0,0 +1,11 @@ +package jd.core.model.classfile.accessor; + +public class Accessor +{ + final public byte tag; + + protected Accessor(byte tag) + { + this.tag = tag; + } +} diff --git a/src/jd/core/model/classfile/accessor/AccessorConstants.java b/src/jd/core/model/classfile/accessor/AccessorConstants.java new file mode 100644 index 00000000..addc9d53 --- /dev/null +++ b/src/jd/core/model/classfile/accessor/AccessorConstants.java @@ -0,0 +1,11 @@ +package jd.core.model.classfile.accessor; + + +public class AccessorConstants +{ + public static final byte ACCESSOR_GETSTATIC= 1; + public static final byte ACCESSOR_PUTSTATIC= 2; + public static final byte ACCESSOR_GETFIELD= 3; + public static final byte ACCESSOR_PUTFIELD= 4; + public static final byte ACCESSOR_INVOKEMETHOD= 5; +} diff --git a/src/jd/core/model/classfile/accessor/GetFieldAccessor.java b/src/jd/core/model/classfile/accessor/GetFieldAccessor.java new file mode 100644 index 00000000..3d3b183c --- /dev/null +++ b/src/jd/core/model/classfile/accessor/GetFieldAccessor.java @@ -0,0 +1,18 @@ +package jd.core.model.classfile.accessor; + + +public class GetFieldAccessor extends Accessor +{ + final public String className; + final public String fieldName; + final public String fieldDescriptor; + + public GetFieldAccessor( + byte tag, String className, String fieldName, String fieldDescriptor) + { + super(tag); + this.className = className; + this.fieldName = fieldName; + this.fieldDescriptor = fieldDescriptor; + } +} diff --git a/src/jd/core/model/classfile/accessor/GetStaticAccessor.java b/src/jd/core/model/classfile/accessor/GetStaticAccessor.java new file mode 100644 index 00000000..099f7111 --- /dev/null +++ b/src/jd/core/model/classfile/accessor/GetStaticAccessor.java @@ -0,0 +1,18 @@ +package jd.core.model.classfile.accessor; + + +public class GetStaticAccessor extends Accessor +{ + final public String className; + final public String fieldName; + final public String fieldDescriptor; + + public GetStaticAccessor( + byte tag, String className, String fieldName, String fieldDescriptor) + { + super(tag); + this.className = className; + this.fieldName = fieldName; + this.fieldDescriptor = fieldDescriptor; + } +} diff --git a/src/jd/core/model/classfile/accessor/InvokeMethodAccessor.java b/src/jd/core/model/classfile/accessor/InvokeMethodAccessor.java new file mode 100644 index 00000000..3496a60b --- /dev/null +++ b/src/jd/core/model/classfile/accessor/InvokeMethodAccessor.java @@ -0,0 +1,28 @@ +package jd.core.model.classfile.accessor; + +import java.util.List; + + +public class InvokeMethodAccessor extends Accessor +{ + final public String className; + final public int methodOpcode; + final public String methodName; + final public String methodDescriptor; + final public List listOfParameterSignatures; + final public String returnedSignature; + + public InvokeMethodAccessor( + byte tag, String className, int methodOpcode, + String methodName, String methodDescriptor, + List listOfParameterSignatures, String returnedSignature) + { + super(tag); + this.className = className; + this.methodOpcode = methodOpcode; + this.methodName = methodName; + this.methodDescriptor = methodDescriptor; + this.listOfParameterSignatures = listOfParameterSignatures; + this.returnedSignature = returnedSignature; + } +} diff --git a/src/jd/core/model/classfile/accessor/PutFieldAccessor.java b/src/jd/core/model/classfile/accessor/PutFieldAccessor.java new file mode 100644 index 00000000..a68ae97d --- /dev/null +++ b/src/jd/core/model/classfile/accessor/PutFieldAccessor.java @@ -0,0 +1,18 @@ +package jd.core.model.classfile.accessor; + + +public class PutFieldAccessor extends Accessor +{ + final public String className; + final public String fieldName; + final public String fieldDescriptor; + + public PutFieldAccessor( + byte tag, String className, String fieldName, String fieldDescriptor) + { + super(tag); + this.className = className; + this.fieldName = fieldName; + this.fieldDescriptor = fieldDescriptor; + } +} diff --git a/src/jd/core/model/classfile/accessor/PutStaticAccessor.java b/src/jd/core/model/classfile/accessor/PutStaticAccessor.java new file mode 100644 index 00000000..1c538396 --- /dev/null +++ b/src/jd/core/model/classfile/accessor/PutStaticAccessor.java @@ -0,0 +1,18 @@ +package jd.core.model.classfile.accessor; + + +public class PutStaticAccessor extends Accessor +{ + final public String className; + final public String fieldName; + final public String fieldDescriptor; + + public PutStaticAccessor( + byte tag, String className, String fieldName, String fieldDescriptor) + { + super(tag); + this.className = className; + this.fieldName = fieldName; + this.fieldDescriptor = fieldDescriptor; + } +} diff --git a/src/jd/core/model/classfile/attribute/Annotation.java b/src/jd/core/model/classfile/attribute/Annotation.java new file mode 100644 index 00000000..5aebeee7 --- /dev/null +++ b/src/jd/core/model/classfile/attribute/Annotation.java @@ -0,0 +1,14 @@ +package jd.core.model.classfile.attribute; + + +public class Annotation +{ + public final int type_index; + public final ElementValuePair[] elementValuePairs; + + public Annotation(int type_index, ElementValuePair[] elementValuePairs) + { + this.type_index = type_index; + this.elementValuePairs = elementValuePairs; + } +} diff --git a/src/jd/core/model/classfile/attribute/Attribute.java b/src/jd/core/model/classfile/attribute/Attribute.java new file mode 100644 index 00000000..2cddf50a --- /dev/null +++ b/src/jd/core/model/classfile/attribute/Attribute.java @@ -0,0 +1,13 @@ +package jd.core.model.classfile.attribute; + +public class Attribute +{ + public final byte tag; + public final int attribute_name_index; + + public Attribute(byte tag, int attribute_name_index) + { + this.tag = tag; + this.attribute_name_index = attribute_name_index; + } +} diff --git a/src/jd/core/model/classfile/attribute/AttributeAnnotationDefault.java b/src/jd/core/model/classfile/attribute/AttributeAnnotationDefault.java new file mode 100644 index 00000000..1305cd00 --- /dev/null +++ b/src/jd/core/model/classfile/attribute/AttributeAnnotationDefault.java @@ -0,0 +1,15 @@ +package jd.core.model.classfile.attribute; + + +public class AttributeAnnotationDefault extends Attribute +{ + public final ElementValue default_value; + + public AttributeAnnotationDefault(byte tag, + int attribute_name_index, + ElementValue default_value) + { + super(tag, attribute_name_index); + this.default_value = default_value; + } +} diff --git a/src/jd/core/model/classfile/attribute/AttributeCode.java b/src/jd/core/model/classfile/attribute/AttributeCode.java new file mode 100644 index 00000000..04f4c2b5 --- /dev/null +++ b/src/jd/core/model/classfile/attribute/AttributeCode.java @@ -0,0 +1,56 @@ +package jd.core.model.classfile.attribute; + + + +public class AttributeCode extends Attribute +{ + //private int max_stack; + //private int max_locals; + public final byte[] code; + public final CodeException[] exception_table; + public final Attribute[] attributes; + + public AttributeCode(byte tag, + int attribute_name_index, int max_stack, + int max_locals, byte[] code, + CodeException[] exception_table, + Attribute[] attributes) + { + super(tag, attribute_name_index); + //this.max_stack = max_stack; + //this.max_locals = max_locals; + this.code = code; + this.exception_table = exception_table; + this.attributes = attributes; + } + + public AttributeNumberTable getAttributeLineNumberTable() + { + if (this.attributes != null) + for (int i=this.attributes.length-1; i>=0; --i) + if (this.attributes[i].tag == AttributeConstants.ATTR_NUMBER_TABLE) + return (AttributeNumberTable)this.attributes[i]; + + return null; + } + + public AttributeLocalVariableTable getAttributeLocalVariableTable() + { + if (this.attributes != null) + for (int i=this.attributes.length-1; i>=0; --i) + if (this.attributes[i].tag == AttributeConstants.ATTR_LOCAL_VARIABLE_TABLE) + return (AttributeLocalVariableTable)this.attributes[i]; + + return null; + } + + public AttributeLocalVariableTable getAttributeLocalVariableTypeTable() + { + if (this.attributes != null) + for (int i=this.attributes.length-1; i>=0; --i) + if (this.attributes[i].tag == AttributeConstants.ATTR_LOCAL_VARIABLE_TYPE_TABLE) + return (AttributeLocalVariableTable)this.attributes[i]; + + return null; + } +} diff --git a/src/jd/core/model/classfile/attribute/AttributeConstantValue.java b/src/jd/core/model/classfile/attribute/AttributeConstantValue.java new file mode 100644 index 00000000..95d85106 --- /dev/null +++ b/src/jd/core/model/classfile/attribute/AttributeConstantValue.java @@ -0,0 +1,15 @@ +package jd.core.model.classfile.attribute; + + +public class AttributeConstantValue extends Attribute +{ + public final int constantvalue_index; + + public AttributeConstantValue(byte tag, + int attribute_name_index, + int constantvalue_index) + { + super(tag, attribute_name_index); + this.constantvalue_index = constantvalue_index; + } +} diff --git a/src/jd/core/model/classfile/attribute/AttributeConstants.java b/src/jd/core/model/classfile/attribute/AttributeConstants.java new file mode 100644 index 00000000..e9c476e5 --- /dev/null +++ b/src/jd/core/model/classfile/attribute/AttributeConstants.java @@ -0,0 +1,27 @@ +package jd.core.model.classfile.attribute; + + +public class AttributeConstants +{ + public static final byte ATTR_UNKNOWN= 0; + public static final byte ATTR_SOURCE_FILE= 1; + public static final byte ATTR_CONSTANT_VALUE = 2; + public static final byte ATTR_CODE = 3; + public static final byte ATTR_EXCEPTIONS = 4; + public static final byte ATTR_LINE_NUMBER_TABLE= 5; + public static final byte ATTR_LOCAL_VARIABLE_TABLE = 6; + public static final byte ATTR_LOCAL_VARIABLE_TYPE_TABLE = 7; + public static final byte ATTR_INNER_CLASSES= 8; + public static final byte ATTR_SYNTHETIC= 9; + public static final byte ATTR_DEPRECATED = 10; + public static final byte ATTR_PMG= 11; + public static final byte ATTR_SIGNATURE= 12; + public static final byte ATTR_STACK_MAP= 13; + public static final byte ATTR_ENCLOSING_METHOD= 14; + public static final byte ATTR_NUMBER_TABLE= 15; + public static final byte ATTR_RUNTIME_VISIBLE_ANNOTATIONS= 16; + public static final byte ATTR_RUNTIME_INVISIBLE_ANNOTATIONS= 17; + public static final byte ATTR_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS= 18; + public static final byte ATTR_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS= 19; + public static final byte ATTR_ANNOTATION_DEFAULT= 20; +} diff --git a/src/jd/core/model/classfile/attribute/AttributeDeprecated.java b/src/jd/core/model/classfile/attribute/AttributeDeprecated.java new file mode 100644 index 00000000..b862b737 --- /dev/null +++ b/src/jd/core/model/classfile/attribute/AttributeDeprecated.java @@ -0,0 +1,10 @@ +package jd.core.model.classfile.attribute; + + +public class AttributeDeprecated extends Attribute +{ + public AttributeDeprecated(byte tag, int attribute_name_index) + { + super(tag, attribute_name_index); + } +} diff --git a/src/jd/core/model/classfile/attribute/AttributeEnclosingMethod.java b/src/jd/core/model/classfile/attribute/AttributeEnclosingMethod.java new file mode 100644 index 00000000..b2287c0c --- /dev/null +++ b/src/jd/core/model/classfile/attribute/AttributeEnclosingMethod.java @@ -0,0 +1,16 @@ +package jd.core.model.classfile.attribute; + + +public class AttributeEnclosingMethod extends Attribute +{ + public final int class_index; + public final int method_index; + + public AttributeEnclosingMethod(byte tag, int attribute_name_index, + int class_index, int method_index) + { + super(tag, attribute_name_index); + this.class_index = class_index; + this.method_index = method_index; + } +} diff --git a/src/jd/core/model/classfile/attribute/AttributeExceptions.java b/src/jd/core/model/classfile/attribute/AttributeExceptions.java new file mode 100644 index 00000000..48be33c8 --- /dev/null +++ b/src/jd/core/model/classfile/attribute/AttributeExceptions.java @@ -0,0 +1,15 @@ +package jd.core.model.classfile.attribute; + + +public class AttributeExceptions extends Attribute +{ + public final int[] exception_index_table; + + public AttributeExceptions(byte tag, + int attribute_name_index, + int[] exception_index_table) + { + super(tag, attribute_name_index); + this.exception_index_table = exception_index_table; + } +} diff --git a/src/jd/core/model/classfile/attribute/AttributeInnerClasses.java b/src/jd/core/model/classfile/attribute/AttributeInnerClasses.java new file mode 100644 index 00000000..18dc24fa --- /dev/null +++ b/src/jd/core/model/classfile/attribute/AttributeInnerClasses.java @@ -0,0 +1,15 @@ +package jd.core.model.classfile.attribute; + + +public class AttributeInnerClasses extends Attribute +{ + public final InnerClass[] classes; + + public AttributeInnerClasses(byte tag, + int attribute_name_index, + InnerClass[] classes) + { + super(tag, attribute_name_index); + this.classes = classes; + } +} diff --git a/src/jd/core/model/classfile/attribute/AttributeLocalVariableTable.java b/src/jd/core/model/classfile/attribute/AttributeLocalVariableTable.java new file mode 100644 index 00000000..94497594 --- /dev/null +++ b/src/jd/core/model/classfile/attribute/AttributeLocalVariableTable.java @@ -0,0 +1,17 @@ +package jd.core.model.classfile.attribute; + +import jd.core.model.classfile.LocalVariable; + + +public class AttributeLocalVariableTable extends Attribute +{ + public final LocalVariable[] local_variable_table; + + public AttributeLocalVariableTable(byte tag, + int attribute_name_index, + LocalVariable[] local_variable_table) + { + super(tag, attribute_name_index); + this.local_variable_table = local_variable_table; + } +} diff --git a/src/jd/core/model/classfile/attribute/AttributeNumberTable.java b/src/jd/core/model/classfile/attribute/AttributeNumberTable.java new file mode 100644 index 00000000..5a0b78da --- /dev/null +++ b/src/jd/core/model/classfile/attribute/AttributeNumberTable.java @@ -0,0 +1,14 @@ +package jd.core.model.classfile.attribute; + + +public class AttributeNumberTable extends Attribute +{ + public final LineNumber[] line_number_table; + + public AttributeNumberTable(byte tag, int attribute_name_index, + LineNumber[] line_number_table) + { + super(tag, attribute_name_index); + this.line_number_table = line_number_table; + } +} \ No newline at end of file diff --git a/src/jd/core/model/classfile/attribute/AttributeRuntimeAnnotations.java b/src/jd/core/model/classfile/attribute/AttributeRuntimeAnnotations.java new file mode 100644 index 00000000..7a593d2d --- /dev/null +++ b/src/jd/core/model/classfile/attribute/AttributeRuntimeAnnotations.java @@ -0,0 +1,15 @@ +package jd.core.model.classfile.attribute; + + +public class AttributeRuntimeAnnotations extends Attribute +{ + public final Annotation[] annotations; + + public AttributeRuntimeAnnotations(byte tag, + int attribute_name_index, + Annotation[] annotations) + { + super(tag, attribute_name_index); + this.annotations = annotations; + } +} diff --git a/src/jd/core/model/classfile/attribute/AttributeRuntimeParameterAnnotations.java b/src/jd/core/model/classfile/attribute/AttributeRuntimeParameterAnnotations.java new file mode 100644 index 00000000..05e1a3f2 --- /dev/null +++ b/src/jd/core/model/classfile/attribute/AttributeRuntimeParameterAnnotations.java @@ -0,0 +1,14 @@ +package jd.core.model.classfile.attribute; + +public class AttributeRuntimeParameterAnnotations extends Attribute +{ + public ParameterAnnotations[] parameter_annotations; + + public AttributeRuntimeParameterAnnotations( + byte tag, int attribute_name_index, + ParameterAnnotations[] parameter_annotations) + { + super(tag, attribute_name_index); + this.parameter_annotations = parameter_annotations; + } +} diff --git a/src/jd/core/model/classfile/attribute/AttributeSignature.java b/src/jd/core/model/classfile/attribute/AttributeSignature.java new file mode 100644 index 00000000..8482106c --- /dev/null +++ b/src/jd/core/model/classfile/attribute/AttributeSignature.java @@ -0,0 +1,14 @@ +package jd.core.model.classfile.attribute; + + +public class AttributeSignature extends Attribute +{ + public final int signature_index; + + public AttributeSignature( + byte tag, int attribute_name_index, int signature_index) + { + super(tag, attribute_name_index); + this.signature_index = signature_index; + } +} diff --git a/src/jd/core/model/classfile/attribute/AttributeSourceFile.java b/src/jd/core/model/classfile/attribute/AttributeSourceFile.java new file mode 100644 index 00000000..d56440f3 --- /dev/null +++ b/src/jd/core/model/classfile/attribute/AttributeSourceFile.java @@ -0,0 +1,14 @@ +package jd.core.model.classfile.attribute; + + +public class AttributeSourceFile extends Attribute +{ + public final int sourcefile_index; + + public AttributeSourceFile( + byte tag, int attribute_name_index, int sourcefile_index) + { + super(tag, attribute_name_index); + this.sourcefile_index = sourcefile_index; + } +} diff --git a/src/jd/core/model/classfile/attribute/AttributeSynthetic.java b/src/jd/core/model/classfile/attribute/AttributeSynthetic.java new file mode 100644 index 00000000..7ac17318 --- /dev/null +++ b/src/jd/core/model/classfile/attribute/AttributeSynthetic.java @@ -0,0 +1,10 @@ +package jd.core.model.classfile.attribute; + + +public class AttributeSynthetic extends Attribute +{ + public AttributeSynthetic(byte tag, int attribute_name_index) + { + super(tag, attribute_name_index); + } +} diff --git a/src/jd/core/model/classfile/attribute/CodeException.java b/src/jd/core/model/classfile/attribute/CodeException.java new file mode 100644 index 00000000..85b3e978 --- /dev/null +++ b/src/jd/core/model/classfile/attribute/CodeException.java @@ -0,0 +1,21 @@ +package jd.core.model.classfile.attribute; + + +public class CodeException +{ + public int index; + public int start_pc; + public int end_pc; + public final int handler_pc; + public final int catch_type; + + public CodeException(int index, int start_pc, int end_pc, + int handler_pc, int catch_type) + { + this.index = index; + this.start_pc = start_pc; + this.end_pc = end_pc; + this.handler_pc = handler_pc; + this.catch_type = catch_type; + } +} diff --git a/src/jd/core/model/classfile/attribute/ElementValue.java b/src/jd/core/model/classfile/attribute/ElementValue.java new file mode 100644 index 00000000..a3a5d923 --- /dev/null +++ b/src/jd/core/model/classfile/attribute/ElementValue.java @@ -0,0 +1,12 @@ +package jd.core.model.classfile.attribute; + + +public class ElementValue +{ + public final byte tag; + + public ElementValue(byte tag) + { + this.tag = tag; + } +} diff --git a/src/jd/core/model/classfile/attribute/ElementValueAnnotationValue.java b/src/jd/core/model/classfile/attribute/ElementValueAnnotationValue.java new file mode 100644 index 00000000..9d4ddca0 --- /dev/null +++ b/src/jd/core/model/classfile/attribute/ElementValueAnnotationValue.java @@ -0,0 +1,13 @@ +package jd.core.model.classfile.attribute; + + +public class ElementValueAnnotationValue extends ElementValue +{ + final public Annotation annotation_value; + + public ElementValueAnnotationValue(byte tag, Annotation annotation_value) + { + super(tag); + this.annotation_value = annotation_value; + } +} diff --git a/src/jd/core/model/classfile/attribute/ElementValueArrayValue.java b/src/jd/core/model/classfile/attribute/ElementValueArrayValue.java new file mode 100644 index 00000000..72b01720 --- /dev/null +++ b/src/jd/core/model/classfile/attribute/ElementValueArrayValue.java @@ -0,0 +1,13 @@ +package jd.core.model.classfile.attribute; + + +public class ElementValueArrayValue extends ElementValue +{ + final public ElementValue[] values; + + public ElementValueArrayValue(byte tag, ElementValue[] values) + { + super(tag); + this.values = values; + } +} diff --git a/src/jd/core/model/classfile/attribute/ElementValueClassInfo.java b/src/jd/core/model/classfile/attribute/ElementValueClassInfo.java new file mode 100644 index 00000000..09fed9df --- /dev/null +++ b/src/jd/core/model/classfile/attribute/ElementValueClassInfo.java @@ -0,0 +1,13 @@ +package jd.core.model.classfile.attribute; + + +public class ElementValueClassInfo extends ElementValue +{ + final public int class_info_index; + + public ElementValueClassInfo(byte tag, int class_info_index) + { + super(tag); + this.class_info_index = class_info_index; + } +} diff --git a/src/jd/core/model/classfile/attribute/ElementValueContants.java b/src/jd/core/model/classfile/attribute/ElementValueContants.java new file mode 100644 index 00000000..cbdcc8a7 --- /dev/null +++ b/src/jd/core/model/classfile/attribute/ElementValueContants.java @@ -0,0 +1,12 @@ +package jd.core.model.classfile.attribute; + + +public class ElementValueContants +{ + public static final byte EV_UNKNOWN= 0; + public static final byte EV_PRIMITIVE_TYPE= 1; + public static final byte EV_ENUM_CONST_VALUE= 2; + public static final byte EV_CLASS_INFO= 3; + public static final byte EV_ANNOTATION_VALUE= 4; + public static final byte EV_ARRAY_VALUE= 5; +} diff --git a/src/jd/core/model/classfile/attribute/ElementValueEnumConstValue.java b/src/jd/core/model/classfile/attribute/ElementValueEnumConstValue.java new file mode 100644 index 00000000..b587c226 --- /dev/null +++ b/src/jd/core/model/classfile/attribute/ElementValueEnumConstValue.java @@ -0,0 +1,17 @@ +package jd.core.model.classfile.attribute; + + +public class ElementValueEnumConstValue extends ElementValue +{ + final public int type_name_index; + final public int const_name_index; + + public ElementValueEnumConstValue(byte tag, + int type_name_index, + int const_name_index) + { + super(tag); + this.type_name_index = type_name_index; + this.const_name_index = const_name_index; + } +} diff --git a/src/jd/core/model/classfile/attribute/ElementValuePair.java b/src/jd/core/model/classfile/attribute/ElementValuePair.java new file mode 100644 index 00000000..2e0641fc --- /dev/null +++ b/src/jd/core/model/classfile/attribute/ElementValuePair.java @@ -0,0 +1,14 @@ +package jd.core.model.classfile.attribute; + + +public class ElementValuePair +{ + public final int element_name_index; + public final ElementValue element_value; + + public ElementValuePair(int element_name_index, ElementValue element_value) + { + this.element_name_index = element_name_index; + this.element_value = element_value; + } +} diff --git a/src/jd/core/model/classfile/attribute/ElementValuePrimitiveType.java b/src/jd/core/model/classfile/attribute/ElementValuePrimitiveType.java new file mode 100644 index 00000000..66d72464 --- /dev/null +++ b/src/jd/core/model/classfile/attribute/ElementValuePrimitiveType.java @@ -0,0 +1,18 @@ +package jd.core.model.classfile.attribute; + + +public class ElementValuePrimitiveType extends ElementValue +{ + /* + * type = {'B', 'D', 'F', 'I', 'J', 'S', 'Z', 'C', 's'} + */ + public byte type; + final public int const_value_index; + + public ElementValuePrimitiveType(byte tag, byte type, int const_value_index) + { + super(tag); + this.type = type; + this.const_value_index = const_value_index; + } +} diff --git a/src/jd/core/model/classfile/attribute/InnerClass.java b/src/jd/core/model/classfile/attribute/InnerClass.java new file mode 100644 index 00000000..1cc36507 --- /dev/null +++ b/src/jd/core/model/classfile/attribute/InnerClass.java @@ -0,0 +1,19 @@ +package jd.core.model.classfile.attribute; + + +public class InnerClass +{ + public final int inner_class_index; + public final int outer_class_index; + public final int inner_name_index; + public final int inner_access_flags; + + public InnerClass(int inner_class_index, int outer_class_index, + int inner_name_index, int inner_access_flags) + { + this.inner_class_index = inner_class_index; + this.outer_class_index = outer_class_index; + this.inner_name_index = inner_name_index; + this.inner_access_flags = inner_access_flags; + } +} diff --git a/src/jd/core/model/classfile/attribute/LineNumber.java b/src/jd/core/model/classfile/attribute/LineNumber.java new file mode 100644 index 00000000..f35a9f86 --- /dev/null +++ b/src/jd/core/model/classfile/attribute/LineNumber.java @@ -0,0 +1,14 @@ +package jd.core.model.classfile.attribute; + + +public class LineNumber +{ + public final int start_pc; + public final int line_number; + + public LineNumber(int start_pc, int line_number) + { + this.start_pc = start_pc; + this.line_number = line_number; + } +} diff --git a/src/jd/core/model/classfile/attribute/ParameterAnnotations.java b/src/jd/core/model/classfile/attribute/ParameterAnnotations.java new file mode 100644 index 00000000..6ed45e2a --- /dev/null +++ b/src/jd/core/model/classfile/attribute/ParameterAnnotations.java @@ -0,0 +1,12 @@ +package jd.core.model.classfile.attribute; + + +public class ParameterAnnotations +{ + public Annotation[] annotations; + + public ParameterAnnotations(Annotation[] annotations) + { + this.annotations = annotations; + } +} diff --git a/src/jd/core/model/classfile/attribute/UnknowAttribute.java b/src/jd/core/model/classfile/attribute/UnknowAttribute.java new file mode 100644 index 00000000..9f9d3afe --- /dev/null +++ b/src/jd/core/model/classfile/attribute/UnknowAttribute.java @@ -0,0 +1,10 @@ +package jd.core.model.classfile.attribute; + + +public class UnknowAttribute extends Attribute +{ + public UnknowAttribute(byte tag, int attribute_name_index) + { + super(tag, attribute_name_index); + } +} diff --git a/src/jd/core/model/classfile/constant/Constant.java b/src/jd/core/model/classfile/constant/Constant.java new file mode 100644 index 00000000..c430d75d --- /dev/null +++ b/src/jd/core/model/classfile/constant/Constant.java @@ -0,0 +1,11 @@ +package jd.core.model.classfile.constant; + +public abstract class Constant +{ + final public byte tag; + + protected Constant(byte tag) + { + this.tag = tag; + } +} diff --git a/src/jd/core/model/classfile/constant/ConstantClass.java b/src/jd/core/model/classfile/constant/ConstantClass.java new file mode 100644 index 00000000..82c2c6a1 --- /dev/null +++ b/src/jd/core/model/classfile/constant/ConstantClass.java @@ -0,0 +1,13 @@ +package jd.core.model.classfile.constant; + + +public class ConstantClass extends Constant +{ + final public int name_index; + + public ConstantClass(byte tag, int name_index) + { + super(tag); + this.name_index = name_index; + } +} diff --git a/src/jd/core/model/classfile/constant/ConstantConstant.java b/src/jd/core/model/classfile/constant/ConstantConstant.java new file mode 100644 index 00000000..90e617c7 --- /dev/null +++ b/src/jd/core/model/classfile/constant/ConstantConstant.java @@ -0,0 +1,17 @@ +package jd.core.model.classfile.constant; + +public class ConstantConstant +{ + public static final byte CONSTANT_Unknown = 0; + public static final byte CONSTANT_Utf8 = 1; + public static final byte CONSTANT_Integer = 3; + public static final byte CONSTANT_Float = 4; + public static final byte CONSTANT_Long = 5; + public static final byte CONSTANT_Double = 6; + public static final byte CONSTANT_Class = 7; + public static final byte CONSTANT_String = 8; + public static final byte CONSTANT_Fieldref = 9; + public static final byte CONSTANT_Methodref = 10; + public static final byte CONSTANT_InterfaceMethodref = 11; + public static final byte CONSTANT_NameAndType = 12; +} diff --git a/src/jd/core/model/classfile/constant/ConstantDouble.java b/src/jd/core/model/classfile/constant/ConstantDouble.java new file mode 100644 index 00000000..51913d0b --- /dev/null +++ b/src/jd/core/model/classfile/constant/ConstantDouble.java @@ -0,0 +1,13 @@ +package jd.core.model.classfile.constant; + + +public class ConstantDouble extends ConstantValue +{ + final public double bytes; + + public ConstantDouble(byte tag, double bytes) + { + super(tag); + this.bytes = bytes; + } +} diff --git a/src/jd/core/model/classfile/constant/ConstantFieldref.java b/src/jd/core/model/classfile/constant/ConstantFieldref.java new file mode 100644 index 00000000..6b9087c8 --- /dev/null +++ b/src/jd/core/model/classfile/constant/ConstantFieldref.java @@ -0,0 +1,17 @@ +package jd.core.model.classfile.constant; + + +public class ConstantFieldref extends Constant +{ + final public int class_index; + final public int name_and_type_index; + + public ConstantFieldref(byte tag, + int class_index, + int name_and_type_index) + { + super(tag); + this.class_index = class_index; + this.name_and_type_index = name_and_type_index; + } +} diff --git a/src/jd/core/model/classfile/constant/ConstantFloat.java b/src/jd/core/model/classfile/constant/ConstantFloat.java new file mode 100644 index 00000000..03bc512d --- /dev/null +++ b/src/jd/core/model/classfile/constant/ConstantFloat.java @@ -0,0 +1,13 @@ +package jd.core.model.classfile.constant; + + +public class ConstantFloat extends ConstantValue +{ + final public float bytes; + + public ConstantFloat(byte tag, float bytes) + { + super(tag); + this.bytes = bytes; + } +} diff --git a/src/jd/core/model/classfile/constant/ConstantInteger.java b/src/jd/core/model/classfile/constant/ConstantInteger.java new file mode 100644 index 00000000..4209b571 --- /dev/null +++ b/src/jd/core/model/classfile/constant/ConstantInteger.java @@ -0,0 +1,13 @@ +package jd.core.model.classfile.constant; + + +public class ConstantInteger extends ConstantValue +{ + final public int bytes; + + public ConstantInteger(byte tag, int bytes) + { + super(tag); + this.bytes = bytes; + } +} diff --git a/src/jd/core/model/classfile/constant/ConstantInterfaceMethodref.java b/src/jd/core/model/classfile/constant/ConstantInterfaceMethodref.java new file mode 100644 index 00000000..d54c01c9 --- /dev/null +++ b/src/jd/core/model/classfile/constant/ConstantInterfaceMethodref.java @@ -0,0 +1,12 @@ +package jd.core.model.classfile.constant; + + +public class ConstantInterfaceMethodref extends ConstantMethodref +{ + public ConstantInterfaceMethodref(byte tag, + int class_index, + int name_and_type_index) + { + super(tag, class_index, name_and_type_index); + } +} diff --git a/src/jd/core/model/classfile/constant/ConstantLong.java b/src/jd/core/model/classfile/constant/ConstantLong.java new file mode 100644 index 00000000..85dde4ea --- /dev/null +++ b/src/jd/core/model/classfile/constant/ConstantLong.java @@ -0,0 +1,13 @@ +package jd.core.model.classfile.constant; + + +public class ConstantLong extends ConstantValue +{ + final public long bytes; + + public ConstantLong(byte tag, long bytes) + { + super(tag); + this.bytes = bytes; + } +} diff --git a/src/jd/core/model/classfile/constant/ConstantMethodref.java b/src/jd/core/model/classfile/constant/ConstantMethodref.java new file mode 100644 index 00000000..52c1037a --- /dev/null +++ b/src/jd/core/model/classfile/constant/ConstantMethodref.java @@ -0,0 +1,64 @@ +package jd.core.model.classfile.constant; + +import java.util.List; + + +public class ConstantMethodref extends Constant +{ + final public int class_index; + final public int name_and_type_index; + + private List listOfParameterSignatures; + private String returnedSignature; + + public ConstantMethodref( + byte tag, int class_index, int name_and_type_index) + { + super(tag); + this.class_index = class_index; + this.name_and_type_index = name_and_type_index; + + this.listOfParameterSignatures = null; + this.returnedSignature = null; + } + + public ConstantMethodref( + byte tag, int class_index, int name_and_type_index, + List listOfParameterSignatures, String returnedSignature) + { + super(tag); + this.class_index = class_index; + this.name_and_type_index = name_and_type_index; + + this.listOfParameterSignatures = listOfParameterSignatures; + this.returnedSignature = returnedSignature; + } + + public List getListOfParameterSignatures() + { + return listOfParameterSignatures; + } + public void setParameterSignatures(List listOfParameterSignatures) + { + this.listOfParameterSignatures = listOfParameterSignatures; + } + public int getNbrOfParameters() + { + return (this.listOfParameterSignatures == null) ? + 0 : this.listOfParameterSignatures.size(); + } + + public String getReturnedSignature() + { + return returnedSignature; + } + public void setReturnedSignature(String returnedSignature) + { + this.returnedSignature = returnedSignature; + } + public boolean returnAResult() + { + return (this.returnedSignature == null) ? + false : !"V".equals(this.returnedSignature); + } +} diff --git a/src/jd/core/model/classfile/constant/ConstantNameAndType.java b/src/jd/core/model/classfile/constant/ConstantNameAndType.java new file mode 100644 index 00000000..a0bf785c --- /dev/null +++ b/src/jd/core/model/classfile/constant/ConstantNameAndType.java @@ -0,0 +1,15 @@ +package jd.core.model.classfile.constant; + + +public class ConstantNameAndType extends Constant +{ + public int name_index; + final public int descriptor_index; + + public ConstantNameAndType(byte tag, int name_index, int descriptor_index) + { + super(tag); + this.name_index = name_index; + this.descriptor_index = descriptor_index; + } +} diff --git a/src/jd/core/model/classfile/constant/ConstantString.java b/src/jd/core/model/classfile/constant/ConstantString.java new file mode 100644 index 00000000..62b4423f --- /dev/null +++ b/src/jd/core/model/classfile/constant/ConstantString.java @@ -0,0 +1,13 @@ +package jd.core.model.classfile.constant; + + +public class ConstantString extends ConstantValue +{ + final public int string_index; + + public ConstantString(byte tag, int string_index) + { + super(tag); + this.string_index = string_index; + } +} diff --git a/src/jd/core/model/classfile/constant/ConstantUtf8.java b/src/jd/core/model/classfile/constant/ConstantUtf8.java new file mode 100644 index 00000000..9bc91475 --- /dev/null +++ b/src/jd/core/model/classfile/constant/ConstantUtf8.java @@ -0,0 +1,13 @@ +package jd.core.model.classfile.constant; + + +public class ConstantUtf8 extends Constant +{ + public String bytes; + + public ConstantUtf8(byte tag, String bytes) + { + super(tag); + this.bytes = bytes; + } +} diff --git a/src/jd/core/model/classfile/constant/ConstantValue.java b/src/jd/core/model/classfile/constant/ConstantValue.java new file mode 100644 index 00000000..8abfe364 --- /dev/null +++ b/src/jd/core/model/classfile/constant/ConstantValue.java @@ -0,0 +1,10 @@ +package jd.core.model.classfile.constant; + + +public abstract class ConstantValue extends Constant +{ + public ConstantValue(byte tag) + { + super(tag); + } +} diff --git a/src/jd/core/model/instruction/bytecode/ByteCodeConstants.java b/src/jd/core/model/instruction/bytecode/ByteCodeConstants.java new file mode 100644 index 00000000..41e24170 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/ByteCodeConstants.java @@ -0,0 +1,478 @@ +package jd.core.model.instruction.bytecode; + + + + +public class ByteCodeConstants +{ + public static final short NO_OF_OPERANDS_UNDEFINED = -1; + public static final short NO_OF_OPERANDS_UNPREDICTABLE = -2; + public static final short NO_OF_OPERANDS_RESERVED = -3; + + public static final String ILLEGAL_OPCODE = ""; + public static final String ILLEGAL_TYPE = ""; + + + /** Java VM opcodes. + */ + public static final int NOP = 0; + public static final int ACONST_NULL = 1; + public static final int ICONST_M1 = 2; + public static final int ICONST_0 = 3; + public static final int ICONST_1 = 4; + public static final int ICONST_2 = 5; + public static final int ICONST_3 = 6; + public static final int ICONST_4 = 7; + public static final int ICONST_5 = 8; + public static final int LCONST_0 = 9; + public static final int LCONST_1 = 10; + public static final int FCONST_0 = 11; + public static final int FCONST_1 = 12; + public static final int FCONST_2 = 13; + public static final int DCONST_0 = 14; + public static final int DCONST_1 = 15; + public static final int BIPUSH = 16; + public static final int SIPUSH = 17; + public static final int LDC = 18; + public static final int LDC_W = 19; + public static final int LDC2_W = 20; + public static final int ILOAD = 21; + public static final int LLOAD = 22; + public static final int FLOAD = 23; + public static final int DLOAD = 24; + public static final int ALOAD = 25; + public static final int ILOAD_0 = 26; + public static final int ILOAD_1 = 27; + public static final int ILOAD_2 = 28; + public static final int ILOAD_3 = 29; + public static final int LLOAD_0 = 30; + public static final int LLOAD_1 = 31; + public static final int LLOAD_2 = 32; + public static final int LLOAD_3 = 33; + public static final int FLOAD_0 = 34; + public static final int FLOAD_1 = 35; + public static final int FLOAD_2 = 36; + public static final int FLOAD_3 = 37; + public static final int DLOAD_0 = 38; + public static final int DLOAD_1 = 39; + public static final int DLOAD_2 = 40; + public static final int DLOAD_3 = 41; + public static final int ALOAD_0 = 42; + public static final int ALOAD_1 = 43; + public static final int ALOAD_2 = 44; + public static final int ALOAD_3 = 45; + public static final int IALOAD = 46; + public static final int LALOAD = 47; + public static final int FALOAD = 48; + public static final int DALOAD = 49; + public static final int AALOAD = 50; + public static final int BALOAD = 51; + public static final int CALOAD = 52; + public static final int SALOAD = 53; + public static final int ISTORE = 54; + public static final int LSTORE = 55; + public static final int FSTORE = 56; + public static final int DSTORE = 57; + public static final int ASTORE = 58; + public static final int ISTORE_0 = 59; + public static final int ISTORE_1 = 60; + public static final int ISTORE_2 = 61; + public static final int ISTORE_3 = 62; + public static final int LSTORE_0 = 63; + public static final int LSTORE_1 = 64; + public static final int LSTORE_2 = 65; + public static final int LSTORE_3 = 66; + public static final int FSTORE_0 = 67; + public static final int FSTORE_1 = 68; + public static final int FSTORE_2 = 69; + public static final int FSTORE_3 = 70; + public static final int DSTORE_0 = 71; + public static final int DSTORE_1 = 72; + public static final int DSTORE_2 = 73; + public static final int DSTORE_3 = 74; + public static final int ASTORE_0 = 75; + public static final int ASTORE_1 = 76; + public static final int ASTORE_2 = 77; + public static final int ASTORE_3 = 78; + public static final int IASTORE = 79; + public static final int LASTORE = 80; + public static final int FASTORE = 81; + public static final int DASTORE = 82; + public static final int AASTORE = 83; + public static final int BASTORE = 84; + public static final int CASTORE = 85; + public static final int SASTORE = 86; + public static final int POP = 87; + public static final int POP2 = 88; + public static final int DUP = 89; + public static final int DUP_X1 = 90; + public static final int DUP_X2 = 91; + public static final int DUP2 = 92; + public static final int DUP2_X1 = 93; + public static final int DUP2_X2 = 94; + public static final int SWAP = 95; + public static final int IADD = 96; + public static final int LADD = 97; + public static final int FADD = 98; + public static final int DADD = 99; + public static final int ISUB = 100; + public static final int LSUB = 101; + public static final int FSUB = 102; + public static final int DSUB = 103; + public static final int IMUL = 104; + public static final int LMUL = 105; + public static final int FMUL = 106; + public static final int DMUL = 107; + public static final int IDIV = 108; + public static final int LDIV = 109; + public static final int FDIV = 110; + public static final int DDIV = 111; + public static final int IREM = 112; + public static final int LREM = 113; + public static final int FREM = 114; + public static final int DREM = 115; + public static final int INEG = 116; + public static final int LNEG = 117; + public static final int FNEG = 118; + public static final int DNEG = 119; + public static final int ISHL = 120; + public static final int LSHL = 121; + public static final int ISHR = 122; + public static final int LSHR = 123; + public static final int IUSHR = 124; + public static final int LUSHR = 125; + public static final int IAND = 126; + public static final int LAND = 127; + public static final int IOR = 128; + public static final int LOR = 129; + public static final int IXOR = 130; + public static final int LXOR = 131; + public static final int IINC = 132; + public static final int I2L = 133; + public static final int I2F = 134; + public static final int I2D = 135; + public static final int L2I = 136; + public static final int L2F = 137; + public static final int L2D = 138; + public static final int F2I = 139; + public static final int F2L = 140; + public static final int F2D = 141; + public static final int D2I = 142; + public static final int D2L = 143; + public static final int D2F = 144; + public static final int I2B = 145; + public static final int INT2BYTE = 145; // Old notion + public static final int I2C = 146; + public static final int INT2CHAR = 146; // Old notion + public static final int I2S = 147; + public static final int INT2SHORT = 147; // Old notion + public static final int LCMP = 148; + public static final int FCMPL = 149; + public static final int FCMPG = 150; + public static final int DCMPL = 151; + public static final int DCMPG = 152; + public static final int IFEQ = 153; + public static final int IFNE = 154; + public static final int IFLT = 155; + public static final int IFGE = 156; + public static final int IFGT = 157; + public static final int IFLE = 158; + public static final int IF_ICMPEQ = 159; + public static final int IF_ICMPNE = 160; + public static final int IF_ICMPLT = 161; + public static final int IF_ICMPGE = 162; + public static final int IF_ICMPGT = 163; + public static final int IF_ICMPLE = 164; + public static final int IF_ACMPEQ = 165; + public static final int IF_ACMPNE = 166; + public static final int GOTO = 167; + public static final int JSR = 168; + public static final int RET = 169; + public static final int TABLESWITCH = 170; + public static final int LOOKUPSWITCH = 171; + public static final int IRETURN = 172; + public static final int LRETURN = 173; + public static final int FRETURN = 174; + public static final int DRETURN = 175; + public static final int ARETURN = 176; + public static final int RETURN = 177; + public static final int GETSTATIC = 178; + public static final int PUTSTATIC = 179; + public static final int GETFIELD = 180; + public static final int PUTFIELD = 181; + public static final int INVOKEVIRTUAL = 182; + public static final int INVOKESPECIAL = 183; + public static final int INVOKENONVIRTUAL = 183; // Old name in JDK 1.0 + public static final int INVOKESTATIC = 184; + public static final int INVOKEINTERFACE = 185; + public static final int NEW = 187; + public static final int NEWARRAY = 188; + public static final int ANEWARRAY = 189; + public static final int ARRAYLENGTH = 190; + public static final int ATHROW = 191; + public static final int CHECKCAST = 192; + public static final int INSTANCEOF = 193; + public static final int MONITORENTER = 194; + public static final int MONITOREXIT = 195; + public static final int WIDE = 196; + public static final int MULTIANEWARRAY = 197; + public static final int IFNULL = 198; + public static final int IFNONNULL = 199; + public static final int GOTO_W = 200; + public static final int JSR_W = 201; + + /** + * Non-legal opcodes, may be used by JVM internally. + */ + public static final int BREAKPOINT = 202; + public static final int LDC_QUICK = 203; + public static final int LDC_W_QUICK = 204; + public static final int LDC2_W_QUICK = 205; + public static final int GETFIELD_QUICK = 206; + public static final int PUTFIELD_QUICK = 207; + public static final int GETFIELD2_QUICK = 208; + public static final int PUTFIELD2_QUICK = 209; + public static final int GETSTATIC_QUICK = 210; + public static final int PUTSTATIC_QUICK = 211; + public static final int GETSTATIC2_QUICK = 212; + public static final int PUTSTATIC2_QUICK = 213; + public static final int INVOKEVIRTUAL_QUICK = 214; + public static final int INVOKENONVIRTUAL_QUICK = 215; + public static final int INVOKESUPER_QUICK = 216; + public static final int INVOKESTATIC_QUICK = 217; + public static final int INVOKEINTERFACE_QUICK = 218; + public static final int INVOKEVIRTUALOBJECT_QUICK = 219; + public static final int NEW_QUICK = 221; + public static final int ANEWARRAY_QUICK = 222; + public static final int MULTIANEWARRAY_QUICK = 223; + public static final int CHECKCAST_QUICK = 224; + public static final int INSTANCEOF_QUICK = 225; + public static final int INVOKEVIRTUAL_QUICK_W = 226; + public static final int GETFIELD_QUICK_W = 227; + public static final int PUTFIELD_QUICK_W = 228; + public static final int IMPDEP1 = 254; + public static final int IMPDEP2 = 255; + + + // Extension for decompiler + public static final int ICONST = 256; + public static final int LCONST = 257; + public static final int FCONST = 258; + public static final int DCONST = 259; + public static final int IF = 260; + public static final int IFCMP = 261; + public static final int IFXNULL = 262; + public static final int DUPLOAD = 263; + public static final int DUPSTORE = 264; + public static final int ASSIGNMENT = 265; + public static final int UNARYOP = 266; + public static final int BINARYOP = 267; + public static final int LOAD = 268; + public static final int STORE = 269; + public static final int EXCEPTIONLOAD = 270; + public static final int ARRAYLOAD = 271; + public static final int ARRAYSTORE = 272; + public static final int XRETURN = 273; + public static final int INVOKENEW = 274; + public static final int CONVERT = 275; + public static final int IMPLICITCONVERT = 276; + public static final int PREINC = 277; + public static final int POSTINC = 278; + public static final int RETURNADDRESSLOAD = 279; + public static final int TERNARYOPSTORE = 280; + public static final int TERNARYOP = 281; + public static final int INITARRAY = 282; + public static final int NEWANDINITARRAY = 283; + public static final int COMPLEXIF = 284; + public static final int OUTERTHIS = 285; + public static final int ASSERT = 286; + + + public static final String[] OPCODE_NAMES = { + "nop", "aconst_null", "iconst_m1", "iconst_0", "iconst_1", + "iconst_2", "iconst_3", "iconst_4", "iconst_5", "lconst_0", + "lconst_1", "fconst_0", "fconst_1", "fconst_2", "dconst_0", + "dconst_1", "bipush", "sipush", "ldc", "ldc_w", "ldc2_w", "iload", + "lload", "fload", "dload", "aload", "iload_0", "iload_1", "iload_2", + "iload_3", "lload_0", "lload_1", "lload_2", "lload_3", "fload_0", + "fload_1", "fload_2", "fload_3", "dload_0", "dload_1", "dload_2", + "dload_3", "aload_0", "aload_1", "aload_2", "aload_3", "iaload", + "laload", "faload", "daload", "aaload", "baload", "caload", "saload", + "istore", "lstore", "fstore", "dstore", "astore", "istore_0", + "istore_1", "istore_2", "istore_3", "lstore_0", "lstore_1", + "lstore_2", "lstore_3", "fstore_0", "fstore_1", "fstore_2", + "fstore_3", "dstore_0", "dstore_1", "dstore_2", "dstore_3", + "astore_0", "astore_1", "astore_2", "astore_3", "iastore", "lastore", + "fastore", "dastore", "aastore", "bastore", "castore", "sastore", + "pop", "pop2", "dup", "dup_x1", "dup_x2", "dup2", "dup2_x1", + "dup2_x2", "swap", "iadd", "ladd", "fadd", "dadd", "isub", "lsub", + "fsub", "dsub", "imul", "lmul", "fmul", "dmul", "idiv", "ldiv", + "fdiv", "ddiv", "irem", "lrem", "frem", "drem", "ineg", "lneg", + "fneg", "dneg", "ishl", "lshl", "ishr", "lshr", "iushr", "lushr", + "iand", "land", "ior", "lor", "ixor", "lxor", "iinc", "i2l", "i2f", + "i2d", "l2i", "l2f", "l2d", "f2i", "f2l", "f2d", "d2i", "d2l", "d2f", + "i2b", "i2c", "i2s", "lcmp", "fcmpl", "fcmpg", + "dcmpl", "dcmpg", "ifeq", "ifne", "iflt", "ifge", "ifgt", "ifle", + "if_icmpeq", "if_icmpne", "if_icmplt", "if_icmpge", "if_icmpgt", + "if_icmple", "if_acmpeq", "if_acmpne", "goto", "jsr", "ret", + "tableswitch", "lookupswitch", "ireturn", "lreturn", "freturn", + "dreturn", "areturn", "return", "getstatic", "putstatic", "getfield", + "putfield", "invokevirtual", "invokespecial", "invokestatic", + "invokeinterface", ILLEGAL_OPCODE, "new", "newarray", "anewarray", + "arraylength", "athrow", "checkcast", "instanceof", "monitorenter", + "monitorexit", "wide", "multianewarray", "ifnull", "ifnonnull", + "goto_w", "jsr_w", "breakpoint", ILLEGAL_OPCODE, ILLEGAL_OPCODE, + ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, + ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, + ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, + ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, + ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, + ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, + ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, + ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, + ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, + ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, + ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, + ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, + ILLEGAL_OPCODE, "impdep1", "impdep2" + }; + + /** + * Number of byte code operands, i.e., number of bytes after the tag byte + * itself. + */ + public static final short[] NO_OF_OPERANDS = { + 0/*nop*/, 0/*aconst_null*/, 0/*iconst_m1*/, 0/*iconst_0*/, + 0/*iconst_1*/, 0/*iconst_2*/, 0/*iconst_3*/, 0/*iconst_4*/, + 0/*iconst_5*/, 0/*lconst_0*/, 0/*lconst_1*/, 0/*fconst_0*/, + 0/*fconst_1*/, 0/*fconst_2*/, 0/*dconst_0*/, 0/*dconst_1*/, + 1/*bipush*/, 2/*sipush*/, 1/*ldc*/, 2/*ldc_w*/, 2/*ldc2_w*/, + 1/*iload*/, 1/*lload*/, 1/*fload*/, 1/*dload*/, 1/*aload*/, + 0/*iload_0*/, 0/*iload_1*/, 0/*iload_2*/, 0/*iload_3*/, + 0/*lload_0*/, 0/*lload_1*/, 0/*lload_2*/, 0/*lload_3*/, + 0/*fload_0*/, 0/*fload_1*/, 0/*fload_2*/, 0/*fload_3*/, + 0/*dload_0*/, 0/*dload_1*/, 0/*dload_2*/, 0/*dload_3*/, + 0/*aload_0*/, 0/*aload_1*/, 0/*aload_2*/, 0/*aload_3*/, + 0/*iaload*/, 0/*laload*/, 0/*faload*/, 0/*daload*/, + 0/*aaload*/, 0/*baload*/, 0/*caload*/, 0/*saload*/, + 1/*istore*/, 1/*lstore*/, 1/*fstore*/, 1/*dstore*/, + 1/*astore*/, 0/*istore_0*/, 0/*istore_1*/, 0/*istore_2*/, + 0/*istore_3*/, 0/*lstore_0*/, 0/*lstore_1*/, 0/*lstore_2*/, + 0/*lstore_3*/, 0/*fstore_0*/, 0/*fstore_1*/, 0/*fstore_2*/, + 0/*fstore_3*/, 0/*dstore_0*/, 0/*dstore_1*/, 0/*dstore_2*/, + 0/*dstore_3*/, 0/*astore_0*/, 0/*astore_1*/, 0/*astore_2*/, + 0/*astore_3*/, 0/*iastore*/, 0/*lastore*/, 0/*fastore*/, + 0/*dastore*/, 0/*aastore*/, 0/*bastore*/, 0/*castore*/, + 0/*sastore*/, 0/*pop*/, 0/*pop2*/, 0/*dup*/, 0/*dup_x1*/, + 0/*dup_x2*/, 0/*dup2*/, 0/*dup2_x1*/, 0/*dup2_x2*/, 0/*swap*/, + 0/*iadd*/, 0/*ladd*/, 0/*fadd*/, 0/*dadd*/, 0/*isub*/, + 0/*lsub*/, 0/*fsub*/, 0/*dsub*/, 0/*imul*/, 0/*lmul*/, + 0/*fmul*/, 0/*dmul*/, 0/*idiv*/, 0/*ldiv*/, 0/*fdiv*/, + 0/*ddiv*/, 0/*irem*/, 0/*lrem*/, 0/*frem*/, 0/*drem*/, + 0/*ineg*/, 0/*lneg*/, 0/*fneg*/, 0/*dneg*/, 0/*ishl*/, + 0/*lshl*/, 0/*ishr*/, 0/*lshr*/, 0/*iushr*/, 0/*lushr*/, + 0/*iand*/, 0/*land*/, 0/*ior*/, 0/*lor*/, 0/*ixor*/, 0/*lxor*/, + 2/*iinc*/, 0/*i2l*/, 0/*i2f*/, 0/*i2d*/, 0/*l2i*/, 0/*l2f*/, + 0/*l2d*/, 0/*f2i*/, 0/*f2l*/, 0/*f2d*/, 0/*d2i*/, 0/*d2l*/, + 0/*d2f*/, 0/*i2b*/, 0/*i2c*/, 0/*i2s*/, 0/*lcmp*/, 0/*fcmpl*/, + 0/*fcmpg*/, 0/*dcmpl*/, 0/*dcmpg*/, 2/*ifeq*/, 2/*ifne*/, + 2/*iflt*/, 2/*ifge*/, 2/*ifgt*/, 2/*ifle*/, 2/*if_icmpeq*/, + 2/*if_icmpne*/, 2/*if_icmplt*/, 2/*if_icmpge*/, 2/*if_icmpgt*/, + 2/*if_icmple*/, 2/*if_acmpeq*/, 2/*if_acmpne*/, 2/*goto*/, + 2/*jsr*/, 1/*ret*/, NO_OF_OPERANDS_UNPREDICTABLE/*tableswitch*/, NO_OF_OPERANDS_UNPREDICTABLE/*lookupswitch*/, + 0/*ireturn*/, 0/*lreturn*/, 0/*freturn*/, + 0/*dreturn*/, 0/*areturn*/, 0/*return*/, + 2/*getstatic*/, 2/*putstatic*/, 2/*getfield*/, + 2/*putfield*/, 2/*invokevirtual*/, 2/*invokespecial*/, 2/*invokestatic*/, + 4/*invokeinterface*/, NO_OF_OPERANDS_UNDEFINED, 2/*new*/, + 1/*newarray*/, 2/*anewarray*/, + 0/*arraylength*/, 0/*athrow*/, 2/*checkcast*/, + 2/*instanceof*/, 0/*monitorenter*/, + 0/*monitorexit*/, NO_OF_OPERANDS_UNPREDICTABLE/*wide*/, 3/*multianewarray*/, + 2/*ifnull*/, 2/*ifnonnull*/, 4/*goto_w*/, + 4/*jsr_w*/, 0/*breakpoint*/, NO_OF_OPERANDS_UNDEFINED, + NO_OF_OPERANDS_UNDEFINED, NO_OF_OPERANDS_UNDEFINED, + NO_OF_OPERANDS_UNDEFINED, NO_OF_OPERANDS_UNDEFINED, + NO_OF_OPERANDS_UNDEFINED, NO_OF_OPERANDS_UNDEFINED, + NO_OF_OPERANDS_UNDEFINED, NO_OF_OPERANDS_UNDEFINED, + NO_OF_OPERANDS_UNDEFINED, NO_OF_OPERANDS_UNDEFINED, + NO_OF_OPERANDS_UNDEFINED, NO_OF_OPERANDS_UNDEFINED, + NO_OF_OPERANDS_UNDEFINED, NO_OF_OPERANDS_UNDEFINED, + NO_OF_OPERANDS_UNDEFINED, NO_OF_OPERANDS_UNDEFINED, + NO_OF_OPERANDS_UNDEFINED, NO_OF_OPERANDS_UNDEFINED, + NO_OF_OPERANDS_UNDEFINED, NO_OF_OPERANDS_UNDEFINED, + NO_OF_OPERANDS_UNDEFINED, NO_OF_OPERANDS_UNDEFINED, + NO_OF_OPERANDS_UNDEFINED, NO_OF_OPERANDS_UNDEFINED, + NO_OF_OPERANDS_UNDEFINED, NO_OF_OPERANDS_UNDEFINED, + NO_OF_OPERANDS_UNDEFINED, NO_OF_OPERANDS_UNDEFINED, + NO_OF_OPERANDS_UNDEFINED, NO_OF_OPERANDS_UNDEFINED, + NO_OF_OPERANDS_UNDEFINED, NO_OF_OPERANDS_UNDEFINED, + NO_OF_OPERANDS_UNDEFINED, NO_OF_OPERANDS_UNDEFINED, + NO_OF_OPERANDS_UNDEFINED, NO_OF_OPERANDS_UNDEFINED, + NO_OF_OPERANDS_UNDEFINED, NO_OF_OPERANDS_UNDEFINED, + NO_OF_OPERANDS_UNDEFINED, NO_OF_OPERANDS_UNDEFINED, + NO_OF_OPERANDS_UNDEFINED, NO_OF_OPERANDS_UNDEFINED, + NO_OF_OPERANDS_UNDEFINED, NO_OF_OPERANDS_UNDEFINED, + NO_OF_OPERANDS_UNDEFINED, NO_OF_OPERANDS_UNDEFINED, + NO_OF_OPERANDS_UNDEFINED, NO_OF_OPERANDS_UNDEFINED, + NO_OF_OPERANDS_UNDEFINED, NO_OF_OPERANDS_UNDEFINED, + NO_OF_OPERANDS_RESERVED/*impdep1*/, NO_OF_OPERANDS_RESERVED/*impdep2*/ + }; + + + public static final int CMP_MAX_INDEX = 7; + + public static final int CMP_EQ = 0; + public static final int CMP_LT = 1; + public static final int CMP_GT = 2; + public static final int CMP_UEQ = 3; + public static final int CMP_UNE = 4; + public static final int CMP_LE = 5; + public static final int CMP_GE = 6; + public static final int CMP_NE = 7; + + public static final String[] CMP_NAMES = { + "==", "<", ">", "", "!", "<=", ">=", "!=" }; + + + public static final byte T_BOOLEAN = 4; + public static final byte T_CHAR = 5; + public static final byte T_FLOAT = 6; + public static final byte T_DOUBLE = 7; + public static final byte T_BYTE = 8; + public static final byte T_SHORT = 9; + public static final byte T_INT = 10; + public static final byte T_LONG = 11; + + public static final byte T_VOID = 12; // Non-standard + public static final byte T_ARRAY = 13; + public static final byte T_OBJECT = 14; + public static final byte T_REFERENCE = 14; // Deprecated + public static final byte T_UNKNOWN = 15; + public static final byte T_ADDRESS = 16; + + /** The primitive type names corresponding to the T_XX constants, + * e.g., TYPE_NAMES[T_INT] = "int" + */ + public static final String[] TYPE_NAMES = { + ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, + "boolean", "char", "float", "double", "byte", "short", "int", "long", + "void", "array", "object", "unknown" // Non-standard + }; + + /** + * Types Bit Fields + */ + public static final byte TBF_INT_CHAR = 1; + public static final byte TBF_INT_BYTE = 2; + public static final byte TBF_INT_SHORT = 4; + public static final byte TBF_INT_INT = 8; + public static final byte TBF_INT_BOOLEAN = 16; + + /** + * Binary operator constants + */ + public static final int CMP_AND = 0; + public static final int CMP_NONE = 1; + public static final int CMP_OR = 2; +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/AALoad.java b/src/jd/core/model/instruction/bytecode/instruction/AALoad.java new file mode 100644 index 00000000..bf0c95a5 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/AALoad.java @@ -0,0 +1,28 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; + + +public class AALoad extends ArrayLoadInstruction +{ + public AALoad( + int opcode, int offset, int lineNumber, + Instruction arrayref, Instruction indexref) + { + super(opcode, offset, lineNumber, arrayref, indexref, null); + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + String signature = + this.arrayref.getReturnedSignature(constants, localVariables); + + if ((signature == null) || (signature.length() == 0) || + (signature.charAt(0) != '[')) + return null; + + return signature.substring(1); + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/AAStore.java b/src/jd/core/model/instruction/bytecode/instruction/AAStore.java new file mode 100644 index 00000000..41072cc4 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/AAStore.java @@ -0,0 +1,27 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; + +public class AAStore extends ArrayStoreInstruction +{ + public AAStore( + int opcode, int offset, int lineNumber, Instruction arrayref, + Instruction indexref, Instruction objectref) + { + super(opcode, offset, lineNumber, arrayref, indexref, null, objectref); + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + String signature = + this.arrayref.getReturnedSignature(constants, localVariables); + + if ((signature == null) || (signature.length() == 0) || + (signature.charAt(0) != '[')) + return null; + + return signature.substring(1); + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/AConstNull.java b/src/jd/core/model/instruction/bytecode/instruction/AConstNull.java new file mode 100644 index 00000000..de0e8a38 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/AConstNull.java @@ -0,0 +1,18 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; + +public class AConstNull extends Instruction +{ + public AConstNull(int opcode, int offset, int lineNumber) + { + super(opcode, offset, lineNumber); + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + return null; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/ALoad.java b/src/jd/core/model/instruction/bytecode/instruction/ALoad.java new file mode 100644 index 00000000..ee3daf3c --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/ALoad.java @@ -0,0 +1,28 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariable; +import jd.core.model.classfile.LocalVariables; +import jd.core.util.StringConstants; + +public class ALoad extends LoadInstruction +{ + public ALoad(int opcode, int offset, int lineNumber, int index) + { + super(opcode, offset, lineNumber, index, null); + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + if ((constants == null) || (localVariables == null)) + return null; + + LocalVariable lv = localVariables.getLocalVariableWithIndexAndOffset(this.index, this.offset); + + if ((lv != null) && (lv.signature_index > 0)) + return constants.getConstantUtf8(lv.signature_index); + + return StringConstants.INTERNAL_OBJECT_SIGNATURE; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/ANewArray.java b/src/jd/core/model/instruction/bytecode/instruction/ANewArray.java new file mode 100644 index 00000000..39dab706 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/ANewArray.java @@ -0,0 +1,39 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; + +public class ANewArray extends IndexInstruction +{ + public Instruction dimension; + + public ANewArray( + int opcode, int offset, int lineNumber, + int index, Instruction dimension) + { + super(opcode, offset, lineNumber, index); + this.dimension = dimension; + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + if (constants == null) + return null; + + String str = constants.getConstantClassName(this.index); + + if (str.length() == 0) + { + return null; + } + else if (str.charAt(0) == '[') + { + return "[" + constants.getConstantClassName(this.index); + } + else + { + return "[L" + constants.getConstantClassName(this.index) + ';'; + } + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/AStore.java b/src/jd/core/model/instruction/bytecode/instruction/AStore.java new file mode 100644 index 00000000..8d7ef0a7 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/AStore.java @@ -0,0 +1,20 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; + +public class AStore extends StoreInstruction +{ + public AStore( + int opcode, int offset, int lineNumber, + int index, Instruction objectref) + { + super(opcode, offset, lineNumber, index, null, objectref); + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + return this.valueref.getReturnedSignature(constants, localVariables); + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/AThrow.java b/src/jd/core/model/instruction/bytecode/instruction/AThrow.java new file mode 100644 index 00000000..46c61590 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/AThrow.java @@ -0,0 +1,23 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; + + +public class AThrow extends Instruction +{ + public Instruction value; + + public AThrow( + int opcode, int offset, int lineNumber, Instruction value) + { + super(opcode, offset, lineNumber); + this.value = value; + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + return this.value.getReturnedSignature(constants, localVariables); + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/ArrayInstruction.java b/src/jd/core/model/instruction/bytecode/instruction/ArrayInstruction.java new file mode 100644 index 00000000..03626807 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/ArrayInstruction.java @@ -0,0 +1,14 @@ +package jd.core.model.instruction.bytecode.instruction; + + +public abstract class ArrayInstruction extends Instruction +{ + public Instruction arrayref; + + public ArrayInstruction( + int opcode, int offset, int lineNumber, Instruction arrayref) + { + super(opcode, offset, lineNumber); + this.arrayref = arrayref; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/ArrayLength.java b/src/jd/core/model/instruction/bytecode/instruction/ArrayLength.java new file mode 100644 index 00000000..e07faf9e --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/ArrayLength.java @@ -0,0 +1,20 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; + + +public class ArrayLength extends ArrayInstruction +{ + public ArrayLength( + int opcode, int offset, int lineNumber, Instruction arrayref) + { + super(opcode, offset, lineNumber, arrayref); + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + return "I"; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/ArrayLoadInstruction.java b/src/jd/core/model/instruction/bytecode/instruction/ArrayLoadInstruction.java new file mode 100644 index 00000000..53bca1b9 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/ArrayLoadInstruction.java @@ -0,0 +1,26 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; + + +public class ArrayLoadInstruction extends ArrayInstruction +{ + public String signature; + public Instruction indexref; + + public ArrayLoadInstruction( + int opcode, int offset, int lineNumber, Instruction arrayref, + Instruction indexref, String signature) + { + super(opcode, offset, lineNumber, arrayref); + this.indexref = indexref; + this.signature = signature; + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + return this.signature; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/ArrayStoreInstruction.java b/src/jd/core/model/instruction/bytecode/instruction/ArrayStoreInstruction.java new file mode 100644 index 00000000..05627a68 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/ArrayStoreInstruction.java @@ -0,0 +1,28 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.instruction.bytecode.instruction.attribute.ValuerefAttribute; + + +public class ArrayStoreInstruction + extends ArrayLoadInstruction implements ValuerefAttribute +{ + public Instruction valueref; + + public ArrayStoreInstruction( + int opcode, int offset, int lineNumber, Instruction arrayref, + Instruction indexref, String signature, Instruction valueref) + { + super(opcode, offset, lineNumber, arrayref, indexref, signature); + this.valueref = valueref; + } + + public Instruction getValueref() + { + return this.valueref; + } + + public void setValueref(Instruction valueref) + { + this.valueref = valueref; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/AssertInstruction.java b/src/jd/core/model/instruction/bytecode/instruction/AssertInstruction.java new file mode 100644 index 00000000..39588eb8 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/AssertInstruction.java @@ -0,0 +1,26 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; + + +public class AssertInstruction extends Instruction +{ + public Instruction test; + public Instruction msg; + + public AssertInstruction( + int opcode, int offset, int lineNumber, + Instruction test, Instruction msg) + { + super(opcode, offset, lineNumber); + this.test = test; + this.msg = msg; + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + return null; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/AssignmentInstruction.java b/src/jd/core/model/instruction/bytecode/instruction/AssignmentInstruction.java new file mode 100644 index 00000000..088ab24e --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/AssignmentInstruction.java @@ -0,0 +1,23 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; + + +public class AssignmentInstruction extends BinaryOperatorInstruction +{ + public AssignmentInstruction( + int opcode, int offset, int lineNumber, int priority, String operator, + Instruction value1, Instruction value2) + { + super( + opcode, offset, lineNumber, priority, + null, operator, value1, value2); + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + return this.value2.getReturnedSignature(constants, localVariables); + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/BIPush.java b/src/jd/core/model/instruction/bytecode/instruction/BIPush.java new file mode 100644 index 00000000..c7ec64da --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/BIPush.java @@ -0,0 +1,10 @@ +package jd.core.model.instruction.bytecode.instruction; + + +public class BIPush extends IConst +{ + public BIPush(int opcode, int offset, int lineNumber, int value) + { + super(opcode, offset, lineNumber, value); + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/BinaryOperatorInstruction.java b/src/jd/core/model/instruction/bytecode/instruction/BinaryOperatorInstruction.java new file mode 100644 index 00000000..684a350f --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/BinaryOperatorInstruction.java @@ -0,0 +1,77 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; + +/* Priority Operator Operation Order of Evaluation + * 1 [ ] Array index Left to Right + * () Method call + * . Member access + * 2 ++ Prefix or postfix increment Right to Left + * -- Prefix or postfix decrement + * + - Unary plus, minus + * ~ Bitwise NOT + * ! Boolean (logical) NOT + * (type) Type cast + * new Object creation + * 3 * / % Multiplication, division, remainder Left to Right + * 4 + - Addition, subtraction Left to Right + * + String concatenation + * 5 << Signed bit shift left to right Left to Right + * >> Signed bit shift right to left + * >>> Unsigned bit shift right to left + * 6 < <= Less than, less than or equal to Left to Right + * > >= Greater than, greater than or equal to + * instanceof Reference test + * 7 == Equal to Left to Right + * != Not equal to + * 8 & Bitwise AND Left to Right + * & Boolean (logical) AND + * 9 ^ Bitwise XOR Left to Right + * ^ Boolean (logical) XOR + * 10 | Bitwise OR Left to Right + * | Boolean (logical) OR + * 11 && Boolean (logical) AND Left to Right + * 12 || Boolean (logical) OR Left to Right + * 13 ? : Conditional Right to Left + * 14 = Assignment Right to Left + * *= /= += Combinated assignment + * -= %= (operation and assignment) + * <<= >>= + * >>>= + * &= ^= |= + * + * http://www.java-tips.org/java-se-tips/java.lang/what-is-java-operator-precedence.html + */ +public class BinaryOperatorInstruction extends Instruction +{ + private int priority; + public String signature; + public String operator; + public Instruction value1; + public Instruction value2; + + public BinaryOperatorInstruction( + int opcode, int offset, int lineNumber, int priority, + String signature, String operator, + Instruction value1, Instruction value2) + { + super(opcode, offset, lineNumber); + this.priority = priority; + this.signature = signature; + this.operator = operator; + this.value1 = value1; + this.value2 = value2; + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + return this.signature; + } + + public int getPriority() + { + return this.priority; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/BranchInstruction.java b/src/jd/core/model/instruction/bytecode/instruction/BranchInstruction.java new file mode 100644 index 00000000..630f1d5a --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/BranchInstruction.java @@ -0,0 +1,23 @@ +package jd.core.model.instruction.bytecode.instruction; + + +public abstract class BranchInstruction extends Instruction +{ + public int branch; + + public BranchInstruction(int opcode, int offset, int lineNumber, int branch) + { + super(opcode, offset, lineNumber); + this.branch = branch; + } + + public int GetJumpOffset() + { + return this.offset + this.branch; + } + + public void SetJumpOffset(int jumpOffset) + { + this.branch = jumpOffset - this.offset; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/CheckCast.java b/src/jd/core/model/instruction/bytecode/instruction/CheckCast.java new file mode 100644 index 00000000..3df90dca --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/CheckCast.java @@ -0,0 +1,51 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; +import jd.core.model.classfile.constant.Constant; +import jd.core.model.classfile.constant.ConstantClass; +import jd.core.model.classfile.constant.ConstantConstant; +import jd.core.model.classfile.constant.ConstantUtf8; +import jd.core.util.SignatureUtil; + + +public class CheckCast extends IndexInstruction +{ + public Instruction objectref; + + public CheckCast( + int opcode, int offset, int lineNumber, + int index, Instruction objectref) + { + super(opcode, offset, lineNumber, index); + this.objectref = objectref; + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + if (constants == null) + return null; + + Constant c = constants.get(this.index); + + if (c.tag == ConstantConstant.CONSTANT_Utf8) + { + ConstantUtf8 cutf8 = (ConstantUtf8)c; + return cutf8.bytes; + } + else + { + ConstantClass cc = (ConstantClass)c; + String signature = constants.getConstantUtf8(cc.name_index); + if (signature.charAt(0) != '[') + signature = SignatureUtil.CreateTypeName(signature); + return signature; + } + } + + public int getPriority() + { + return 2; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/ComplexConditionalBranchInstruction.java b/src/jd/core/model/instruction/bytecode/instruction/ComplexConditionalBranchInstruction.java new file mode 100644 index 00000000..81932923 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/ComplexConditionalBranchInstruction.java @@ -0,0 +1,32 @@ +package jd.core.model.instruction.bytecode.instruction; + +import java.util.List; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; +import jd.core.model.instruction.fast.FastConstants; + + +public class ComplexConditionalBranchInstruction extends ConditionalBranchInstruction +{ + public List instructions; + + public ComplexConditionalBranchInstruction( + int opcode, int offset, int lineNumber, int cmp, + List instructions, int branch) + { + super(opcode, offset, lineNumber, cmp, branch); + this.instructions = instructions; + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + return null; + } + + public int getPriority() + { + return (this.cmp == FastConstants.CMP_AND) ? 12 : 13; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/ConditionalBranchInstruction.java b/src/jd/core/model/instruction/bytecode/instruction/ConditionalBranchInstruction.java new file mode 100644 index 00000000..a782a624 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/ConditionalBranchInstruction.java @@ -0,0 +1,23 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; + + +public class ConditionalBranchInstruction extends BranchInstruction +{ + public int cmp; + + public ConditionalBranchInstruction( + int opcode, int offset, int lineNumber, int cmp, int branch) + { + super(opcode, offset, lineNumber, branch); + this.cmp = cmp; + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + return "Z"; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/ConstInstruction.java b/src/jd/core/model/instruction/bytecode/instruction/ConstInstruction.java new file mode 100644 index 00000000..4063211b --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/ConstInstruction.java @@ -0,0 +1,14 @@ +package jd.core.model.instruction.bytecode.instruction; + + + +public abstract class ConstInstruction extends Instruction +{ + public int value; + + public ConstInstruction(int opcode, int offset, int lineNumber, int value) + { + super(opcode, offset, lineNumber); + this.value = value; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/ConvertInstruction.java b/src/jd/core/model/instruction/bytecode/instruction/ConvertInstruction.java new file mode 100644 index 00000000..99145db6 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/ConvertInstruction.java @@ -0,0 +1,30 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; + + +public class ConvertInstruction extends Instruction +{ + final public String signature; + public Instruction value; + + public ConvertInstruction( + int opcode, int offset, int lineNumber, Instruction value, String signature) + { + super(opcode, offset, lineNumber); + this.value = value; + this.signature = signature; + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + return this.signature; + } + + public int getPriority() + { + return 2; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/DConst.java b/src/jd/core/model/instruction/bytecode/instruction/DConst.java new file mode 100644 index 00000000..538f1d06 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/DConst.java @@ -0,0 +1,18 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; + +public class DConst extends ConstInstruction +{ + public DConst(int opcode, int offset, int lineNumber, int value) + { + super(opcode, offset, lineNumber, value); + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + return "D"; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/DupLoad.java b/src/jd/core/model/instruction/bytecode/instruction/DupLoad.java new file mode 100644 index 00000000..71306daa --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/DupLoad.java @@ -0,0 +1,24 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; + +public class DupLoad extends Instruction +{ + public DupStore dupStore; + + public DupLoad(int opcode, int offset, int lineNumber, DupStore dupStore) + { + super(opcode, offset, lineNumber); + this.dupStore = dupStore; + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + if (dupStore == null) + throw new RuntimeException("DupLoad without DupStore"); + + return dupStore.getReturnedSignature(constants, localVariables); + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/DupStore.java b/src/jd/core/model/instruction/bytecode/instruction/DupStore.java new file mode 100644 index 00000000..11335e5f --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/DupStore.java @@ -0,0 +1,39 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; +import jd.core.model.instruction.bytecode.ByteCodeConstants; + +public class DupStore extends Instruction +{ + public Instruction objectref; + public DupLoad dupLoad1; + public DupLoad dupLoad2; + + public DupStore( + int opcode, int offset, int lineNumber, Instruction objectref) + { + super(opcode, offset, lineNumber); + this.objectref = objectref; + this.dupLoad1 = new DupLoad( + ByteCodeConstants.DUPLOAD, offset, lineNumber, this); + this.dupLoad2 = new DupLoad( + ByteCodeConstants.DUPLOAD, offset, lineNumber, this); + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + return this.objectref.getReturnedSignature(constants, localVariables); + } + + public DupLoad getDupLoad1() + { + return dupLoad1; + } + + public DupLoad getDupLoad2() + { + return dupLoad2; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/ExceptionLoad.java b/src/jd/core/model/instruction/bytecode/instruction/ExceptionLoad.java new file mode 100644 index 00000000..01dd1b4f --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/ExceptionLoad.java @@ -0,0 +1,26 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; +import jd.core.util.UtilConstants; + +public class ExceptionLoad extends IndexInstruction +{ + final public int exceptionNameIndex; + + public ExceptionLoad( + int opcode, int offset, int lineNumber, int signatureIndex) + { + super(opcode, offset, lineNumber, UtilConstants.INVALID_INDEX); + this.exceptionNameIndex = signatureIndex; + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + if ((constants == null) || (this.exceptionNameIndex == 0)) + return null; + + return constants.getConstantUtf8(this.exceptionNameIndex); + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/FConst.java b/src/jd/core/model/instruction/bytecode/instruction/FConst.java new file mode 100644 index 00000000..bcace3c0 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/FConst.java @@ -0,0 +1,18 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; + +public class FConst extends ConstInstruction +{ + public FConst(int opcode, int offset, int lineNumber, int value) + { + super(opcode, offset, lineNumber, value); + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + return "F"; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/GetField.java b/src/jd/core/model/instruction/bytecode/instruction/GetField.java new file mode 100644 index 00000000..59862340 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/GetField.java @@ -0,0 +1,37 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; +import jd.core.model.classfile.constant.ConstantFieldref; +import jd.core.model.classfile.constant.ConstantNameAndType; + +public class GetField extends IndexInstruction +{ + public Instruction objectref; + + public GetField( + int opcode, int offset, int lineNumber, + int index, Instruction objectref) + { + super(opcode, offset, lineNumber, index); + this.objectref = objectref; + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + if (constants == null) + return null; + + ConstantFieldref cfr = constants.getConstantFieldref(this.index); + if (cfr == null) + return null; + + ConstantNameAndType cnat = + constants.getConstantNameAndType(cfr.name_and_type_index); + if (cnat == null) + return null; + + return constants.getConstantUtf8(cnat.descriptor_index); + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/GetStatic.java b/src/jd/core/model/instruction/bytecode/instruction/GetStatic.java new file mode 100644 index 00000000..1c87cb4f --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/GetStatic.java @@ -0,0 +1,32 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; +import jd.core.model.classfile.constant.ConstantFieldref; +import jd.core.model.classfile.constant.ConstantNameAndType; + +public class GetStatic extends IndexInstruction +{ + public GetStatic(int opcode, int offset, int lineNumber, int index) + { + super(opcode, offset, lineNumber, index); + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + if (constants == null) + return null; + + ConstantFieldref cfr = constants.getConstantFieldref(this.index); + if (cfr == null) + return null; + + ConstantNameAndType cnat = + constants.getConstantNameAndType(cfr.name_and_type_index); + if (cnat == null) + return null; + + return constants.getConstantUtf8(cnat.descriptor_index); + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/Goto.java b/src/jd/core/model/instruction/bytecode/instruction/Goto.java new file mode 100644 index 00000000..c9bc1f2d --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/Goto.java @@ -0,0 +1,18 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; + +public class Goto extends BranchInstruction +{ + public Goto(int opcode, int offset, int lineNumber, int branch) + { + super(opcode, offset, lineNumber, branch); + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + return null; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/IBinaryOperatorInstruction.java b/src/jd/core/model/instruction/bytecode/instruction/IBinaryOperatorInstruction.java new file mode 100644 index 00000000..89ac399b --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/IBinaryOperatorInstruction.java @@ -0,0 +1,40 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; +import jd.core.model.instruction.bytecode.ByteCodeConstants; + + +public class IBinaryOperatorInstruction extends BinaryOperatorInstruction +{ + public IBinaryOperatorInstruction( + int opcode, int offset, int lineNumber, int priority, + String operator, Instruction value1, Instruction value2) + { + super( + opcode, offset, lineNumber, priority, + null, operator, value1, value2); + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + String signature; + + switch (this.value1.opcode) + { + case ByteCodeConstants.ICONST: + case ByteCodeConstants.BIPUSH: + case ByteCodeConstants.SIPUSH: + signature = this.value2.getReturnedSignature(constants, localVariables); + if (signature == null) + signature = this.value1.getReturnedSignature(constants, localVariables); + return signature; + default: + signature = this.value1.getReturnedSignature(constants, localVariables); + if (signature == null) + signature = this.value2.getReturnedSignature(constants, localVariables); + return signature; + } + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/IConst.java b/src/jd/core/model/instruction/bytecode/instruction/IConst.java new file mode 100644 index 00000000..ea94834e --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/IConst.java @@ -0,0 +1,65 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; + +/** + * Pseudo type 'X' correspond � char, byte, short ou int ... + */ +public class IConst extends ConstInstruction +{ + public String signature; + + public IConst(int opcode, int offset, int lineNumber, int value) + { + super(opcode, offset, lineNumber, value); + + /* Definition de la signature: + * 'X' si TBF_INT_INT|TBF_INT_SHORT|TBF_INT_BYTE|TBF_INT_CHAR|TBF_INT_BOOLEAN est possible + * 'Y' si TBF_INT_INT|TBF_INT_SHORT|TBF_INT_BYTE|TBF_INT_CHAR est possible + * 'C' si TBF_INT_INT|TBF_INT_SHORT|TBF_INT_CHAR est possible + * 'B' si TBF_INT_INT|TBF_INT_SHORT|TBF_INT_BYTE est possible + * 'S' si TBF_INT_INT|TBF_INT_SHORT est possible + * 'I' si TBF_INT_INT est possible + */ + + if (value < 0) + { + if (value >= Byte.MIN_VALUE) + this.signature = "B"; + else if (value >= Short.MIN_VALUE) + this.signature = "S"; + else + this.signature = "I"; + } + else + { + if (value <= 1) + this.signature = "X"; + else if (value <= Byte.MAX_VALUE) + this.signature = "Y"; + else if (value <= Character.MAX_VALUE) + this.signature = "C"; + else if (value <= Short.MAX_VALUE) + this.signature = "S"; + else + this.signature = "I"; + } + } + + public String getSignature() + { + return signature; + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + return this.signature; + } + + public void setReturnedSignature(String signature) + { + this.signature = signature; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/IInc.java b/src/jd/core/model/instruction/bytecode/instruction/IInc.java new file mode 100644 index 00000000..98a8e880 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/IInc.java @@ -0,0 +1,39 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariable; +import jd.core.model.classfile.LocalVariables; + +public class IInc extends IndexInstruction +{ + public int count; + + public IInc(int opcode, int offset, int lineNumber, int index, int count) + { + super(opcode, offset, lineNumber, index); + this.count = count; + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + if ((constants == null) || (localVariables == null)) + return null; + + LocalVariable lv = localVariables.getLocalVariableWithIndexAndOffset(this.index, this.offset); + + if ((lv == null) || (lv.signature_index <= 0)) + return null; + + return constants.getConstantUtf8(lv.signature_index); + } + + public int getPriority() + { + if ((this.count == 1) || (this.count == -1)) + // Operator '++' or '--' + return 2; + // Operator '+=' or '-=' + return 14; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/ILoad.java b/src/jd/core/model/instruction/bytecode/instruction/ILoad.java new file mode 100644 index 00000000..baf8f7bd --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/ILoad.java @@ -0,0 +1,27 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariable; +import jd.core.model.classfile.LocalVariables; + +public class ILoad extends LoadInstruction +{ + public ILoad(int opcode, int offset, int lineNumber, int index) + { + super(opcode, offset, lineNumber, index, null); + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + if ((constants == null) || (localVariables == null)) + return null; + + LocalVariable lv = localVariables.getLocalVariableWithIndexAndOffset(this.index, this.offset); + + if ((lv == null) || (lv.signature_index < 0)) + return null; + + return constants.getConstantUtf8(lv.signature_index); + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/IStore.java b/src/jd/core/model/instruction/bytecode/instruction/IStore.java new file mode 100644 index 00000000..7dd72e96 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/IStore.java @@ -0,0 +1,20 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; + +public class IStore extends StoreInstruction +{ + public IStore( + int opcode, int offset, int lineNumber, + int index, Instruction objectref) + { + super(opcode, offset, lineNumber, index, null, objectref); + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + return this.valueref.getReturnedSignature(constants, localVariables); + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/IfCmp.java b/src/jd/core/model/instruction/bytecode/instruction/IfCmp.java new file mode 100644 index 00000000..2a8d64ea --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/IfCmp.java @@ -0,0 +1,31 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.instruction.bytecode.ByteCodeConstants; + + +public class IfCmp extends ConditionalBranchInstruction +{ + public Instruction value1; + public Instruction value2; + + public IfCmp( + int opcode, int offset, int lineNumber, int cmp, + Instruction value1, Instruction value2, int branch) + { + super(opcode, offset, lineNumber, cmp, branch); + this.value1 = value1; + this.value2 = value2; + } + + public int getPriority() + { + switch (this.cmp) + { + case ByteCodeConstants.CMP_EQ: + case ByteCodeConstants.CMP_NE: + return 7; + default: + return 6; + } + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/IfInstruction.java b/src/jd/core/model/instruction/bytecode/instruction/IfInstruction.java new file mode 100644 index 00000000..4e7ca3b5 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/IfInstruction.java @@ -0,0 +1,29 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.instruction.bytecode.ByteCodeConstants; + + +public class IfInstruction extends ConditionalBranchInstruction +{ + public Instruction value; + + public IfInstruction( + int opcode, int offset, int lineNumber, + int cmp, Instruction value, int branch) + { + super(opcode, offset, lineNumber, cmp, branch); + this.value = value; + } + + public int getPriority() + { + switch (this.cmp) + { + case ByteCodeConstants.CMP_EQ: + case ByteCodeConstants.CMP_NE: + return 7; + default: + return 6; + } + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/ImplicitConvertInstruction.java b/src/jd/core/model/instruction/bytecode/instruction/ImplicitConvertInstruction.java new file mode 100644 index 00000000..2563f223 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/ImplicitConvertInstruction.java @@ -0,0 +1,18 @@ +package jd.core.model.instruction.bytecode.instruction; + + + +public class ImplicitConvertInstruction extends ConvertInstruction +{ + public ImplicitConvertInstruction( + int opcode, int offset, int lineNumber, + Instruction value, String signature) + { + super(opcode, offset, lineNumber, value, signature); + } + + public int getPriority() + { + return this.value.getPriority(); + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/IncInstruction.java b/src/jd/core/model/instruction/bytecode/instruction/IncInstruction.java new file mode 100644 index 00000000..bf094b96 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/IncInstruction.java @@ -0,0 +1,34 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; + +public class IncInstruction extends Instruction +{ + public Instruction value; + public int count; + + public IncInstruction( + int opcode, int offset, int lineNumber, Instruction value, int count) + { + super(opcode, offset, lineNumber); + this.value = value; + this.count = count; + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + return (this.value == null) ? null : + this.value.getReturnedSignature(constants, localVariables); + } + + public int getPriority() + { + if ((this.count == 1) || (this.count == -1)) + // Operator '++' or '--' + return 2; + // Operator '+=' or '-=' + return 14; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/IndexInstruction.java b/src/jd/core/model/instruction/bytecode/instruction/IndexInstruction.java new file mode 100644 index 00000000..386f6d91 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/IndexInstruction.java @@ -0,0 +1,14 @@ +package jd.core.model.instruction.bytecode.instruction; + + + +public abstract class IndexInstruction extends Instruction +{ + public int index; + + public IndexInstruction(int opcode, int offset, int lineNumber, int index) + { + super(opcode, offset, lineNumber); + this.index = index; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/InitArrayInstruction.java b/src/jd/core/model/instruction/bytecode/instruction/InitArrayInstruction.java new file mode 100644 index 00000000..b4ac6f62 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/InitArrayInstruction.java @@ -0,0 +1,28 @@ +package jd.core.model.instruction.bytecode.instruction; + +import java.util.List; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; + + +public class InitArrayInstruction extends Instruction +{ + public Instruction newArray; + public List values; + + public InitArrayInstruction( + int opcode, int offset, int lineNumber, + Instruction newArray, List values) + { + super(opcode, offset, lineNumber); + this.newArray = newArray; + this.values = values; + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + return this.newArray.getReturnedSignature(constants, localVariables); + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/InstanceOf.java b/src/jd/core/model/instruction/bytecode/instruction/InstanceOf.java new file mode 100644 index 00000000..79c02550 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/InstanceOf.java @@ -0,0 +1,29 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; + + +public class InstanceOf extends IndexInstruction +{ + public Instruction objectref; + + public InstanceOf( + int opcode, int offset, int lineNumber, + int index, Instruction objectref) + { + super(opcode, offset, lineNumber, index); + this.objectref = objectref; + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + return "Z"; + } + + public int getPriority() + { + return 6; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/Instruction.java b/src/jd/core/model/instruction/bytecode/instruction/Instruction.java new file mode 100644 index 00000000..3bedb6c0 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/Instruction.java @@ -0,0 +1,28 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; + +public abstract class Instruction +{ + public static int UNKNOWN_LINE_NUMBER = 0; + + public int opcode; + public int offset; + public int lineNumber; + + public Instruction(int opcode, int offset, int lineNumber) + { + this.opcode = opcode; + this.offset = offset; + this.lineNumber = lineNumber; + } + + public abstract String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables); + + public int getPriority() + { + return 0; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/InvokeInstruction.java b/src/jd/core/model/instruction/bytecode/instruction/InvokeInstruction.java new file mode 100644 index 00000000..b006640a --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/InvokeInstruction.java @@ -0,0 +1,42 @@ +package jd.core.model.instruction.bytecode.instruction; + +import java.util.List; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; +import jd.core.model.classfile.constant.ConstantMethodref; + + +public abstract class InvokeInstruction extends IndexInstruction +{ + public List args; + + public InvokeInstruction( + int opcode, int offset, int lineNumber, + int index, List args) + { + super(opcode, offset, lineNumber, index); + this.args = args; + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + if (constants == null) + return null; + + ConstantMethodref cmr = constants.getConstantMethodref(this.index); + + return cmr.getReturnedSignature(); + } + + public List getListOfParameterSignatures(ConstantPool constants) + { + if (constants == null) + return null; + + ConstantMethodref cmr = constants.getConstantMethodref(this.index); + + return cmr.getListOfParameterSignatures(); + } +} \ No newline at end of file diff --git a/src/jd/core/model/instruction/bytecode/instruction/InvokeNew.java b/src/jd/core/model/instruction/bytecode/instruction/InvokeNew.java new file mode 100644 index 00000000..eeaac563 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/InvokeNew.java @@ -0,0 +1,25 @@ +package jd.core.model.instruction.bytecode.instruction; + +import java.util.List; + +import jd.core.model.instruction.fast.FastConstants; + + +public class InvokeNew extends InvokeInstruction +{ + public int enumValueFieldRefIndex; + + public InvokeNew( + int opcode, int offset, int lineNumber, + int index, List args) + { + super(opcode, offset, lineNumber, index, args); + this.enumValueFieldRefIndex = 0; + } + + public void transformToEnumValue(GetStatic getStatic) + { + this.opcode = FastConstants.ENUMVALUE; + this.enumValueFieldRefIndex = getStatic.index; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/InvokeNoStaticInstruction.java b/src/jd/core/model/instruction/bytecode/instruction/InvokeNoStaticInstruction.java new file mode 100644 index 00000000..e03a3df5 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/InvokeNoStaticInstruction.java @@ -0,0 +1,16 @@ +package jd.core.model.instruction.bytecode.instruction; + +import java.util.List; + +public abstract class InvokeNoStaticInstruction extends InvokeInstruction +{ + public Instruction objectref; + + public InvokeNoStaticInstruction( + int opcode, int offset, int lineNumber, int index, + Instruction objectref, List args) + { + super(opcode, offset, lineNumber, index, args); + this.objectref = objectref; + } +} \ No newline at end of file diff --git a/src/jd/core/model/instruction/bytecode/instruction/Invokeinterface.java b/src/jd/core/model/instruction/bytecode/instruction/Invokeinterface.java new file mode 100644 index 00000000..84dd58ca --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/Invokeinterface.java @@ -0,0 +1,14 @@ +package jd.core.model.instruction.bytecode.instruction; + +import java.util.List; + + +public class Invokeinterface extends InvokeNoStaticInstruction +{ + public Invokeinterface( + int opcode, int offset, int lineNumber, int index, + Instruction objectref, List args) + { + super(opcode, offset, lineNumber, index, objectref, args); + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/Invokespecial.java b/src/jd/core/model/instruction/bytecode/instruction/Invokespecial.java new file mode 100644 index 00000000..f56769c6 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/Invokespecial.java @@ -0,0 +1,14 @@ +package jd.core.model.instruction.bytecode.instruction; + +import java.util.List; + + + +public class Invokespecial extends InvokeNoStaticInstruction +{ + public Invokespecial(int opcode, int offset, int lineNumber, int index, + Instruction objectref, List args) + { + super(opcode, offset, lineNumber, index, objectref, args); + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/Invokestatic.java b/src/jd/core/model/instruction/bytecode/instruction/Invokestatic.java new file mode 100644 index 00000000..b08f24c8 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/Invokestatic.java @@ -0,0 +1,13 @@ +package jd.core.model.instruction.bytecode.instruction; + +import java.util.List; + +public class Invokestatic extends InvokeInstruction +{ + public Invokestatic( + int opcode, int offset, int lineNumber, + int index, List args) + { + super(opcode, offset, lineNumber, index, args); + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/Invokevirtual.java b/src/jd/core/model/instruction/bytecode/instruction/Invokevirtual.java new file mode 100644 index 00000000..26de2733 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/Invokevirtual.java @@ -0,0 +1,15 @@ +package jd.core.model.instruction.bytecode.instruction; + +import java.util.List; + + + +public class Invokevirtual extends InvokeNoStaticInstruction +{ + public Invokevirtual( + int opcode, int offset, int lineNumber, int index, + Instruction objectref, List args) + { + super(opcode, offset, lineNumber, index, objectref, args); + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/Jsr.java b/src/jd/core/model/instruction/bytecode/instruction/Jsr.java new file mode 100644 index 00000000..6ec95d57 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/Jsr.java @@ -0,0 +1,18 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; + +public class Jsr extends BranchInstruction +{ + public Jsr(int opcode, int offset, int lineNumber, int branch) + { + super(opcode, offset, lineNumber, branch); + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + return null; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/LConst.java b/src/jd/core/model/instruction/bytecode/instruction/LConst.java new file mode 100644 index 00000000..a53e48a9 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/LConst.java @@ -0,0 +1,18 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; + +public class LConst extends ConstInstruction +{ + public LConst(int opcode, int offset, int lineNumber, int value) + { + super(opcode, offset, lineNumber, value); + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + return "J"; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/Ldc.java b/src/jd/core/model/instruction/bytecode/instruction/Ldc.java new file mode 100644 index 00000000..ba1ae846 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/Ldc.java @@ -0,0 +1,46 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; +import jd.core.model.classfile.constant.Constant; +import jd.core.model.classfile.constant.ConstantConstant; +import jd.core.util.StringConstants; + +public class Ldc extends LdcInstruction +{ + public Ldc(int opcode, int offset, int lineNumber, int index) + { + super(opcode, offset, lineNumber, index); + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + if (constants == null) + return null; + + Constant c = constants.get(this.index); + + if (c == null) + return null; + + switch (c.tag) + { + case ConstantConstant.CONSTANT_Float: + return "F"; + case ConstantConstant.CONSTANT_Integer: + return "I"; + case ConstantConstant.CONSTANT_String: + return StringConstants.INTERNAL_STRING_SIGNATURE; + case ConstantConstant.CONSTANT_Class: + return StringConstants.INTERNAL_CLASS_SIGNATURE; + /*{ + int index = ((ConstantClass)c).name_index; + return SignatureUtil.CreateTypeName( + constants.getConstantUtf8(index)); + }*/ + default: + return null; + } + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/Ldc2W.java b/src/jd/core/model/instruction/bytecode/instruction/Ldc2W.java new file mode 100644 index 00000000..3f7df233 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/Ldc2W.java @@ -0,0 +1,28 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; +import jd.core.model.classfile.constant.ConstantConstant; +import jd.core.model.classfile.constant.ConstantValue; + +public class Ldc2W extends LdcInstruction +{ + public Ldc2W(int opcode, int offset, int lineNumber, int index) + { + super(opcode, offset, lineNumber, index); + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + if (constants == null) + return null; + + ConstantValue cv = constants.getConstantValue(this.index); + + if (cv == null) + return null; + + return (cv.tag == ConstantConstant.CONSTANT_Double) ? "D" : "J"; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/LdcInstruction.java b/src/jd/core/model/instruction/bytecode/instruction/LdcInstruction.java new file mode 100644 index 00000000..d1ba6639 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/LdcInstruction.java @@ -0,0 +1,10 @@ +package jd.core.model.instruction.bytecode.instruction; + + +public abstract class LdcInstruction extends IndexInstruction +{ + public LdcInstruction(int opcode, int offset, int lineNumber, int index) + { + super(opcode, offset, lineNumber, index); + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/LoadInstruction.java b/src/jd/core/model/instruction/bytecode/instruction/LoadInstruction.java new file mode 100644 index 00000000..ab15b99b --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/LoadInstruction.java @@ -0,0 +1,23 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; + + +public class LoadInstruction extends IndexInstruction +{ + private String signature; + + public LoadInstruction( + int opcode, int offset, int lineNumber, int index, String signature) + { + super(opcode, offset, lineNumber, index); + this.signature = signature; + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + return this.signature; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/LookupSwitch.java b/src/jd/core/model/instruction/bytecode/instruction/LookupSwitch.java new file mode 100644 index 00000000..1f3426bf --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/LookupSwitch.java @@ -0,0 +1,15 @@ +package jd.core.model.instruction.bytecode.instruction; + + +public class LookupSwitch extends Switch +{ + public int[] keys; + + public LookupSwitch( + int opcode, int offset, int lineNumber, Instruction key, + int defaultOffset, int[] offsets, int[] keys) + { + super(opcode, offset, lineNumber, key, defaultOffset, offsets); + this.keys = keys; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/MonitorEnter.java b/src/jd/core/model/instruction/bytecode/instruction/MonitorEnter.java new file mode 100644 index 00000000..73398ccd --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/MonitorEnter.java @@ -0,0 +1,22 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; + +public class MonitorEnter extends Instruction +{ + public Instruction objectref; + + public MonitorEnter( + int opcode, int offset, int lineNumber, Instruction objectref) + { + super(opcode, offset, lineNumber); + this.objectref = objectref; + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + return null; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/MonitorExit.java b/src/jd/core/model/instruction/bytecode/instruction/MonitorExit.java new file mode 100644 index 00000000..2ba4cf14 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/MonitorExit.java @@ -0,0 +1,22 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; + +public class MonitorExit extends Instruction +{ + public Instruction objectref; + + public MonitorExit( + int opcode, int offset, int lineNumber, Instruction objectref) + { + super(opcode, offset, lineNumber); + this.objectref = objectref; + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + return null; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/MultiANewArray.java b/src/jd/core/model/instruction/bytecode/instruction/MultiANewArray.java new file mode 100644 index 00000000..2275e3ba --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/MultiANewArray.java @@ -0,0 +1,26 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; + +public class MultiANewArray extends IndexInstruction +{ + public Instruction dimensions[]; + + public MultiANewArray( + int opcode, int offset, int lineNumber, + int index, Instruction[] dimensions) + { + super(opcode, offset, lineNumber, index); + this.dimensions = dimensions; + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + if (constants == null) + return null; + + return constants.getConstantClassName(this.index); + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/New.java b/src/jd/core/model/instruction/bytecode/instruction/New.java new file mode 100644 index 00000000..12224cce --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/New.java @@ -0,0 +1,23 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; +import jd.core.util.SignatureUtil; + +public class New extends IndexInstruction +{ + public New(int opcode, int offset, int lineNumber, int index) + { + super(opcode, offset, lineNumber, index); + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + if (constants == null) + return null; + + return SignatureUtil.CreateTypeName( + constants.getConstantClassName(this.index)); + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/NewArray.java b/src/jd/core/model/instruction/bytecode/instruction/NewArray.java new file mode 100644 index 00000000..e2b0144a --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/NewArray.java @@ -0,0 +1,27 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; +import jd.core.util.SignatureUtil; + +public class NewArray extends Instruction +{ + public int type; + public Instruction dimension; + + public NewArray( + int opcode, int offset, int lineNumber, int type, Instruction dimension) + { + super(opcode, offset, lineNumber); + this.type = type; + this.dimension = dimension; + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + String signature = SignatureUtil.GetSignatureFromType(this.type); + + return (signature == null) ? null : "[" + signature; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/Pop.java b/src/jd/core/model/instruction/bytecode/instruction/Pop.java new file mode 100644 index 00000000..31ecdc16 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/Pop.java @@ -0,0 +1,21 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; + +public class Pop extends Instruction +{ + public Instruction objectref; + + public Pop(int opcode, int offset, int lineNumber, Instruction objectref) + { + super(opcode, offset, lineNumber); + this.objectref = objectref; + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + return null; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/PutField.java b/src/jd/core/model/instruction/bytecode/instruction/PutField.java new file mode 100644 index 00000000..51887c3a --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/PutField.java @@ -0,0 +1,27 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.instruction.bytecode.instruction.attribute.ValuerefAttribute; + + +public class PutField extends GetField implements ValuerefAttribute +{ + public Instruction valueref; + + public PutField( + int opcode, int offset, int lineNumber, int index, + Instruction objectref, Instruction valueref) + { + super(opcode, offset, lineNumber, index, objectref); + this.valueref = valueref; + } + + public Instruction getValueref() + { + return valueref; + } + + public void setValueref(Instruction valueref) + { + this.valueref = valueref; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/PutStatic.java b/src/jd/core/model/instruction/bytecode/instruction/PutStatic.java new file mode 100644 index 00000000..3d5a554e --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/PutStatic.java @@ -0,0 +1,26 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.instruction.bytecode.instruction.attribute.ValuerefAttribute; + + +public class PutStatic extends GetStatic implements ValuerefAttribute +{ + public Instruction valueref; + + public PutStatic( + int opcode, int offset, int lineNumber, int index, Instruction valueref) + { + super(opcode, offset, lineNumber, index); + this.valueref = valueref; + } + + public Instruction getValueref() + { + return valueref; + } + + public void setValueref(Instruction valueref) + { + this.valueref = valueref; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/Ret.java b/src/jd/core/model/instruction/bytecode/instruction/Ret.java new file mode 100644 index 00000000..809be029 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/Ret.java @@ -0,0 +1,18 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; + +public class Ret extends IndexInstruction +{ + public Ret(int opcode, int offset, int lineNumber, int index) + { + super(opcode, offset, lineNumber, index); + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + return null; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/Return.java b/src/jd/core/model/instruction/bytecode/instruction/Return.java new file mode 100644 index 00000000..496fefc6 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/Return.java @@ -0,0 +1,18 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; + +public class Return extends Instruction +{ + public Return(int opcode, int offset, int lineNumber) + { + super(opcode, offset, lineNumber); + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + return null; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/ReturnAddressLoad.java b/src/jd/core/model/instruction/bytecode/instruction/ReturnAddressLoad.java new file mode 100644 index 00000000..9ac1f6a8 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/ReturnAddressLoad.java @@ -0,0 +1,22 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; + +/* + * Pseudo instruction plac�e en debut de sous procedure. Lors de l'execution, + * cette adresse est normalement plac�e sur la pile par l'instruction JSR. + */ +public class ReturnAddressLoad extends Instruction +{ + public ReturnAddressLoad(int opcode, int offset, int lineNumber) + { + super(opcode, offset, lineNumber); + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + return null; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/ReturnInstruction.java b/src/jd/core/model/instruction/bytecode/instruction/ReturnInstruction.java new file mode 100644 index 00000000..3ece8ddc --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/ReturnInstruction.java @@ -0,0 +1,22 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; + +public class ReturnInstruction extends Instruction +{ + public Instruction valueref; + + public ReturnInstruction( + int opcode, int offset, int lineNumber, Instruction valueref) + { + super(opcode, offset, lineNumber); + this.valueref = valueref; + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + return null; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/SIPush.java b/src/jd/core/model/instruction/bytecode/instruction/SIPush.java new file mode 100644 index 00000000..dfdaf0e3 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/SIPush.java @@ -0,0 +1,10 @@ +package jd.core.model.instruction.bytecode.instruction; + + +public class SIPush extends IConst +{ + public SIPush(int opcode, int offset, int lineNumber, int value) + { + super(opcode, offset, lineNumber, value); + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/StoreInstruction.java b/src/jd/core/model/instruction/bytecode/instruction/StoreInstruction.java new file mode 100644 index 00000000..885e14d3 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/StoreInstruction.java @@ -0,0 +1,28 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.instruction.bytecode.instruction.attribute.ValuerefAttribute; + + +public class StoreInstruction + extends LoadInstruction implements ValuerefAttribute +{ + public Instruction valueref; + + public StoreInstruction( + int opcode, int offset, int lineNumber, int index, + String signature, Instruction valueref) + { + super(opcode, offset, lineNumber, index, signature); + this.valueref = valueref; + } + + public Instruction getValueref() + { + return valueref; + } + + public void setValueref(Instruction valueref) + { + this.valueref = valueref; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/Switch.java b/src/jd/core/model/instruction/bytecode/instruction/Switch.java new file mode 100644 index 00000000..25a0c52f --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/Switch.java @@ -0,0 +1,28 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; + + +public class Switch extends Instruction +{ + public Instruction key; + public int defaultOffset; + public int[] offsets; + + public Switch( + int opcode, int offset, int lineNumber, + Instruction key, int defaultOffset, int[] offsets) + { + super(opcode, offset, lineNumber); + this.key = key; + this.defaultOffset = defaultOffset; + this.offsets = offsets; + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + return null; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/TableSwitch.java b/src/jd/core/model/instruction/bytecode/instruction/TableSwitch.java new file mode 100644 index 00000000..0178d40a --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/TableSwitch.java @@ -0,0 +1,17 @@ +package jd.core.model.instruction.bytecode.instruction; + + +public class TableSwitch extends Switch +{ + public int low; + public int high; + + public TableSwitch( + int opcode, int offset, int lineNumber, Instruction key, + int defaultOffset, int[] offsets, int low, int high) + { + super(opcode, offset, lineNumber, key, defaultOffset, offsets); + this.low = low; + this.high = high; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/TernaryOpStore.java b/src/jd/core/model/instruction/bytecode/instruction/TernaryOpStore.java new file mode 100644 index 00000000..360d7848 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/TernaryOpStore.java @@ -0,0 +1,29 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; + +/* + * Cree pour la construction de l'operateur ternaire. + * Instancie par IfCmpFactory, IfFactory, IfXNullFactory & GotoFactory + */ +public class TernaryOpStore extends Instruction +{ + public Instruction objectref; + public int ternaryOp2ndValueOffset; + + public TernaryOpStore( + int opcode, int offset, int lineNumber, Instruction objectref, + int ternaryOp2ndValueOffset) + { + super(opcode, offset, lineNumber); + this.objectref = objectref; + this.ternaryOp2ndValueOffset = ternaryOp2ndValueOffset; + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + return this.objectref.getReturnedSignature(constants, localVariables); + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/TernaryOperator.java b/src/jd/core/model/instruction/bytecode/instruction/TernaryOperator.java new file mode 100644 index 00000000..c801c819 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/TernaryOperator.java @@ -0,0 +1,42 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; + +/* + * La construction de cette instruction ne suit pas les r�gles g�n�rales ! + * C'est la seule exception. Cette instruction, appartement au package + * 'bytecode', ne peut etre construite qu'apres avoir aglom�r�e les instructions + * 'if'. Cette instruction est affich�e par une classe du package 'bytecode' et + * est construite par une classe du package 'fast'. + */ +public class TernaryOperator extends Instruction +{ + public Instruction test; + public Instruction value1; + public Instruction value2; + + public TernaryOperator( + int opcode, int offset, int lineNumber, + Instruction test, Instruction value1, Instruction value2) + { + super(opcode, offset, lineNumber); + this.test = test; + this.value1 = value1; + this.value2 = value2; + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + if (this.value1 != null) + return this.value1.getReturnedSignature(constants, localVariables); + else + return this.value2.getReturnedSignature(constants, localVariables); + } + + public int getPriority() + { + return 13; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/UnaryOperatorInstruction.java b/src/jd/core/model/instruction/bytecode/instruction/UnaryOperatorInstruction.java new file mode 100644 index 00000000..4e8dfe80 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/UnaryOperatorInstruction.java @@ -0,0 +1,36 @@ +package jd.core.model.instruction.bytecode.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; + + + +public class UnaryOperatorInstruction extends Instruction +{ + private int priority; + public String signature; + public String operator; + public Instruction value; + + public UnaryOperatorInstruction( + int opcode, int offset, int lineNumber, int priority, + String signature, String operator, Instruction value) + { + super(opcode, offset, lineNumber); + this.priority = priority; + this.signature = signature; + this.operator = operator; + this.value = value; + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + return this.signature; + } + + public int getPriority() + { + return this.priority; + } +} diff --git a/src/jd/core/model/instruction/bytecode/instruction/attribute/ValuerefAttribute.java b/src/jd/core/model/instruction/bytecode/instruction/attribute/ValuerefAttribute.java new file mode 100644 index 00000000..ee6accf1 --- /dev/null +++ b/src/jd/core/model/instruction/bytecode/instruction/attribute/ValuerefAttribute.java @@ -0,0 +1,10 @@ +package jd.core.model.instruction.bytecode.instruction.attribute; + +import jd.core.model.instruction.bytecode.instruction.Instruction; + +public interface ValuerefAttribute +{ + public Instruction getValueref(); + + public void setValueref(Instruction valueref); +} diff --git a/src/jd/core/model/instruction/fast/FastConstants.java b/src/jd/core/model/instruction/fast/FastConstants.java new file mode 100644 index 00000000..770abfed --- /dev/null +++ b/src/jd/core/model/instruction/fast/FastConstants.java @@ -0,0 +1,56 @@ +package jd.core.model.instruction.fast; + +import jd.core.model.instruction.bytecode.ByteCodeConstants; + +public class FastConstants extends ByteCodeConstants +{ + // Fast opcode + public static final int WHILE = 301; + public static final int DO_WHILE = 302; + public static final int INFINITE_LOOP = 303; + public static final int FOR = 304; + public static final int FOREACH = 305; + + public static final int IF_ = 306; + public static final int IF_ELSE = 307; + + public static final int IF_CONTINUE = 308; + public static final int IF_BREAK = 309; + public static final int IF_LABELED_BREAK = 310; + public static final int GOTO_CONTINUE = 311; + public static final int GOTO_BREAK = 312; + public static final int GOTO_LABELED_BREAK = 313; + + public static final int SWITCH = 314; + public static final int SWITCH_ENUM = 315; + public static final int SWITCH_STRING = 316; + public static final int DECLARE = 317; + public static final int TRY = 318; + public static final int SYNCHRONIZED = 319; + + public static final int LABEL = 320; + + public static final int ENUMVALUE = 321; + + // Type of try blocks + public static final int TYPE_UNDEFINED = 0; + public static final int TYPE_CATCH = 1; + public static final int TYPE_118_FINALLY = 2; + public static final int TYPE_118_FINALLY_2 = 3; + public static final int TYPE_118_FINALLY_THROW = 4; + public static final int TYPE_118_SYNCHRONIZED = 5; + public static final int TYPE_118_SYNCHRONIZED_DOUBLE = 6; + public static final int TYPE_118_CATCH_FINALLY = 7; + public static final int TYPE_118_CATCH_FINALLY_2 = 8; + public static final int TYPE_131_CATCH_FINALLY = 9; + public static final int TYPE_142 = 10; + public static final int TYPE_142_FINALLY_THROW = 11; + // Jikes & Hors Eclipse + public static final int TYPE_JIKES_122 = 12; + // Dans Eclipse + public static final int TYPE_ECLIPSE_677_FINALLY = 13; + public static final int TYPE_ECLIPSE_677_CATCH_FINALLY = 14; + + + public static final String LABEL_PREFIX = "label"; +} diff --git a/src/jd/core/model/instruction/fast/instruction/FastDeclaration.java b/src/jd/core/model/instruction/fast/instruction/FastDeclaration.java new file mode 100644 index 00000000..67f7eceb --- /dev/null +++ b/src/jd/core/model/instruction/fast/instruction/FastDeclaration.java @@ -0,0 +1,29 @@ +package jd.core.model.instruction.fast.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; +import jd.core.model.instruction.bytecode.instruction.Instruction; + +/** + * list & while(true) + */ +public class FastDeclaration extends Instruction +{ + public int index; + public Instruction instruction; + + public FastDeclaration( + int opcode, int offset, int lineNumber, + int index, Instruction instruction) + { + super(opcode, offset, lineNumber); + this.index = index; + this.instruction = instruction; + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + return null; + } +} diff --git a/src/jd/core/model/instruction/fast/instruction/FastFor.java b/src/jd/core/model/instruction/fast/instruction/FastFor.java new file mode 100644 index 00000000..923e59bc --- /dev/null +++ b/src/jd/core/model/instruction/fast/instruction/FastFor.java @@ -0,0 +1,25 @@ +package jd.core.model.instruction.fast.instruction; + +import java.util.List; + +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +/** + * while, do-while & if + */ +public class FastFor extends FastTestList +{ + public Instruction init; + public Instruction inc; + + public FastFor( + int opcode, int offset, int lineNumber, int branch, + Instruction init, Instruction test, Instruction inc, + List instructions) + { + super(opcode, offset, lineNumber, branch, test, instructions); + this.init = init; + this.inc = inc; + } +} diff --git a/src/jd/core/model/instruction/fast/instruction/FastForEach.java b/src/jd/core/model/instruction/fast/instruction/FastForEach.java new file mode 100644 index 00000000..611cba43 --- /dev/null +++ b/src/jd/core/model/instruction/fast/instruction/FastForEach.java @@ -0,0 +1,21 @@ +package jd.core.model.instruction.fast.instruction; + +import java.util.List; + +import jd.core.model.instruction.bytecode.instruction.Instruction; + +public class FastForEach extends FastList +{ + public Instruction variable; + public Instruction values; + + public FastForEach( + int opcode, int offset, int lineNumber, int branch, + Instruction declaration, Instruction values, + List instructions) + { + super(opcode, offset, lineNumber, branch, instructions); + this.variable = declaration; + this.values = values; + } +} diff --git a/src/jd/core/model/instruction/fast/instruction/FastInstruction.java b/src/jd/core/model/instruction/fast/instruction/FastInstruction.java new file mode 100644 index 00000000..11a9bc4d --- /dev/null +++ b/src/jd/core/model/instruction/fast/instruction/FastInstruction.java @@ -0,0 +1,23 @@ +package jd.core.model.instruction.fast.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; +import jd.core.model.instruction.bytecode.instruction.Instruction; + +public class FastInstruction extends Instruction +{ + public Instruction instruction; + + public FastInstruction( + int opcode, int offset, int lineNumber, Instruction instruction) + { + super(opcode, offset, lineNumber); + this.instruction = instruction; + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + return null; + } +} diff --git a/src/jd/core/model/instruction/fast/instruction/FastLabel.java b/src/jd/core/model/instruction/fast/instruction/FastLabel.java new file mode 100644 index 00000000..7c4ad0bf --- /dev/null +++ b/src/jd/core/model/instruction/fast/instruction/FastLabel.java @@ -0,0 +1,23 @@ +package jd.core.model.instruction.fast.instruction; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; +import jd.core.model.instruction.bytecode.instruction.Instruction; + +public class FastLabel extends Instruction +{ + public Instruction instruction; + + public FastLabel( + int opcode, int offset, int lineNumber, Instruction instruction) + { + super(opcode, offset, lineNumber); + this.instruction = instruction; + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + return this.instruction.getReturnedSignature(constants, localVariables); + } +} diff --git a/src/jd/core/model/instruction/fast/instruction/FastList.java b/src/jd/core/model/instruction/fast/instruction/FastList.java new file mode 100644 index 00000000..17873d12 --- /dev/null +++ b/src/jd/core/model/instruction/fast/instruction/FastList.java @@ -0,0 +1,31 @@ +package jd.core.model.instruction.fast.instruction; + +import java.util.List; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; +import jd.core.model.instruction.bytecode.instruction.BranchInstruction; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +/** + * list & while(true) + */ +public class FastList extends BranchInstruction +{ + public List instructions; + + public FastList( + int opcode, int offset, int lineNumber, + int branch, List instructions) + { + super(opcode, offset, lineNumber, branch); + this.instructions = instructions; + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + return null; + } +} diff --git a/src/jd/core/model/instruction/fast/instruction/FastSwitch.java b/src/jd/core/model/instruction/fast/instruction/FastSwitch.java new file mode 100644 index 00000000..3080d60c --- /dev/null +++ b/src/jd/core/model/instruction/fast/instruction/FastSwitch.java @@ -0,0 +1,88 @@ +package jd.core.model.instruction.fast.instruction; + +import java.util.List; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariables; +import jd.core.model.instruction.bytecode.instruction.BranchInstruction; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +/** + * while, do-while & if + */ +public class FastSwitch extends BranchInstruction +{ + public Instruction test; + public Pair[] pairs; + + public FastSwitch( + int opcode, int offset, int lineNumber, int branch, + Instruction test, Pair[] pairs) + { + super(opcode, offset, lineNumber, branch); + this.test = test; + this.pairs = pairs; + } + + public static class Pair implements Comparable + { + private boolean defaultFlag; + private int key; + private int offset; + private List instructions; + + public Pair(boolean defaultFlag, int key, int offset) + { + this.defaultFlag = defaultFlag; + this.key = key; + this.offset = offset; + this.instructions = null; + } + + public boolean isDefault() + { + return defaultFlag; + } + + public int getKey() + { + return key; + } + public void setKey(int key) + { + this.key = key; + } + + public int getOffset() + { + return offset; + } + + public List getInstructions() + { + return instructions; + } + public void setInstructions(List instructions) + { + this.instructions = instructions; + } + + public int compareTo(Pair p) + { + int diffOffset = this.offset - p.offset; + + if (diffOffset != 0) + return diffOffset; + + return this.isDefault() ? 1 : p.isDefault() ? -1 : + (this.key - p.key); + } + } + + public String getReturnedSignature( + ConstantPool constants, LocalVariables localVariables) + { + return null; + } +} diff --git a/src/jd/core/model/instruction/fast/instruction/FastSynchronized.java b/src/jd/core/model/instruction/fast/instruction/FastSynchronized.java new file mode 100644 index 00000000..469d51b4 --- /dev/null +++ b/src/jd/core/model/instruction/fast/instruction/FastSynchronized.java @@ -0,0 +1,22 @@ +package jd.core.model.instruction.fast.instruction; + +import java.util.List; + +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +/** + * enter exit monitor + */ +public class FastSynchronized extends FastList +{ + public Instruction monitor; + + public FastSynchronized( + int opcode, int offset, int lineNumber, + int branch, List instructions) + { + super(opcode, offset, lineNumber, branch, instructions); + this.monitor = null; + } +} diff --git a/src/jd/core/model/instruction/fast/instruction/FastTest2Lists.java b/src/jd/core/model/instruction/fast/instruction/FastTest2Lists.java new file mode 100644 index 00000000..f029b3a0 --- /dev/null +++ b/src/jd/core/model/instruction/fast/instruction/FastTest2Lists.java @@ -0,0 +1,23 @@ +package jd.core.model.instruction.fast.instruction; + +import java.util.List; + +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +/** + * if-else + */ +public class FastTest2Lists extends FastTestList +{ + public List instructions2; + + public FastTest2Lists( + int opcode, int offset, int lineNumber, int branch, + Instruction test, List instructions1, + List instructions2) + { + super(opcode, offset, lineNumber, branch, test, instructions1); + this.instructions2 = instructions2; + } +} diff --git a/src/jd/core/model/instruction/fast/instruction/FastTestList.java b/src/jd/core/model/instruction/fast/instruction/FastTestList.java new file mode 100644 index 00000000..d57e7322 --- /dev/null +++ b/src/jd/core/model/instruction/fast/instruction/FastTestList.java @@ -0,0 +1,22 @@ +package jd.core.model.instruction.fast.instruction; + +import java.util.List; + +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +/** + * while, do-while & if + */ +public class FastTestList extends FastList +{ + public Instruction test; + + public FastTestList( + int opcode, int offset, int lineNumber, int branch, Instruction test, + List instructions) + { + super(opcode, offset, lineNumber, branch, instructions); + this.test = test; + } +} diff --git a/src/jd/core/model/instruction/fast/instruction/FastTry.java b/src/jd/core/model/instruction/fast/instruction/FastTry.java new file mode 100644 index 00000000..ecad2b2e --- /dev/null +++ b/src/jd/core/model/instruction/fast/instruction/FastTry.java @@ -0,0 +1,48 @@ +package jd.core.model.instruction.fast.instruction; + +import java.util.List; + +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +/** + * try-catch-finally + */ +public class FastTry extends FastList +{ + public List catches; + public List finallyInstructions; + + public FastTry( + int opcode, int offset, int lineNumber, int branch, + List instructions, List catches, + List finallyInstructions) + { + super(opcode, offset, lineNumber, branch, instructions); + this.catches = catches; + this.finallyInstructions = finallyInstructions; + } + + public static class FastCatch + { + public int offset; + public int exceptionOffset; + public int exceptionTypeIndex; + public int otherExceptionTypeIndexes[]; + public int localVarIndex; + public List instructions; + + public FastCatch( + int offset, int exceptionOffset, int exceptionTypeIndex, + int otherExceptionTypeIndexes[], int localVarIndex, + List instructions) + { + this.offset = offset; + this.exceptionOffset = exceptionOffset; + this.exceptionTypeIndex = exceptionTypeIndex; + this.otherExceptionTypeIndexes = otherExceptionTypeIndexes; + this.localVarIndex = localVarIndex; + this.instructions = instructions; + } + } +} diff --git a/src/jd/core/model/layout/block/AnnotationsLayoutBlock.java b/src/jd/core/model/layout/block/AnnotationsLayoutBlock.java new file mode 100644 index 00000000..d75e92b7 --- /dev/null +++ b/src/jd/core/model/layout/block/AnnotationsLayoutBlock.java @@ -0,0 +1,30 @@ +package jd.core.model.layout.block; + +import java.util.ArrayList; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.attribute.Annotation; +import jd.core.model.instruction.bytecode.instruction.Instruction; + +public class AnnotationsLayoutBlock extends LayoutBlock +{ + public ClassFile classFile; + public ArrayList annotations; + + public AnnotationsLayoutBlock( + ClassFile classFile, ArrayList annotations) + { + this(classFile, annotations, annotations.size()); + } + + private AnnotationsLayoutBlock( + ClassFile classFile, ArrayList annotations, int maxLineCount) + { + super( + LayoutBlockConstants.ANNOTATIONS, + Instruction.UNKNOWN_LINE_NUMBER, Instruction.UNKNOWN_LINE_NUMBER, + 0, maxLineCount, maxLineCount); + this.classFile = classFile; + this.annotations = annotations; + } +} diff --git a/src/jd/core/model/layout/block/BlockLayoutBlock.java b/src/jd/core/model/layout/block/BlockLayoutBlock.java new file mode 100644 index 00000000..4ca97b09 --- /dev/null +++ b/src/jd/core/model/layout/block/BlockLayoutBlock.java @@ -0,0 +1,28 @@ +package jd.core.model.layout.block; + +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class BlockLayoutBlock extends LayoutBlock +{ + public BlockLayoutBlock other; + + public BlockLayoutBlock(byte tag, int lineCount) + { + super( + tag, Instruction.UNKNOWN_LINE_NUMBER, + Instruction.UNKNOWN_LINE_NUMBER, lineCount); + this.other = null; + } + + public BlockLayoutBlock( + byte tag, int minimalLineCount, + int maximalLineCount, int preferedLineCount) + { + super( + tag, + Instruction.UNKNOWN_LINE_NUMBER, Instruction.UNKNOWN_LINE_NUMBER, + minimalLineCount, maximalLineCount, preferedLineCount); + this.other = null; + } +} diff --git a/src/jd/core/model/layout/block/ByteCodeLayoutBlock.java b/src/jd/core/model/layout/block/ByteCodeLayoutBlock.java new file mode 100644 index 00000000..f2db10d1 --- /dev/null +++ b/src/jd/core/model/layout/block/ByteCodeLayoutBlock.java @@ -0,0 +1,21 @@ +package jd.core.model.layout.block; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.instruction.Instruction; + +public class ByteCodeLayoutBlock extends LayoutBlock +{ + public ClassFile classFile; + public Method method; + + public ByteCodeLayoutBlock(ClassFile classFile, Method method) + { + super( + LayoutBlockConstants.BYTE_CODE, + Instruction.UNKNOWN_LINE_NUMBER, Instruction.UNKNOWN_LINE_NUMBER, + 0, 0, 0); + this.classFile = classFile; + this.method = method; + } +} diff --git a/src/jd/core/model/layout/block/CaseBlockEndLayoutBlock.java b/src/jd/core/model/layout/block/CaseBlockEndLayoutBlock.java new file mode 100644 index 00000000..d643fbe6 --- /dev/null +++ b/src/jd/core/model/layout/block/CaseBlockEndLayoutBlock.java @@ -0,0 +1,16 @@ +package jd.core.model.layout.block; + +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class CaseBlockEndLayoutBlock extends LayoutBlock +{ + public CaseBlockEndLayoutBlock() + { + super( + LayoutBlockConstants.CASE_BLOCK_END, + Instruction.UNKNOWN_LINE_NUMBER, + Instruction.UNKNOWN_LINE_NUMBER, + 0, LayoutBlockConstants.UNLIMITED_LINE_COUNT, 1); + } +} diff --git a/src/jd/core/model/layout/block/CaseBlockStartLayoutBlock.java b/src/jd/core/model/layout/block/CaseBlockStartLayoutBlock.java new file mode 100644 index 00000000..00ced3df --- /dev/null +++ b/src/jd/core/model/layout/block/CaseBlockStartLayoutBlock.java @@ -0,0 +1,16 @@ +package jd.core.model.layout.block; + +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class CaseBlockStartLayoutBlock extends LayoutBlock +{ + public CaseBlockStartLayoutBlock() + { + super( + LayoutBlockConstants.CASE_BLOCK_START, + Instruction.UNKNOWN_LINE_NUMBER, + Instruction.UNKNOWN_LINE_NUMBER, + 0, 1, 1); + } +} diff --git a/src/jd/core/model/layout/block/CaseEnumLayoutBlock.java b/src/jd/core/model/layout/block/CaseEnumLayoutBlock.java new file mode 100644 index 00000000..bf95a9c7 --- /dev/null +++ b/src/jd/core/model/layout/block/CaseEnumLayoutBlock.java @@ -0,0 +1,23 @@ +package jd.core.model.layout.block; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.fast.instruction.FastSwitch; + +public class CaseEnumLayoutBlock extends CaseLayoutBlock +{ + public int switchMapKeyIndex; + + public CaseEnumLayoutBlock( + ClassFile classFile, Method method, + FastSwitch fs, int firstIndex, int lastIndex, + int switchMapKeyIndex) + { + super( + LayoutBlockConstants.FRAGMENT_CASE_ENUM, + classFile, method, fs, + firstIndex, lastIndex, lastIndex-firstIndex); + + this.switchMapKeyIndex = switchMapKeyIndex; + } +} diff --git a/src/jd/core/model/layout/block/CaseLayoutBlock.java b/src/jd/core/model/layout/block/CaseLayoutBlock.java new file mode 100644 index 00000000..193b5fb6 --- /dev/null +++ b/src/jd/core/model/layout/block/CaseLayoutBlock.java @@ -0,0 +1,42 @@ +package jd.core.model.layout.block; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.fast.instruction.FastSwitch; + + +public class CaseLayoutBlock extends LayoutBlock +{ + public ClassFile classFile; + public Method method; + public FastSwitch fs; + public int firstIndex; + public int lastIndex; + + public CaseLayoutBlock( + byte tag, ClassFile classFile, Method method, + FastSwitch fs, int firstIndex, int lastIndex) + { + this( + tag, classFile, method, fs, + firstIndex, lastIndex, lastIndex-firstIndex); + } + + protected CaseLayoutBlock( + byte tag, ClassFile classFile, Method method, FastSwitch fs, + int firstIndex, int lastIndex, int preferedLineCount) + { + super( + tag, + Instruction.UNKNOWN_LINE_NUMBER, + Instruction.UNKNOWN_LINE_NUMBER, + 0, preferedLineCount, preferedLineCount); + + this.classFile = classFile; + this.method = method; + this.fs = fs; + this.firstIndex = firstIndex; + this.lastIndex = lastIndex; + } +} diff --git a/src/jd/core/model/layout/block/CommentDeprecatedLayoutBlock.java b/src/jd/core/model/layout/block/CommentDeprecatedLayoutBlock.java new file mode 100644 index 00000000..673ad9e4 --- /dev/null +++ b/src/jd/core/model/layout/block/CommentDeprecatedLayoutBlock.java @@ -0,0 +1,14 @@ +package jd.core.model.layout.block; + +import jd.core.model.instruction.bytecode.instruction.Instruction; + +public class CommentDeprecatedLayoutBlock extends LayoutBlock +{ + public CommentDeprecatedLayoutBlock() + { + super( + LayoutBlockConstants.COMMENT_DEPRECATED, + Instruction.UNKNOWN_LINE_NUMBER, Instruction.UNKNOWN_LINE_NUMBER, + 0, 3, 3); + } +} diff --git a/src/jd/core/model/layout/block/CommentErrorLayoutBlock.java b/src/jd/core/model/layout/block/CommentErrorLayoutBlock.java new file mode 100644 index 00000000..8423925c --- /dev/null +++ b/src/jd/core/model/layout/block/CommentErrorLayoutBlock.java @@ -0,0 +1,14 @@ +package jd.core.model.layout.block; + +import jd.core.model.instruction.bytecode.instruction.Instruction; + +public class CommentErrorLayoutBlock extends LayoutBlock +{ + public CommentErrorLayoutBlock() + { + super( + LayoutBlockConstants.COMMENT_ERROR, + Instruction.UNKNOWN_LINE_NUMBER, Instruction.UNKNOWN_LINE_NUMBER, + 0, 1, 1); + } +} diff --git a/src/jd/core/model/layout/block/DeclareLayoutBlock.java b/src/jd/core/model/layout/block/DeclareLayoutBlock.java new file mode 100644 index 00000000..ab39e000 --- /dev/null +++ b/src/jd/core/model/layout/block/DeclareLayoutBlock.java @@ -0,0 +1,25 @@ +package jd.core.model.layout.block; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class DeclareLayoutBlock extends LayoutBlock +{ + public ClassFile classFile; + public Method method; + public Instruction instruction; + + public DeclareLayoutBlock( + ClassFile classFile, Method method, Instruction instruction) + { + super( + LayoutBlockConstants.DECLARE, + Instruction.UNKNOWN_LINE_NUMBER, Instruction.UNKNOWN_LINE_NUMBER, + 0, 0, 0); + this.classFile = classFile; + this.method = method; + this.instruction = instruction; + } +} diff --git a/src/jd/core/model/layout/block/ExtendsSuperInterfacesLayoutBlock.java b/src/jd/core/model/layout/block/ExtendsSuperInterfacesLayoutBlock.java new file mode 100644 index 00000000..bf9263ee --- /dev/null +++ b/src/jd/core/model/layout/block/ExtendsSuperInterfacesLayoutBlock.java @@ -0,0 +1,28 @@ +package jd.core.model.layout.block; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.instruction.bytecode.instruction.Instruction; + +public class ExtendsSuperInterfacesLayoutBlock extends LayoutBlock +{ + public ClassFile classFile; + + public ExtendsSuperInterfacesLayoutBlock(ClassFile classFile) + { + this( + LayoutBlockConstants.EXTENDS_SUPER_INTERFACES, + Instruction.UNKNOWN_LINE_NUMBER, Instruction.UNKNOWN_LINE_NUMBER, + 0, 1, 1, classFile); + } + + protected ExtendsSuperInterfacesLayoutBlock( + byte tag, int firstLineNumber, int lastLineNumber, + int minimalLineCount, int maximalLineCount, int preferedLineCount, + ClassFile classFile) + { + super( + tag, firstLineNumber, lastLineNumber, + minimalLineCount, maximalLineCount, preferedLineCount); + this.classFile = classFile; + } +} diff --git a/src/jd/core/model/layout/block/ExtendsSuperTypeLayoutBlock.java b/src/jd/core/model/layout/block/ExtendsSuperTypeLayoutBlock.java new file mode 100644 index 00000000..085bd627 --- /dev/null +++ b/src/jd/core/model/layout/block/ExtendsSuperTypeLayoutBlock.java @@ -0,0 +1,28 @@ +package jd.core.model.layout.block; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.instruction.bytecode.instruction.Instruction; + +public class ExtendsSuperTypeLayoutBlock extends LayoutBlock +{ + public ClassFile classFile; + + public ExtendsSuperTypeLayoutBlock(ClassFile classFile) + { + this( + LayoutBlockConstants.EXTENDS_SUPER_TYPE, + Instruction.UNKNOWN_LINE_NUMBER, Instruction.UNKNOWN_LINE_NUMBER, + 0, 1, 1, classFile); + } + + protected ExtendsSuperTypeLayoutBlock( + byte tag, int firstLineNumber, int lastLineNumber, + int minimalLineCount, int maximalLineCount, int preferedLineCount, + ClassFile classFile) + { + super( + tag, firstLineNumber, lastLineNumber, + minimalLineCount, maximalLineCount, preferedLineCount); + this.classFile = classFile; + } +} diff --git a/src/jd/core/model/layout/block/FastCatchLayoutBlock.java b/src/jd/core/model/layout/block/FastCatchLayoutBlock.java new file mode 100644 index 00000000..98841124 --- /dev/null +++ b/src/jd/core/model/layout/block/FastCatchLayoutBlock.java @@ -0,0 +1,28 @@ +package jd.core.model.layout.block; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.fast.instruction.FastTry.FastCatch; + + +public class FastCatchLayoutBlock extends LayoutBlock +{ + public ClassFile classFile; + public Method method; + public FastCatch fc; + + public FastCatchLayoutBlock( + ClassFile classFile, Method method, FastCatch fc) + { + super( + LayoutBlockConstants.FRAGMENT_CATCH, + Instruction.UNKNOWN_LINE_NUMBER, + Instruction.UNKNOWN_LINE_NUMBER, + 0, 0, 0); + + this.classFile = classFile; + this.method = method; + this.fc = fc; + } +} diff --git a/src/jd/core/model/layout/block/FastSwitchLayoutBlock.java b/src/jd/core/model/layout/block/FastSwitchLayoutBlock.java new file mode 100644 index 00000000..a81cf648 --- /dev/null +++ b/src/jd/core/model/layout/block/FastSwitchLayoutBlock.java @@ -0,0 +1,27 @@ +package jd.core.model.layout.block; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.fast.instruction.FastSwitch; + + +public class FastSwitchLayoutBlock extends LayoutBlock +{ + public ClassFile classFile; + public Method method; + public FastSwitch fs; + + public FastSwitchLayoutBlock( + byte tag, int firstLineNumber, int lastLineNumber, + int minimalLineCount, int maximalLineCount, int preferedLineCount, + ClassFile classFile, Method method, FastSwitch fs) + { + super( + tag, firstLineNumber, lastLineNumber, + minimalLineCount, maximalLineCount, preferedLineCount); + + this.classFile = classFile; + this.method = method; + this.fs = fs; + } +} diff --git a/src/jd/core/model/layout/block/FieldNameLayoutBlock.java b/src/jd/core/model/layout/block/FieldNameLayoutBlock.java new file mode 100644 index 00000000..01155bfb --- /dev/null +++ b/src/jd/core/model/layout/block/FieldNameLayoutBlock.java @@ -0,0 +1,21 @@ +package jd.core.model.layout.block; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Field; +import jd.core.model.instruction.bytecode.instruction.Instruction; + +public class FieldNameLayoutBlock extends LayoutBlock +{ + public ClassFile classFile; + public Field field; + + public FieldNameLayoutBlock(ClassFile classFile, Field field) + { + super( + LayoutBlockConstants.FIELD_NAME, + Instruction.UNKNOWN_LINE_NUMBER, Instruction.UNKNOWN_LINE_NUMBER, + 0, 0, 0); + this.classFile = classFile; + this.field = field; + } +} diff --git a/src/jd/core/model/layout/block/FragmentLayoutBlock.java b/src/jd/core/model/layout/block/FragmentLayoutBlock.java new file mode 100644 index 00000000..e17c4d88 --- /dev/null +++ b/src/jd/core/model/layout/block/FragmentLayoutBlock.java @@ -0,0 +1,14 @@ +package jd.core.model.layout.block; + +import jd.core.model.instruction.bytecode.instruction.Instruction; + +public class FragmentLayoutBlock extends LayoutBlock +{ + public FragmentLayoutBlock(byte tag) + { + super( + tag, + Instruction.UNKNOWN_LINE_NUMBER, Instruction.UNKNOWN_LINE_NUMBER, + 0, 0, 0); + } +} diff --git a/src/jd/core/model/layout/block/GenericExtendsSuperInterfacesLayoutBlock.java b/src/jd/core/model/layout/block/GenericExtendsSuperInterfacesLayoutBlock.java new file mode 100644 index 00000000..7ee955db --- /dev/null +++ b/src/jd/core/model/layout/block/GenericExtendsSuperInterfacesLayoutBlock.java @@ -0,0 +1,22 @@ +package jd.core.model.layout.block; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.instruction.bytecode.instruction.Instruction; + +public class GenericExtendsSuperInterfacesLayoutBlock + extends ExtendsSuperInterfacesLayoutBlock +{ + public char[] caSignature; + public int signatureIndex; + + public GenericExtendsSuperInterfacesLayoutBlock( + ClassFile classFile, char[] caSignature, int signatureIndex) + { + super( + LayoutBlockConstants.GENERIC_EXTENDS_SUPER_INTERFACES, + Instruction.UNKNOWN_LINE_NUMBER, Instruction.UNKNOWN_LINE_NUMBER, + 0, 1, 1, classFile); + this.caSignature = caSignature; + this.signatureIndex = signatureIndex; + } +} diff --git a/src/jd/core/model/layout/block/GenericExtendsSuperTypeLayoutBlock.java b/src/jd/core/model/layout/block/GenericExtendsSuperTypeLayoutBlock.java new file mode 100644 index 00000000..fe522b39 --- /dev/null +++ b/src/jd/core/model/layout/block/GenericExtendsSuperTypeLayoutBlock.java @@ -0,0 +1,22 @@ +package jd.core.model.layout.block; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.instruction.bytecode.instruction.Instruction; + +public class GenericExtendsSuperTypeLayoutBlock + extends ExtendsSuperTypeLayoutBlock +{ + public char[] caSignature; + public int signatureIndex; + + public GenericExtendsSuperTypeLayoutBlock( + ClassFile classFile, char[] caSignature, int signatureIndex) + { + super( + LayoutBlockConstants.GENERIC_EXTENDS_SUPER_TYPE, + Instruction.UNKNOWN_LINE_NUMBER, Instruction.UNKNOWN_LINE_NUMBER, + 0, 1, 1, classFile); + this.caSignature = caSignature; + this.signatureIndex = signatureIndex; + } +} diff --git a/src/jd/core/model/layout/block/GenericImplementsInterfacesLayoutBlock.java b/src/jd/core/model/layout/block/GenericImplementsInterfacesLayoutBlock.java new file mode 100644 index 00000000..a8e731af --- /dev/null +++ b/src/jd/core/model/layout/block/GenericImplementsInterfacesLayoutBlock.java @@ -0,0 +1,22 @@ +package jd.core.model.layout.block; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.instruction.bytecode.instruction.Instruction; + +public class GenericImplementsInterfacesLayoutBlock + extends ImplementsInterfacesLayoutBlock +{ + public char[] caSignature; + public int signatureIndex; + + public GenericImplementsInterfacesLayoutBlock( + ClassFile classFile, char[] caSignature, int signatureIndex) + { + super( + LayoutBlockConstants.GENERIC_IMPLEMENTS_INTERFACES, + Instruction.UNKNOWN_LINE_NUMBER, Instruction.UNKNOWN_LINE_NUMBER, + 0, 1, 1, classFile); + this.caSignature = caSignature; + this.signatureIndex = signatureIndex; + } +} diff --git a/src/jd/core/model/layout/block/GenericTypeNameLayoutBlock.java b/src/jd/core/model/layout/block/GenericTypeNameLayoutBlock.java new file mode 100644 index 00000000..593f8e2e --- /dev/null +++ b/src/jd/core/model/layout/block/GenericTypeNameLayoutBlock.java @@ -0,0 +1,19 @@ +package jd.core.model.layout.block; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.instruction.bytecode.instruction.Instruction; + +public class GenericTypeNameLayoutBlock extends TypeNameLayoutBlock +{ + public String signature; + + public GenericTypeNameLayoutBlock( + ClassFile classFile, String signature) + { + super( + LayoutBlockConstants.GENERIC_TYPE_NAME, + Instruction.UNKNOWN_LINE_NUMBER, Instruction.UNKNOWN_LINE_NUMBER, + 0, 0, 0, classFile); + this.signature = signature; + } +} diff --git a/src/jd/core/model/layout/block/ImplementsInterfacesLayoutBlock.java b/src/jd/core/model/layout/block/ImplementsInterfacesLayoutBlock.java new file mode 100644 index 00000000..4cd32fd0 --- /dev/null +++ b/src/jd/core/model/layout/block/ImplementsInterfacesLayoutBlock.java @@ -0,0 +1,28 @@ +package jd.core.model.layout.block; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.instruction.bytecode.instruction.Instruction; + +public class ImplementsInterfacesLayoutBlock extends LayoutBlock +{ + public ClassFile classFile; + + public ImplementsInterfacesLayoutBlock(ClassFile classFile) + { + this( + LayoutBlockConstants.IMPLEMENTS_INTERFACES, + Instruction.UNKNOWN_LINE_NUMBER, Instruction.UNKNOWN_LINE_NUMBER, + 0, 1, 1, classFile); + } + + protected ImplementsInterfacesLayoutBlock( + byte tag, int firstLineNumber, int lastLineNumber, + int minimalLineCount, int maximalLineCount, int preferedLineCount, + ClassFile classFile) + { + super( + tag, firstLineNumber, lastLineNumber, + minimalLineCount, maximalLineCount, preferedLineCount); + this.classFile = classFile; + } +} diff --git a/src/jd/core/model/layout/block/ImportsLayoutBlock.java b/src/jd/core/model/layout/block/ImportsLayoutBlock.java new file mode 100644 index 00000000..407511a0 --- /dev/null +++ b/src/jd/core/model/layout/block/ImportsLayoutBlock.java @@ -0,0 +1,18 @@ +package jd.core.model.layout.block; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.instruction.bytecode.instruction.Instruction; + +public class ImportsLayoutBlock extends LayoutBlock +{ + public ClassFile classFile; + + public ImportsLayoutBlock(ClassFile classFile, int maxLineCount) + { + super( + LayoutBlockConstants.IMPORTS, + Instruction.UNKNOWN_LINE_NUMBER, Instruction.UNKNOWN_LINE_NUMBER, + 0, maxLineCount, maxLineCount); + this.classFile = classFile; + } +} diff --git a/src/jd/core/model/layout/block/InnerTypeBodyBlockEndLayoutBlock.java b/src/jd/core/model/layout/block/InnerTypeBodyBlockEndLayoutBlock.java new file mode 100644 index 00000000..57db29f6 --- /dev/null +++ b/src/jd/core/model/layout/block/InnerTypeBodyBlockEndLayoutBlock.java @@ -0,0 +1,12 @@ +package jd.core.model.layout.block; + + +public class InnerTypeBodyBlockEndLayoutBlock extends BlockLayoutBlock +{ + public InnerTypeBodyBlockEndLayoutBlock() + { + super( + LayoutBlockConstants.INNER_TYPE_BODY_BLOCK_END, 0, + LayoutBlockConstants.UNLIMITED_LINE_COUNT, 1); + } +} diff --git a/src/jd/core/model/layout/block/InnerTypeBodyBlockStartLayoutBlock.java b/src/jd/core/model/layout/block/InnerTypeBodyBlockStartLayoutBlock.java new file mode 100644 index 00000000..8bda525c --- /dev/null +++ b/src/jd/core/model/layout/block/InnerTypeBodyBlockStartLayoutBlock.java @@ -0,0 +1,18 @@ +package jd.core.model.layout.block; + + +public class InnerTypeBodyBlockStartLayoutBlock extends BlockLayoutBlock +{ + public InnerTypeBodyBlockStartLayoutBlock() + { + super( + LayoutBlockConstants.INNER_TYPE_BODY_BLOCK_START, 0, + LayoutBlockConstants.UNLIMITED_LINE_COUNT, 2); + } + + public void transformToStartEndBlock() + { + this.tag = LayoutBlockConstants.INNER_TYPE_BODY_BLOCK_START_END; + this.preferedLineCount = this.lineCount = 0; + } +} diff --git a/src/jd/core/model/layout/block/InstructionLayoutBlock.java b/src/jd/core/model/layout/block/InstructionLayoutBlock.java new file mode 100644 index 00000000..b3a75743 --- /dev/null +++ b/src/jd/core/model/layout/block/InstructionLayoutBlock.java @@ -0,0 +1,33 @@ +package jd.core.model.layout.block; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class InstructionLayoutBlock extends LayoutBlock +{ + public ClassFile classFile; + public Method method; + public Instruction instruction; + public int firstOffset; + public int lastOffset; + + public InstructionLayoutBlock( + byte tag, int firstLineNumber, int lastLineNumber, + int minimalLineCount, int maximalLineCount, int preferedLineCount, + ClassFile classFile, + Method method, + Instruction instruction, + int firstOffset, int lastOffset) + { + super( + tag, firstLineNumber, lastLineNumber, + minimalLineCount, maximalLineCount, preferedLineCount); + this.classFile = classFile; + this.method = method; + this.instruction = instruction; + this.firstOffset = firstOffset; + this.lastOffset = lastOffset; + } +} diff --git a/src/jd/core/model/layout/block/InstructionsLayoutBlock.java b/src/jd/core/model/layout/block/InstructionsLayoutBlock.java new file mode 100644 index 00000000..95145bc3 --- /dev/null +++ b/src/jd/core/model/layout/block/InstructionsLayoutBlock.java @@ -0,0 +1,41 @@ +package jd.core.model.layout.block; + +import java.util.List; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class InstructionsLayoutBlock extends LayoutBlock +{ + public ClassFile classFile; + public Method method; + public List instructions; + public int firstIndex; + public int lastIndex; + public int firstOffset; + public int lastOffset; + + public InstructionsLayoutBlock( + int firstLineNumber, int lastLineNumber, + int minimalLineCount, int maximalLineCount, int preferedLineCount, + ClassFile classFile, + Method method, + List instructions, + int firstIndex, int lastIndex, + int firstOffset, int lastOffset) + { + super( + LayoutBlockConstants.INSTRUCTIONS, + firstLineNumber, lastLineNumber, + minimalLineCount, maximalLineCount, preferedLineCount); + this.classFile = classFile; + this.method = method; + this.instructions = instructions; + this.firstIndex = firstIndex; + this.lastIndex = lastIndex; + this.firstOffset = firstOffset; + this.lastOffset = lastOffset; + } +} diff --git a/src/jd/core/model/layout/block/LayoutBlock.java b/src/jd/core/model/layout/block/LayoutBlock.java new file mode 100644 index 00000000..bd5a1a8f --- /dev/null +++ b/src/jd/core/model/layout/block/LayoutBlock.java @@ -0,0 +1,56 @@ +package jd.core.model.layout.block; + +import jd.core.model.layout.section.LayoutSection; + +/** + * bloc(i).lastLineNumber = bloc(i).firstLineNumber + bloc(i).minimalLineCount + * + * bloc(i).firstLineNumber + bloc(i).minimalLineCount <= + * bloc(i+1).firstLineNumber <= + * bloc(i).firstLineNumber + bloc(i).maximalLineCount + */ +public class LayoutBlock { + + public byte tag; + + public int firstLineNumber; + public int lastLineNumber; + + public int minimalLineCount; + public int maximalLineCount; + public int preferedLineCount; + + public int lineCount; + + public int index; + public LayoutSection section; + + public LayoutBlock( + byte tag, int firstLineNumber, int lastLineNumber, int lineCount) + { + this.tag = tag; + this.firstLineNumber = firstLineNumber; + this.lastLineNumber = lastLineNumber; + this.minimalLineCount = lineCount; + this.maximalLineCount = lineCount; + this.preferedLineCount = lineCount; + this.lineCount = lineCount; + this.index = 0; + this.section = null; + } + + public LayoutBlock( + byte tag, int firstLineNumber, int lastLineNumber, + int minimalLineCount, int maximalLineCount, int preferedLineCount) + { + this.tag = tag; + this.firstLineNumber = firstLineNumber; + this.lastLineNumber = lastLineNumber; + this.minimalLineCount = minimalLineCount; + this.maximalLineCount = maximalLineCount; + this.preferedLineCount = preferedLineCount; + this.lineCount = preferedLineCount; + this.index = 0; + this.section = null; + } +} diff --git a/src/jd/core/model/layout/block/LayoutBlockConstants.java b/src/jd/core/model/layout/block/LayoutBlockConstants.java new file mode 100644 index 00000000..99ded947 --- /dev/null +++ b/src/jd/core/model/layout/block/LayoutBlockConstants.java @@ -0,0 +1,116 @@ +package jd.core.model.layout.block; + +public class LayoutBlockConstants +{ + public static final byte UNDEFINED = 0; + + public static final byte PACKAGE = 1; + public static final byte SEPARATOR = 2; + public static final byte SEPARATOR_AT_BEGINING = 3; + public static final byte SEPARATOR_AFTER_IMPORTS = 4; + public static final byte SEPARATOR_OF_STATEMENTS = 5; + + public static final byte IMPORTS = 6; + + public static final byte TYPE_MARKER_START = 7; + public static final byte TYPE_MARKER_END = 8; + + public static final byte FIELD_MARKER_START = 9; + public static final byte FIELD_MARKER_END = 10; + + public static final byte METHOD_MARKER_START = 11; + public static final byte METHOD_MARKER_END = 12; + + public static final byte TYPE_BODY_BLOCK_START = 13; + public static final byte TYPE_BODY_BLOCK_END = 14; + public static final byte TYPE_BODY_BLOCK_START_END = 15; + + public static final byte INNER_TYPE_BODY_BLOCK_START = 16; + public static final byte INNER_TYPE_BODY_BLOCK_END = 17; + public static final byte INNER_TYPE_BODY_BLOCK_START_END = 18; + + public static final byte METHOD_BODY_BLOCK_START = 19; + public static final byte METHOD_BODY_BLOCK_END = 20; + public static final byte METHOD_BODY_BLOCK_START_END = 21; + + public static final byte METHOD_BODY_SINGLE_LINE_BLOCK_START = 22; + public static final byte METHOD_BODY_SINGLE_LINE_BLOCK_END = 23; + + public static final byte STATEMENTS_BLOCK_START = 25; + public static final byte STATEMENTS_BLOCK_END = 26; + public static final byte STATEMENTS_BLOCK_START_END = 27; + + public static final byte SINGLE_STATEMENT_BLOCK_START = 28; + public static final byte SINGLE_STATEMENT_BLOCK_END = 29; + public static final byte SINGLE_STATEMENTS_BLOCK_START_END = 30; + + public static final byte SWITCH_BLOCK_START = 31; + public static final byte SWITCH_BLOCK_END = 32; + + public static final byte CASE_BLOCK_START = 33; + public static final byte CASE_BLOCK_END = 34; + + public static final byte FOR_BLOCK_START = 37; + public static final byte FOR_BLOCK_END = 38; + + public static final byte COMMENT_DEPRECATED = 39; + public static final byte COMMENT_ERROR = 40; + + public static final byte ANNOTATIONS = 41; + + public static final byte TYPE_NAME = 42; + public static final byte EXTENDS_SUPER_TYPE = 43; + public static final byte EXTENDS_SUPER_INTERFACES = 44; + public static final byte IMPLEMENTS_INTERFACES = 45; + + public static final byte GENERIC_TYPE_NAME = 46; + public static final byte GENERIC_EXTENDS_SUPER_TYPE = 47; + public static final byte GENERIC_EXTENDS_SUPER_INTERFACES = 48; + public static final byte GENERIC_IMPLEMENTS_INTERFACES = 49; + + public static final byte FIELD_NAME = 50; + + public static final byte METHOD_STATIC = 51; + + public static final byte METHOD_NAME = 52; + public static final byte THROWS = 53; + + public static final byte INSTRUCTION = 54; + public static final byte INSTRUCTIONS = 55; + public static final byte BYTE_CODE = 56; + public static final byte DECLARE = 57; + + public static final byte SUBLIST_FIELD = 58; + public static final byte SUBLIST_METHOD = 59; + public static final byte SUBLIST_INNER_CLASS = 60; + + public static final byte FRAGMENT_WHILE = 61; + public static final byte FRAGMENT_FOR = 62; + public static final byte FRAGMENT_IF = 63; + public static final byte FRAGMENT_SWITCH = 64; + public static final byte FRAGMENT_CASE = 65; + public static final byte FRAGMENT_CASE_ENUM = 66; + public static final byte FRAGMENT_CASE_STRING = 67; + public static final byte FRAGMENT_CATCH = 68; + public static final byte FRAGMENT_SYNCHRONIZED = 69; + public static final byte STATEMENT_LABEL = 70; + + public static final byte FRAGMENT_ELSE = 71; + public static final byte FRAGMENT_ELSE_SPACE = 72; + public static final byte FRAGMENT_DO = 73; + public static final byte FRAGMENT_INFINITE_LOOP = 74; + public static final byte FRAGMENT_TRY = 75; + public static final byte FRAGMENT_FINALLY = 76; + public static final byte FRAGMENT_CONTINUE = 77; + public static final byte FRAGMENT_BREAK = 78; + public static final byte FRAGMENT_LABELED_BREAK = 79; + + public static final byte FRAGMENT_RIGHT_ROUND_BRACKET = 80; + public static final byte FRAGMENT_RIGHT_ROUND_BRACKET_SEMICOLON = 81; + public static final byte FRAGMENT_SEMICOLON = 82; + public static final byte FRAGMENT_SEMICOLON_SPACE = 83; + public static final byte FRAGMENT_SPACE_COLON_SPACE = 84; + public static final byte FRAGMENT_COMA_SPACE = 85; + + public static final int UNLIMITED_LINE_COUNT = Integer.MAX_VALUE; +} diff --git a/src/jd/core/model/layout/block/MarkerLayoutBlock.java b/src/jd/core/model/layout/block/MarkerLayoutBlock.java new file mode 100644 index 00000000..e71bc5cd --- /dev/null +++ b/src/jd/core/model/layout/block/MarkerLayoutBlock.java @@ -0,0 +1,21 @@ +package jd.core.model.layout.block; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class MarkerLayoutBlock extends LayoutBlock +{ + public ClassFile classFile; + public MarkerLayoutBlock other; + + public MarkerLayoutBlock(byte tag, ClassFile classFile) + { + super( + tag, + Instruction.UNKNOWN_LINE_NUMBER, Instruction.UNKNOWN_LINE_NUMBER, + 0, 0, 0); + this.classFile = classFile; + this.other = null; + } +} diff --git a/src/jd/core/model/layout/block/MethodBodyBlockEndLayoutBlock.java b/src/jd/core/model/layout/block/MethodBodyBlockEndLayoutBlock.java new file mode 100644 index 00000000..36778e12 --- /dev/null +++ b/src/jd/core/model/layout/block/MethodBodyBlockEndLayoutBlock.java @@ -0,0 +1,12 @@ +package jd.core.model.layout.block; + + +public class MethodBodyBlockEndLayoutBlock extends BlockLayoutBlock +{ + public MethodBodyBlockEndLayoutBlock() + { + super( + LayoutBlockConstants.METHOD_BODY_BLOCK_END, 0, + LayoutBlockConstants.UNLIMITED_LINE_COUNT, 1); + } +} diff --git a/src/jd/core/model/layout/block/MethodBodyBlockStartLayoutBlock.java b/src/jd/core/model/layout/block/MethodBodyBlockStartLayoutBlock.java new file mode 100644 index 00000000..7293f101 --- /dev/null +++ b/src/jd/core/model/layout/block/MethodBodyBlockStartLayoutBlock.java @@ -0,0 +1,28 @@ +package jd.core.model.layout.block; + + +public class MethodBodyBlockStartLayoutBlock extends BlockLayoutBlock +{ + public MethodBodyBlockStartLayoutBlock() + { + this(2); + } + + public MethodBodyBlockStartLayoutBlock(int preferedLineCount) + { + super( + LayoutBlockConstants.METHOD_BODY_BLOCK_START, 0, + LayoutBlockConstants.UNLIMITED_LINE_COUNT, preferedLineCount); + } + + public void transformToStartEndBlock(int preferedLineCount) + { + this.tag = LayoutBlockConstants.METHOD_BODY_BLOCK_START_END; + this.preferedLineCount = this.lineCount = preferedLineCount; + } + + public void transformToSingleLineBlock() + { + this.tag = LayoutBlockConstants.METHOD_BODY_SINGLE_LINE_BLOCK_START; + } +} diff --git a/src/jd/core/model/layout/block/MethodBodySingleLineBlockEndLayoutBlock.java b/src/jd/core/model/layout/block/MethodBodySingleLineBlockEndLayoutBlock.java new file mode 100644 index 00000000..046a4b53 --- /dev/null +++ b/src/jd/core/model/layout/block/MethodBodySingleLineBlockEndLayoutBlock.java @@ -0,0 +1,12 @@ +package jd.core.model.layout.block; + + +public class MethodBodySingleLineBlockEndLayoutBlock extends BlockLayoutBlock +{ + public MethodBodySingleLineBlockEndLayoutBlock() + { + super( + LayoutBlockConstants.METHOD_BODY_SINGLE_LINE_BLOCK_END, 0, + LayoutBlockConstants.UNLIMITED_LINE_COUNT, 1); + } +} diff --git a/src/jd/core/model/layout/block/MethodNameLayoutBlock.java b/src/jd/core/model/layout/block/MethodNameLayoutBlock.java new file mode 100644 index 00000000..258e27ea --- /dev/null +++ b/src/jd/core/model/layout/block/MethodNameLayoutBlock.java @@ -0,0 +1,29 @@ +package jd.core.model.layout.block; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.instruction.Instruction; + +public class MethodNameLayoutBlock extends LayoutBlock +{ + public ClassFile classFile; + public Method method; + public String signature; + public boolean descriptorFlag; + public boolean nullCodeFlag; + + public MethodNameLayoutBlock( + ClassFile classFile, Method method, + String signature, boolean descriptorFlag, boolean nullCodeFlag) + { + super( + LayoutBlockConstants.METHOD_NAME, + Instruction.UNKNOWN_LINE_NUMBER, Instruction.UNKNOWN_LINE_NUMBER, + 0, 0, 0); + this.classFile = classFile; + this.method = method; + this.signature = signature; + this.descriptorFlag = descriptorFlag; + this.nullCodeFlag = nullCodeFlag; + } +} diff --git a/src/jd/core/model/layout/block/MethodStaticLayoutBlock.java b/src/jd/core/model/layout/block/MethodStaticLayoutBlock.java new file mode 100644 index 00000000..b5d96bca --- /dev/null +++ b/src/jd/core/model/layout/block/MethodStaticLayoutBlock.java @@ -0,0 +1,18 @@ +package jd.core.model.layout.block; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.instruction.bytecode.instruction.Instruction; + +public class MethodStaticLayoutBlock extends LayoutBlock +{ + public ClassFile classFile; + + public MethodStaticLayoutBlock(ClassFile classFile) + { + super( + LayoutBlockConstants.METHOD_STATIC, + Instruction.UNKNOWN_LINE_NUMBER, Instruction.UNKNOWN_LINE_NUMBER, + 0, 0, 0); + this.classFile = classFile; + } +} diff --git a/src/jd/core/model/layout/block/OffsetLayoutBlock.java b/src/jd/core/model/layout/block/OffsetLayoutBlock.java new file mode 100644 index 00000000..5e23845b --- /dev/null +++ b/src/jd/core/model/layout/block/OffsetLayoutBlock.java @@ -0,0 +1,18 @@ +package jd.core.model.layout.block; + + +public class OffsetLayoutBlock extends LayoutBlock +{ + public int offset; + + public OffsetLayoutBlock( + byte tag, int firstLineNumber, int lastLineNumber, + int minimalLineCount, int maximalLineCount, int preferedLineCount, + int offset) + { + super( + tag, firstLineNumber, lastLineNumber, + minimalLineCount, maximalLineCount, preferedLineCount); + this.offset = offset; + } +} diff --git a/src/jd/core/model/layout/block/PackageLayoutBlock.java b/src/jd/core/model/layout/block/PackageLayoutBlock.java new file mode 100644 index 00000000..339892cc --- /dev/null +++ b/src/jd/core/model/layout/block/PackageLayoutBlock.java @@ -0,0 +1,18 @@ +package jd.core.model.layout.block; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.instruction.bytecode.instruction.Instruction; + +public class PackageLayoutBlock extends LayoutBlock +{ + public ClassFile classFile; + + public PackageLayoutBlock(ClassFile classFile) + { + super( + LayoutBlockConstants.PACKAGE, + Instruction.UNKNOWN_LINE_NUMBER, Instruction.UNKNOWN_LINE_NUMBER, + 0, 0, 0); + this.classFile = classFile; + } +} diff --git a/src/jd/core/model/layout/block/SeparatorLayoutBlock.java b/src/jd/core/model/layout/block/SeparatorLayoutBlock.java new file mode 100644 index 00000000..fac8692e --- /dev/null +++ b/src/jd/core/model/layout/block/SeparatorLayoutBlock.java @@ -0,0 +1,14 @@ +package jd.core.model.layout.block; + +import jd.core.model.instruction.bytecode.instruction.Instruction; + +public class SeparatorLayoutBlock extends LayoutBlock +{ + public SeparatorLayoutBlock(byte tag, int preferedLineCount) + { + super( + tag, + Instruction.UNKNOWN_LINE_NUMBER, Instruction.UNKNOWN_LINE_NUMBER, + 0, LayoutBlockConstants.UNLIMITED_LINE_COUNT, preferedLineCount); + } +} diff --git a/src/jd/core/model/layout/block/SingleStatementBlockEndLayoutBlock.java b/src/jd/core/model/layout/block/SingleStatementBlockEndLayoutBlock.java new file mode 100644 index 00000000..7eb7967d --- /dev/null +++ b/src/jd/core/model/layout/block/SingleStatementBlockEndLayoutBlock.java @@ -0,0 +1,12 @@ +package jd.core.model.layout.block; + + +public class SingleStatementBlockEndLayoutBlock extends BlockLayoutBlock +{ + public SingleStatementBlockEndLayoutBlock(int preferedLineCount) + { + super( + LayoutBlockConstants.SINGLE_STATEMENT_BLOCK_END, 0, + LayoutBlockConstants.UNLIMITED_LINE_COUNT, preferedLineCount); + } +} diff --git a/src/jd/core/model/layout/block/SingleStatementBlockStartLayoutBlock.java b/src/jd/core/model/layout/block/SingleStatementBlockStartLayoutBlock.java new file mode 100644 index 00000000..1934b285 --- /dev/null +++ b/src/jd/core/model/layout/block/SingleStatementBlockStartLayoutBlock.java @@ -0,0 +1,12 @@ +package jd.core.model.layout.block; + + +public class SingleStatementBlockStartLayoutBlock extends BlockLayoutBlock +{ + public SingleStatementBlockStartLayoutBlock() + { + super( + LayoutBlockConstants.SINGLE_STATEMENT_BLOCK_START, 0, + LayoutBlockConstants.UNLIMITED_LINE_COUNT, 1); + } +} diff --git a/src/jd/core/model/layout/block/StatementsBlockEndLayoutBlock.java b/src/jd/core/model/layout/block/StatementsBlockEndLayoutBlock.java new file mode 100644 index 00000000..c6a29526 --- /dev/null +++ b/src/jd/core/model/layout/block/StatementsBlockEndLayoutBlock.java @@ -0,0 +1,12 @@ +package jd.core.model.layout.block; + + +public class StatementsBlockEndLayoutBlock extends BlockLayoutBlock +{ + public StatementsBlockEndLayoutBlock(int preferedLineCount) + { + super( + LayoutBlockConstants.STATEMENTS_BLOCK_END, 0, + LayoutBlockConstants.UNLIMITED_LINE_COUNT, preferedLineCount); + } +} diff --git a/src/jd/core/model/layout/block/StatementsBlockStartLayoutBlock.java b/src/jd/core/model/layout/block/StatementsBlockStartLayoutBlock.java new file mode 100644 index 00000000..4d0912ac --- /dev/null +++ b/src/jd/core/model/layout/block/StatementsBlockStartLayoutBlock.java @@ -0,0 +1,23 @@ +package jd.core.model.layout.block; + + +public class StatementsBlockStartLayoutBlock extends BlockLayoutBlock +{ + public StatementsBlockStartLayoutBlock() + { + this(2); + } + + public StatementsBlockStartLayoutBlock(int preferedLineCount) + { + super( + LayoutBlockConstants.STATEMENTS_BLOCK_START, 0, + LayoutBlockConstants.UNLIMITED_LINE_COUNT, preferedLineCount); + } + + public void transformToStartEndBlock(int preferedLineCount) + { + this.tag = LayoutBlockConstants.STATEMENTS_BLOCK_START_END; + this.preferedLineCount = this.lineCount = preferedLineCount; + } +} diff --git a/src/jd/core/model/layout/block/SubListLayoutBlock.java b/src/jd/core/model/layout/block/SubListLayoutBlock.java new file mode 100644 index 00000000..c88420a4 --- /dev/null +++ b/src/jd/core/model/layout/block/SubListLayoutBlock.java @@ -0,0 +1,18 @@ +package jd.core.model.layout.block; + +import java.util.List; + +public class SubListLayoutBlock extends LayoutBlock +{ + public List subList; + + public SubListLayoutBlock( + byte tag, List subList, + int firstLineNumber, int lastLineNumber, int preferedLineCount) + { + super( + tag, firstLineNumber, lastLineNumber, + 0, preferedLineCount, preferedLineCount); + this.subList = subList; + } +} diff --git a/src/jd/core/model/layout/block/SwitchBlockEndLayoutBlock.java b/src/jd/core/model/layout/block/SwitchBlockEndLayoutBlock.java new file mode 100644 index 00000000..655f7926 --- /dev/null +++ b/src/jd/core/model/layout/block/SwitchBlockEndLayoutBlock.java @@ -0,0 +1,10 @@ +package jd.core.model.layout.block; + + +public class SwitchBlockEndLayoutBlock extends BlockLayoutBlock +{ + public SwitchBlockEndLayoutBlock() + { + super(LayoutBlockConstants.SWITCH_BLOCK_END, 0, 0, 0); + } +} diff --git a/src/jd/core/model/layout/block/SwitchBlockStartLayoutBlock.java b/src/jd/core/model/layout/block/SwitchBlockStartLayoutBlock.java new file mode 100644 index 00000000..8aeb829a --- /dev/null +++ b/src/jd/core/model/layout/block/SwitchBlockStartLayoutBlock.java @@ -0,0 +1,12 @@ +package jd.core.model.layout.block; + + +public class SwitchBlockStartLayoutBlock extends BlockLayoutBlock +{ + public SwitchBlockStartLayoutBlock() + { + super( + LayoutBlockConstants.SWITCH_BLOCK_START, 0, + LayoutBlockConstants.UNLIMITED_LINE_COUNT, 2); + } +} diff --git a/src/jd/core/model/layout/block/ThrowsLayoutBlock.java b/src/jd/core/model/layout/block/ThrowsLayoutBlock.java new file mode 100644 index 00000000..a2c489ff --- /dev/null +++ b/src/jd/core/model/layout/block/ThrowsLayoutBlock.java @@ -0,0 +1,24 @@ +package jd.core.model.layout.block; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.instruction.Instruction; + +public class ThrowsLayoutBlock extends LayoutBlock +{ + public ClassFile classFile; + public Method method; + public boolean nullCodeFlag; + + public ThrowsLayoutBlock( + ClassFile classFile, Method method, boolean nullCodeFlag) + { + super( + LayoutBlockConstants.THROWS, + Instruction.UNKNOWN_LINE_NUMBER, Instruction.UNKNOWN_LINE_NUMBER, + 0, 1, 1); + this.classFile = classFile; + this.method = method; + this.nullCodeFlag = nullCodeFlag; + } +} diff --git a/src/jd/core/model/layout/block/TypeBodyBlockEndLayoutBlock.java b/src/jd/core/model/layout/block/TypeBodyBlockEndLayoutBlock.java new file mode 100644 index 00000000..ea307fab --- /dev/null +++ b/src/jd/core/model/layout/block/TypeBodyBlockEndLayoutBlock.java @@ -0,0 +1,17 @@ +package jd.core.model.layout.block; + + +public class TypeBodyBlockEndLayoutBlock extends BlockLayoutBlock +{ + public TypeBodyBlockEndLayoutBlock() + { + this(1); + } + + public TypeBodyBlockEndLayoutBlock(int preferedLineCount) + { + super( + LayoutBlockConstants.TYPE_BODY_BLOCK_END, + 0, 1, preferedLineCount); + } +} diff --git a/src/jd/core/model/layout/block/TypeBodyBlockStartLayoutBlock.java b/src/jd/core/model/layout/block/TypeBodyBlockStartLayoutBlock.java new file mode 100644 index 00000000..bd367931 --- /dev/null +++ b/src/jd/core/model/layout/block/TypeBodyBlockStartLayoutBlock.java @@ -0,0 +1,23 @@ +package jd.core.model.layout.block; + + +public class TypeBodyBlockStartLayoutBlock extends BlockLayoutBlock +{ + public TypeBodyBlockStartLayoutBlock() + { + this(2); + } + + public TypeBodyBlockStartLayoutBlock(int preferedLineCount) + { + super( + LayoutBlockConstants.TYPE_BODY_BLOCK_START, + 0, 2, preferedLineCount); + } + + public void transformToStartEndBlock(int preferedLineCount) + { + this.tag = LayoutBlockConstants.TYPE_BODY_BLOCK_START_END; + this.preferedLineCount = this.lineCount = preferedLineCount; + } +} diff --git a/src/jd/core/model/layout/block/TypeNameLayoutBlock.java b/src/jd/core/model/layout/block/TypeNameLayoutBlock.java new file mode 100644 index 00000000..f3880e71 --- /dev/null +++ b/src/jd/core/model/layout/block/TypeNameLayoutBlock.java @@ -0,0 +1,28 @@ +package jd.core.model.layout.block; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.instruction.bytecode.instruction.Instruction; + +public class TypeNameLayoutBlock extends LayoutBlock +{ + public ClassFile classFile; + + public TypeNameLayoutBlock(ClassFile classFile) + { + this( + LayoutBlockConstants.TYPE_NAME, + Instruction.UNKNOWN_LINE_NUMBER, Instruction.UNKNOWN_LINE_NUMBER, + 0, 0, 0, classFile); + } + + protected TypeNameLayoutBlock( + byte tag, int firstLineNumber, int lastLineNumber, + int minimalLineCount, int maximalLineCount, + int preferedLineCount, ClassFile classFile) + { + super( + tag, firstLineNumber, lastLineNumber, + minimalLineCount, maximalLineCount, preferedLineCount); + this.classFile = classFile; + } +} diff --git a/src/jd/core/model/layout/section/LayoutSection.java b/src/jd/core/model/layout/section/LayoutSection.java new file mode 100644 index 00000000..f9432c78 --- /dev/null +++ b/src/jd/core/model/layout/section/LayoutSection.java @@ -0,0 +1,39 @@ +package jd.core.model.layout.section; + + +public class LayoutSection implements Comparable +{ + public int index; + public int firstBlockIndex; + public int lastBlockIndex; + + public final int originalLineCount; + + public boolean relayout; + public int score; + public boolean containsError; + // + public int debugFirstLineNumber; + + public LayoutSection( + int index, + int firstBlockIndex, int lastBlockIndex, + int firstLineNumber, int lastLineNumber, + boolean containsError) + { + this.index = index; + this.firstBlockIndex = firstBlockIndex; + this.lastBlockIndex = lastBlockIndex; + this.originalLineCount = lastLineNumber - firstLineNumber; + this.relayout = true; + this.score = 0; + this.containsError = containsError; + // + this.debugFirstLineNumber = firstLineNumber; + } + + public int compareTo(LayoutSection o) + { + return ((LayoutSection)o).score - this.score; + } +} diff --git a/src/jd/core/model/reference/Reference.java b/src/jd/core/model/reference/Reference.java new file mode 100644 index 00000000..0c879118 --- /dev/null +++ b/src/jd/core/model/reference/Reference.java @@ -0,0 +1,34 @@ +package jd.core.model.reference; + + +public class Reference +{ + private String internalName; + private int counter; + + Reference(String internalName) + { + this.internalName = internalName; + this.counter = 1; + } + + public String getInternalName() + { + return this.internalName; + } + + public int getCounter() + { + return this.counter; + } + + public void incCounter() + { + this.counter++; + } + +// public String toString() +// { +// return this.internalName + '#' + this.counter; +// } +} diff --git a/src/jd/core/model/reference/ReferenceMap.java b/src/jd/core/model/reference/ReferenceMap.java new file mode 100644 index 00000000..d52b0b1d --- /dev/null +++ b/src/jd/core/model/reference/ReferenceMap.java @@ -0,0 +1,57 @@ +package jd.core.model.reference; + +import java.util.Collection; +import java.util.HashMap; + + + + +public class ReferenceMap +{ + private HashMap references; + + public ReferenceMap() + { + this.references = new HashMap(); + } + + public void add(String internalName) + { + if (internalName.indexOf(';') != -1) + { + System.err.println( + "ReferenceMap.add: InvalidParameterException(" + + internalName + ")"); + // throw new InvalidParameterException(internalName); + } + else + { + Reference ref = this.references.get(internalName); + + if (ref == null) + this.references.put(internalName, new Reference(internalName)); + else + ref.incCounter(); + } + } + + public Reference remove(String internalName) + { + return this.references.remove(internalName); + } + + public Collection values() + { + return this.references.values(); + } + +// public String toString() +// { +// return this.references.values().toString(); +// } + + public boolean contains(String internalName) + { + return this.references.containsKey(internalName); + } +} diff --git a/src/jd/core/preferences/Preferences.java b/src/jd/core/preferences/Preferences.java new file mode 100644 index 00000000..3a004256 --- /dev/null +++ b/src/jd/core/preferences/Preferences.java @@ -0,0 +1,31 @@ +package jd.core.preferences; + + +public class Preferences +{ + protected boolean showDefaultConstructor; + protected boolean realignmentLineNumber; + + public Preferences() + { + this.showDefaultConstructor = false; + this.realignmentLineNumber = true; + } + + public Preferences( + boolean showDefaultConstructor, boolean realignmentLineNumber) + { + this.showDefaultConstructor = showDefaultConstructor; + this.realignmentLineNumber = realignmentLineNumber; + } + + public boolean getShowDefaultConstructor() + { + return this.showDefaultConstructor; + } + + public boolean getRealignmentLineNumber() + { + return this.realignmentLineNumber; + } +} diff --git a/src/jd/core/printer/InstructionPrinter.java b/src/jd/core/printer/InstructionPrinter.java new file mode 100644 index 00000000..6a91f66f --- /dev/null +++ b/src/jd/core/printer/InstructionPrinter.java @@ -0,0 +1,353 @@ +package jd.core.printer; + +import java.util.ArrayList; + + +public class InstructionPrinter implements Printer +{ + protected Printer printer; + private int previousLineNumber; + private boolean newInstruction; + private boolean multiLineInstruction; + private boolean active; + private ArrayList states; + + /* + * L'etat se reduit a "multiLineInstruction" + * --> Optimisation: utilisation de Boolean a la place de State. + private static class State + { + public boolean newInstruction; + public boolean multiLineInstruction; + + public State(boolean newInstruction, boolean multiLineInstruction) + { + this.newInstruction = newInstruction; + this.multiLineInstruction = multiLineInstruction; + } + } */ + + // ------------------------------------------------------------------------- + public InstructionPrinter(Printer printer) + { + this.printer = printer; + this.active = false; + this.states = new ArrayList(0); + } + + public void init(int previousLineNumber) + { + this.previousLineNumber = previousLineNumber; + this.newInstruction = false; + this.multiLineInstruction = false; + this.active = false; + } + + public void startOfInstruction() + { + this.active = true; + } + + public void addNewLinesAndPrefix(int lineNumber) + { + if (this.active == false) + { + // Instruction non commenc�e, e cours d'affichage. Restoration de + // l'�tat precedant. + this.multiLineInstruction = this.states.remove(this.states.size()-1).booleanValue(); + /* State state = this.states.remove(this.states.size()-1); + this.newInstruction = state.newInstruction; + this.multiLineInstruction = state.multiLineInstruction; */ + this.active = true; + } + + if (lineNumber == UNKNOWN_LINE_NUMBER) + { + if (this.newInstruction) + { + if (this.previousLineNumber == UNKNOWN_LINE_NUMBER) + { + this.printer.endOfLine(); + this.printer.startOfLine(lineNumber); + } + else + { + this.printer.print(' '); + } + } + } + else + { + if (this.previousLineNumber == UNKNOWN_LINE_NUMBER) + { + this.previousLineNumber = lineNumber; + } + else + { + if (this.previousLineNumber < lineNumber) + { + int lineCount = lineNumber - this.previousLineNumber; + + this.printer.endOfLine(); + + if (lineCount > 1) + { + this.printer.startOfLine(Printer.UNKNOWN_LINE_NUMBER); + this.printer.endOfLine(); + + if (lineCount > 2) + { + this.printer.extraLine(lineCount-2); + } + } + + if ((this.newInstruction == false) && + (this.multiLineInstruction == false)) + { + this.printer.indent(); + this.multiLineInstruction = true; + } + + this.printer.startOfLine(lineNumber); + + this.previousLineNumber = lineNumber; + } + } + } + + this.newInstruction = false; + } + + public void endOfInstruction() + { + if (this.multiLineInstruction) + { + this.printer.desindent(); + } + + this.newInstruction = true; + this.multiLineInstruction = false; + this.active = false; + } + + public void release() + { + if (this.active == true) + { + // Instruction non termin�e. Sauvegarde de l'�tat courant. + this.states.add(Boolean.valueOf(this.multiLineInstruction)); + /* this.states.add( + new State(this.newInstruction, this.multiLineInstruction)); */ + } + } + + // ------------------------------------------------------------------------- + public void print(int lineNumber, byte b) + { + addNewLinesAndPrefix(lineNumber); + this.printer.print(b); + } + + public void print(int lineNumber, char c) + { + addNewLinesAndPrefix(lineNumber); + this.printer.print(c); + } + + public void print(int lineNumber, int i) + { + addNewLinesAndPrefix(lineNumber); + this.printer.print(i); + } + + public void print(int lineNumber, String s) + { + addNewLinesAndPrefix(lineNumber); + this.printer.print(s); + } + + public void printNumeric(int lineNumber, String s) + { + addNewLinesAndPrefix(lineNumber); + this.printer.printNumeric(s); + } + + public void printString(int lineNumber, String s, String scopeInternalName) + { + addNewLinesAndPrefix(lineNumber); + this.printer.printString(s, scopeInternalName); + } + + public void printKeyword(int lineNumber, String keyword) + { + addNewLinesAndPrefix(lineNumber); + this.printer.printKeyword(keyword); + } + + public void printType( + int lineNumber, String internalName, + String name, String scopeInternalName) + { + addNewLinesAndPrefix(lineNumber); + this.printer.printType(internalName, name, scopeInternalName); + } + + public void printField( + int lineNumber, String internalName, String name, + String descriptor, String scopeInternalName) + { + addNewLinesAndPrefix(lineNumber); + this.printer.printField( + internalName, name, descriptor, scopeInternalName); + } + + public void printStaticField( + int lineNumber, String internalName, String name, + String descriptor, String scopeInternalName) + { + addNewLinesAndPrefix(lineNumber); + this.printer.printStaticField( + internalName, name, descriptor, scopeInternalName); + } + + public void printMethod( + int lineNumber, String internalName, String name, + String descriptor, String scopeInternalName) + { + addNewLinesAndPrefix(lineNumber); + this.printer.printMethod( + internalName, name, descriptor, scopeInternalName); + } + + public void printStaticMethod( + int lineNumber, String internalName, String name, + String descriptor, String scopeInternalName) + { + addNewLinesAndPrefix(lineNumber); + this.printer.printStaticMethod( + internalName, name, descriptor, scopeInternalName); + } + + // ------------------------------------------------------------------------- + public void print(byte b) { this.printer.print(b); } + public void print(char c) { this.printer.print(c); } + public void print(int i) { this.printer.print(i); } + public void print(String s) { this.printer.print(s); } + + public void printNumeric(String s) { this.printer.printNumeric(s); } + public void printString(String s, String scopeInternalName) { this.printer.printString(s, scopeInternalName); } + public void printKeyword(String keyword) { this.printer.printKeyword(keyword); } + public void printJavaWord(String s) { this.printer.printJavaWord(s); } + + // TODO pourquoi de temps en temps passer un 'internalName' et d'autre fois un 'internalPath'? comprendre les besoin de jd-gui. + public void printType(String internalName, String name, String scopeInternalName) + { this.printer.printType(internalName, name, scopeInternalName); } + public void printTypeDeclaration(String internalName, String name) + { this.printer.printTypeDeclaration(internalName, name); } + public void printTypeImport(String internalName, String name) + { this.printer.printTypeImport(internalName, name); } + + public void printField( + String internalName, String name, + String descriptor, String scopeInternalName) + { this.printer.printField(internalName, name, descriptor, scopeInternalName); } + public void printFieldDeclaration( + String internalName, String name, String descriptor) + { this.printer.printFieldDeclaration(internalName, name, descriptor); } + + public void printStaticField( + String internalName, String name, + String descriptor, String scopeInternalName) + { this.printer.printStaticField(internalName, name, descriptor, scopeInternalName); } + public void printStaticFieldDeclaration( + String internalName, String name, String descriptor) + { this.printer.printStaticFieldDeclaration(internalName, name, descriptor); } + + public void printConstructor( + String internalName, String name, + String descriptor, String scopeInternalName) + { this.printer.printConstructor(internalName, name, descriptor, scopeInternalName); } + public void printConstructorDeclaration( + String internalName, String name, String descriptor) + { this.printer.printConstructorDeclaration(internalName, name, descriptor); } + public void printStaticConstructorDeclaration( + String internalName, String name) + { this.printer.printStaticConstructorDeclaration(internalName, name); } + + public void printMethod( + String internalName, String name, + String descriptor, String scopeInternalName) + { this.printer.printMethod(internalName, name, descriptor, scopeInternalName); } + public void printMethodDeclaration( + String internalName, String name, String descriptor) + { this.printer.printMethodDeclaration(internalName, name, descriptor); } + + public void printStaticMethod( + String internalName, String name, + String descriptor, String scopeInternalName) + { this.printer.printStaticMethod(internalName, name, descriptor, scopeInternalName); } + public void printStaticMethodDeclaration( + String internalName, String name, String descriptor) + { this.printer.printStaticMethodDeclaration(internalName, name, descriptor); } + + public void start(int maxLineNumber, int majorVersion, int minorVersion) + { this.printer.start(maxLineNumber, majorVersion, minorVersion); } + public void end() { this.printer.end(); } + + public void indent() { this.printer.indent(); } + public void desindent() { this.printer.desindent(); } + + public void startOfLine(int lineNumber) + { this.printer.startOfLine(lineNumber); } + public void endOfLine() { this.printer.endOfLine(); } + public void extraLine(int count) { this.printer.extraLine(count); } + + public void startOfComment() { this.printer.startOfComment(); } + public void endOfComment() { this.printer.endOfComment(); } + + public void startOfJavadoc() { this.printer.startOfJavadoc(); } + public void endOfJavadoc() { this.printer.endOfJavadoc(); } + + public void startOfXdoclet() { this.printer.startOfXdoclet(); } + public void endOfXdoclet() { this.printer.endOfXdoclet(); } + + public void startOfError() { this.printer.startOfError(); } + public void endOfError() { this.printer.endOfError(); } + + public void startOfImportStatements() { this.printer.startOfImportStatements(); } + public void endOfImportStatements() { this.printer.endOfImportStatements(); } + + public void startOfTypeDeclaration(String internalPath) { this.printer.startOfTypeDeclaration(internalPath); } + public void endOfTypeDeclaration() { this.printer.endOfTypeDeclaration(); } + + public void startOfAnnotationName() { this.printer.startOfAnnotationName(); } + public void endOfAnnotationName() { this.printer.endOfAnnotationName(); } + + public void startOfOptionalPrefix() { this.printer.startOfOptionalPrefix(); } + public void endOfOptionalPrefix() { this.printer.endOfOptionalPrefix(); } + + public void debugStartOfLayoutBlock() { this.printer.debugStartOfLayoutBlock(); } + public void debugEndOfLayoutBlock() { this.printer.debugEndOfLayoutBlock(); } + public void debugStartOfSeparatorLayoutBlock() + { this.printer.debugStartOfSeparatorLayoutBlock(); } + public void debugEndOfSeparatorLayoutBlock(int min, int value, int max) + { this.printer.debugEndOfSeparatorLayoutBlock(min, value, max); } + public void debugStartOfStatementsBlockLayoutBlock() + { this.printer.debugStartOfStatementsBlockLayoutBlock(); } + public void debugEndOfStatementsBlockLayoutBlock(int min, int value, int max) + { this.printer.debugEndOfStatementsBlockLayoutBlock(min, value, max); } + public void debugStartOfInstructionBlockLayoutBlock() + { this.printer.debugStartOfInstructionBlockLayoutBlock(); } + public void debugEndOfInstructionBlockLayoutBlock() + { this.printer.debugEndOfInstructionBlockLayoutBlock(); } + public void debugStartOfCommentDeprecatedLayoutBlock() + { this.printer.debugStartOfCommentDeprecatedLayoutBlock(); } + public void debugEndOfCommentDeprecatedLayoutBlock() + { this.printer.debugEndOfCommentDeprecatedLayoutBlock(); } + public void debugMarker(String marker) + { this.printer.debugMarker(marker); } + public void debugEndOfCaseBlockLayoutBlock() + { this.printer.debugEndOfCaseBlockLayoutBlock(); } + public void debugStartOfCaseBlockLayoutBlock() + { this.printer.debugStartOfCaseBlockLayoutBlock(); } +} diff --git a/src/jd/core/printer/Printer.java b/src/jd/core/printer/Printer.java new file mode 100644 index 00000000..d36bc82d --- /dev/null +++ b/src/jd/core/printer/Printer.java @@ -0,0 +1,104 @@ +package jd.core.printer; + + +public interface Printer +{ + public static int UNKNOWN_LINE_NUMBER = 0; + + + public void print(byte b); + public void print(char c); + public void print(int i); + public void print(String s); + + public void printNumeric(String s); + public void printString(String s, String scopeInternalName); + + public void printKeyword(String keyword); + public void printJavaWord(String s); + + public void printType(String internalName, String name, String scopeInternalName); + public void printTypeDeclaration(String internalName, String name); + public void printTypeImport(String internalName, String name); + + public void printField( + String internalName, String name, + String descriptor, String scopeInternalName); + public void printFieldDeclaration( + String internalName, String name, String descriptor); + + public void printStaticField( + String internalName, String name, + String descriptor, String scopeInternalName); + public void printStaticFieldDeclaration( + String internalName, String name, String descriptor); + + public void printConstructor( + String internalName, String name, + String descriptor, String scopeInternalName); + public void printConstructorDeclaration( + String internalName, String name, String descriptor); + + public void printStaticConstructorDeclaration( + String internalName, String name); + + public void printMethod( + String internalName, String name, + String descriptor, String scopeInternalName); + public void printMethodDeclaration( + String internalName, String name, String descriptor); + + public void printStaticMethod( + String internalName, String name, + String descriptor, String scopeInternalName); + public void printStaticMethodDeclaration( + String internalName, String name, String descriptor); + + public void start(int maxLineNumber, int majorVersion, int minorVersion); + public void end(); + + public void indent(); + public void desindent(); + + public void startOfLine(int lineNumber); + public void endOfLine(); + public void extraLine(int count); + + public void startOfComment(); + public void endOfComment(); + + public void startOfJavadoc(); + public void endOfJavadoc(); + + public void startOfXdoclet(); + public void endOfXdoclet(); + + public void startOfError(); + public void endOfError(); + + public void startOfImportStatements(); + public void endOfImportStatements(); + + public void startOfTypeDeclaration(String internalPath); + public void endOfTypeDeclaration(); + + public void startOfAnnotationName(); + public void endOfAnnotationName(); + + public void startOfOptionalPrefix(); + public void endOfOptionalPrefix(); + + public void debugStartOfLayoutBlock(); + public void debugEndOfLayoutBlock(); + public void debugStartOfSeparatorLayoutBlock(); + public void debugEndOfSeparatorLayoutBlock(int min, int value, int max); + public void debugStartOfStatementsBlockLayoutBlock(); + public void debugEndOfStatementsBlockLayoutBlock(int min, int value, int max); + public void debugStartOfInstructionBlockLayoutBlock(); + public void debugEndOfInstructionBlockLayoutBlock(); + public void debugStartOfCommentDeprecatedLayoutBlock(); + public void debugEndOfCommentDeprecatedLayoutBlock(); + public void debugMarker(String marker); + public void debugStartOfCaseBlockLayoutBlock(); + public void debugEndOfCaseBlockLayoutBlock(); +} diff --git a/src/jd/core/process/DecompilerImpl.java b/src/jd/core/process/DecompilerImpl.java new file mode 100644 index 00000000..c39036dd --- /dev/null +++ b/src/jd/core/process/DecompilerImpl.java @@ -0,0 +1,59 @@ +package jd.core.process; + +import java.util.ArrayList; + +import jd.core.Decompiler; +import jd.core.loader.Loader; +import jd.core.loader.LoaderException; +import jd.core.model.classfile.ClassFile; +import jd.core.model.layout.block.LayoutBlock; +import jd.core.model.reference.ReferenceMap; +import jd.core.preferences.Preferences; +import jd.core.printer.Printer; +import jd.core.process.analyzer.classfile.ClassFileAnalyzer; +import jd.core.process.analyzer.classfile.ReferenceAnalyzer; +import jd.core.process.deserializer.ClassFileDeserializer; +import jd.core.process.layouter.ClassFileLayouter; +import jd.core.process.writer.ClassFileWriter; + +public class DecompilerImpl implements Decompiler +{ + public void decompile( + Preferences preferences, Loader loader, + Printer printer, String internalClassPath) + throws LoaderException + { +//long time0 = System.currentTimeMillis(); + + // 1) Deserialisation + ClassFile classFile = + ClassFileDeserializer.Deserialize(loader, internalClassPath); + if (classFile == null) + throw new LoaderException( + "Can not deserialize '" + internalClassPath + "'."); + + // 2) Analyse du byte code + ReferenceMap referenceMap = new ReferenceMap(); + ClassFileAnalyzer.Analyze(referenceMap, classFile); + + // 3) Creation de la liste des references pour generer la liste des + // "import" + ReferenceAnalyzer.Analyze(referenceMap, classFile); + + // 4) Mise en page du code source + ArrayList layoutBlockList = new ArrayList(1024); + int maxLineNumber = ClassFileLayouter.Layout( + preferences, referenceMap, classFile, layoutBlockList); + +//System.out.println("layoutBlockList.size = " + layoutBlockList.size()); + + // 5) Ecriture du code source + ClassFileWriter.Write( + loader, printer, referenceMap, maxLineNumber, + classFile.getMajorVersion(), classFile.getMinorVersion(), + layoutBlockList); + +//long time1 = System.currentTimeMillis(); +//System.out.println("time = " + (time1-time0) + " ms"); + } +} diff --git a/src/jd/core/process/analyzer/classfile/AccessorAnalyzer.java b/src/jd/core/process/analyzer/classfile/AccessorAnalyzer.java new file mode 100644 index 00000000..b4403ffc --- /dev/null +++ b/src/jd/core/process/analyzer/classfile/AccessorAnalyzer.java @@ -0,0 +1,384 @@ +package jd.core.process.analyzer.classfile; + +import java.util.List; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.Method; +import jd.core.model.classfile.accessor.AccessorConstants; +import jd.core.model.classfile.accessor.GetFieldAccessor; +import jd.core.model.classfile.accessor.GetStaticAccessor; +import jd.core.model.classfile.accessor.InvokeMethodAccessor; +import jd.core.model.classfile.accessor.PutFieldAccessor; +import jd.core.model.classfile.accessor.PutStaticAccessor; +import jd.core.model.classfile.constant.ConstantFieldref; +import jd.core.model.classfile.constant.ConstantMethodref; +import jd.core.model.classfile.constant.ConstantNameAndType; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.ALoad; +import jd.core.model.instruction.bytecode.instruction.GetField; +import jd.core.model.instruction.bytecode.instruction.GetStatic; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.InvokeInstruction; +import jd.core.model.instruction.bytecode.instruction.InvokeNoStaticInstruction; +import jd.core.model.instruction.bytecode.instruction.PutField; +import jd.core.model.instruction.bytecode.instruction.PutStatic; +import jd.core.model.instruction.bytecode.instruction.ReturnInstruction; +import jd.core.util.SignatureUtil; + +/* + * Recherche des accesseurs + */ +public class AccessorAnalyzer +{ + public static void Analyze(ClassFile classFile, Method method) + { + // Recherche des accesseurs de champs statiques + // static AuthenticatedSubject access$000() + if (SearchGetStaticAccessor(classFile, method) == true) + return; + + // Recherche des accesseurs de champs statiques + // static void access$0(int) + if (SearchPutStaticAccessor(classFile, method) == true) + return; + + // Recherche des accesseurs de champs + // static int access$1(TestInnerClass) + if (SearchGetFieldAccessor(classFile, method) == true) + return; + + // Recherche des accesseurs de champs + // static void access$0(TestInnerClass, int) + if (SearchPutFieldAccessor(classFile, method) == true) + return; + + // Recherche des accesseurs de methodes + // static void access$100(EntitlementFunctionLibrary, EvaluationCtx, URI, Bag, Bag[]) + SearchInvokeMethodAccessor(classFile, method); + } + + /* Recherche des accesseurs de champs statiques: + * static AuthenticatedSubject access$000() + * { + * Byte code: + * getstatic 3 com/bea/security/providers/xacml/entitlement/function/EntitlementFunctionLibrary:kernelId Lweblogic/security/acl/internal/AuthenticatedSubject; + * areturn + * } + */ + private static boolean SearchGetStaticAccessor( + ClassFile classFile, Method method) + { + List list = method.getInstructions(); + if (list.size() != 1) + return false; + + Instruction instruction = list.get(0); + if (instruction.opcode != ByteCodeConstants.XRETURN) + return false; + + instruction = ((ReturnInstruction)instruction).valueref; + if (instruction.opcode != ByteCodeConstants.GETSTATIC) + return false; + + ConstantPool constants = classFile.getConstantPool(); + ConstantFieldref cfr = constants.getConstantFieldref( + ((GetStatic)instruction).index); + + if (cfr.class_index != classFile.getThisClassIndex()) + return false; + + String methodDescriptor = + constants.getConstantUtf8(method.descriptor_index); + if (methodDescriptor.charAt(1) != ')') + return false; + + String methodName = constants.getConstantUtf8(method.name_index); + + ConstantNameAndType cnat = constants.getConstantNameAndType( + cfr.name_and_type_index); + + String fieldDescriptor = constants.getConstantUtf8(cnat.descriptor_index); + String fieldName = constants.getConstantUtf8(cnat.name_index); + + // Trouve ! Ajout de l'accesseur. + classFile.addAccessor(methodName, methodDescriptor, + new GetStaticAccessor( + AccessorConstants.ACCESSOR_GETSTATIC, + classFile.getThisClassName(), fieldName, fieldDescriptor)); + + return true; + } + + /* Recherche des accesseurs de champs statiques: + * static void access$0(int) + * { + * Byte code: + * iload_0 + * putstatic 11 basic/data/TestInnerClass:test0 I + * return + * } + */ + private static boolean SearchPutStaticAccessor( + ClassFile classFile, Method method) + { + List list = method.getInstructions(); + if (list.size() != 2) + return false; + + if (list.get(1).opcode != ByteCodeConstants.RETURN) + return false; + + Instruction instruction = list.get(0); + if (instruction.opcode != ByteCodeConstants.PUTSTATIC) + return false; + + ConstantPool constants = classFile.getConstantPool(); + ConstantFieldref cfr = constants.getConstantFieldref( + ((PutStatic)instruction).index); + + if (cfr.class_index != classFile.getThisClassIndex()) + return false; + + String methodDescriptor = + constants.getConstantUtf8(method.descriptor_index); + if (methodDescriptor.charAt(1) == ')') + return false; + if (SignatureUtil.GetParameterSignatureCount(methodDescriptor) != 1) + return false; + + String methodName = constants.getConstantUtf8(method.name_index); + + ConstantNameAndType cnat = constants.getConstantNameAndType( + cfr.name_and_type_index); + + String fieldDescriptor = constants.getConstantUtf8(cnat.descriptor_index); + String fieldName = constants.getConstantUtf8(cnat.name_index); + + // Trouve ! Ajout de l'accesseur. + classFile.addAccessor(methodName, methodDescriptor, + new PutStaticAccessor( + AccessorConstants.ACCESSOR_PUTSTATIC, + classFile.getThisClassName(), fieldName, fieldDescriptor)); + + return true; + } + + /* Recherche des accesseurs de champs: + * static int access$1(TestInnerClass) + * { + * Byte code: + * aload_0 + * getfield 12 basic/data/TestInnerClass:test I + * ireturn + * } + */ + private static boolean SearchGetFieldAccessor( + ClassFile classFile, Method method) + { + List list = method.getInstructions(); + if (list.size() != 1) + return false; + + Instruction instruction = list.get(0); + if (instruction.opcode != ByteCodeConstants.XRETURN) + return false; + + instruction = ((ReturnInstruction)instruction).valueref; + if (instruction.opcode != ByteCodeConstants.GETFIELD) + return false; + + ConstantPool constants = classFile.getConstantPool(); + ConstantFieldref cfr = constants.getConstantFieldref( + ((GetField)instruction).index); + + if (cfr.class_index != classFile.getThisClassIndex()) + return false; + + String methodDescriptor = + constants.getConstantUtf8(method.descriptor_index); + if (methodDescriptor.charAt(1) == ')') + return false; + if (SignatureUtil.GetParameterSignatureCount(methodDescriptor) != 1) + return false; + + String methodName = constants.getConstantUtf8(method.name_index); + + ConstantNameAndType cnat = constants.getConstantNameAndType( + cfr.name_and_type_index); + + String fieldDescriptor = constants.getConstantUtf8(cnat.descriptor_index); + String fieldName = constants.getConstantUtf8(cnat.name_index); + + // Trouve ! Ajout de l'accesseur. + classFile.addAccessor(methodName, methodDescriptor, + new GetFieldAccessor( + AccessorConstants.ACCESSOR_GETFIELD, + classFile.getThisClassName(), fieldName, fieldDescriptor)); + + return true; + } + + /* Recherche des accesseurs de champs: + * static void access$0(TestInnerClass, int) + * { + * Byte code: + * aload_0 + * iload_1 + * putfield 13 basic/data/TestInnerClass:test I + * return + * } + */ + private static boolean SearchPutFieldAccessor( + ClassFile classFile, Method method) + { + List list = method.getInstructions(); + PutField pf; + + switch (list.size()) + { + case 2: + { + if (list.get(1).opcode != ByteCodeConstants.RETURN) + return false; + + Instruction instruction = list.get(0); + if (instruction.opcode != ByteCodeConstants.PUTFIELD) + return false; + + pf = (PutField)instruction; + } + break; + case 3: + { + if (list.get(0).opcode != ByteCodeConstants.DUPSTORE) + return false; + + if (list.get(2).opcode != ByteCodeConstants.XRETURN) + return false; + + Instruction instruction = list.get(1); + if (instruction.opcode != ByteCodeConstants.PUTFIELD) + return false; + + pf = (PutField)instruction; + } + break; + default: + return false; + } + + ConstantPool constants = classFile.getConstantPool(); + ConstantFieldref cfr = constants.getConstantFieldref(pf.index); + + if (cfr.class_index != classFile.getThisClassIndex()) + return false; + + String methodDescriptor = + constants.getConstantUtf8(method.descriptor_index); + if (methodDescriptor.charAt(1) == ')') + return false; + if (SignatureUtil.GetParameterSignatureCount(methodDescriptor) != 2) + return false; + + ConstantNameAndType cnat = constants.getConstantNameAndType( + cfr.name_and_type_index); + + String methodName = constants.getConstantUtf8(method.name_index); + String fieldDescriptor = constants.getConstantUtf8(cnat.descriptor_index); + String fieldName = constants.getConstantUtf8(cnat.name_index); + + // Trouve ! Ajout de l'accesseur. + classFile.addAccessor(methodName, methodDescriptor, + new PutFieldAccessor( + AccessorConstants.ACCESSOR_PUTFIELD, + classFile.getThisClassName(), fieldName, fieldDescriptor)); + + return true; + } + + /* Recherche des accesseurs de methodes: + * static void access$100(EntitlementFunctionLibrary, EvaluationCtx, URI, Bag, Bag[]) + * { + * Byte code: + * aload_0 + * aload_1 + * aload_2 + * aload_3 + * aload 4 + * invokevirtual 2 com/bea/security/providers/xacml/entitlement/function/EntitlementFunctionLibrary:debugEval (Lcom/bea/security/xacml/EvaluationCtx;Ljava/net/URI;Lcom/bea/common/security/xacml/attr/Bag;[Lcom/bea/common/security/xacml/attr/Bag;)V + * return + * } + */ + private static boolean SearchInvokeMethodAccessor( + ClassFile classFile, Method method) + { + List list = method.getInstructions(); + Instruction instruction; + + switch(list.size()) + { + case 1: + instruction = list.get(0); + if (instruction.opcode != ByteCodeConstants.XRETURN) + return false; + instruction = ((ReturnInstruction)instruction).valueref; + break; + case 2: + instruction = list.get(1); + if (instruction.opcode != ByteCodeConstants.RETURN) + return false; + instruction = list.get(0); + break; + default: + return false; + } + + InvokeInstruction ii; + + switch (instruction.opcode) + { + case ByteCodeConstants.INVOKEVIRTUAL: + case ByteCodeConstants.INVOKESPECIAL: + case ByteCodeConstants.INVOKEINTERFACE: + InvokeNoStaticInstruction insi = + (InvokeNoStaticInstruction)instruction; + + if ((insi.objectref.opcode != ByteCodeConstants.ALOAD) || + (((ALoad)insi.objectref).index != 0)) + return false; + + ii = insi; + break; + case ByteCodeConstants.INVOKESTATIC: + ii = (InvokeInstruction)instruction; + break; + default: + return false; + } + + ConstantPool constants = classFile.getConstantPool(); + + String methodName = constants.getConstantUtf8(method.name_index); + String methodDescriptor = + constants.getConstantUtf8(method.descriptor_index); + + ConstantMethodref cmr = constants.getConstantMethodref(ii.index); + ConstantNameAndType cnat = constants.getConstantNameAndType( + cmr.name_and_type_index); + + String targetMethodName = constants.getConstantUtf8(cnat.name_index); + String targetMethodDescriptor = + constants.getConstantUtf8(cnat.descriptor_index); + + // Trouve ! Ajout de l'accesseur. + classFile.addAccessor(methodName, methodDescriptor, + new InvokeMethodAccessor( + AccessorConstants.ACCESSOR_INVOKEMETHOD, classFile.getThisClassName(), + ii.opcode, targetMethodName, targetMethodDescriptor, + cmr.getListOfParameterSignatures(), + cmr.getReturnedSignature())); + + return true; + } +} diff --git a/src/jd/core/process/analyzer/classfile/ClassFileAnalyzer.java b/src/jd/core/process/analyzer/classfile/ClassFileAnalyzer.java new file mode 100644 index 00000000..d72ed32e --- /dev/null +++ b/src/jd/core/process/analyzer/classfile/ClassFileAnalyzer.java @@ -0,0 +1,1290 @@ +package jd.core.process.analyzer.classfile; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.ClassFileConstants; +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.Field; +import jd.core.model.classfile.Method; +import jd.core.model.classfile.attribute.AttributeSignature; +import jd.core.model.classfile.constant.Constant; +import jd.core.model.classfile.constant.ConstantConstant; +import jd.core.model.classfile.constant.ConstantFieldref; +import jd.core.model.classfile.constant.ConstantMethodref; +import jd.core.model.classfile.constant.ConstantNameAndType; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.ALoad; +import jd.core.model.instruction.bytecode.instruction.ArrayStoreInstruction; +import jd.core.model.instruction.bytecode.instruction.BinaryOperatorInstruction; +import jd.core.model.instruction.bytecode.instruction.GetField; +import jd.core.model.instruction.bytecode.instruction.GetStatic; +import jd.core.model.instruction.bytecode.instruction.IfCmp; +import jd.core.model.instruction.bytecode.instruction.IfInstruction; +import jd.core.model.instruction.bytecode.instruction.IndexInstruction; +import jd.core.model.instruction.bytecode.instruction.InitArrayInstruction; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.Invokespecial; +import jd.core.model.instruction.bytecode.instruction.Invokevirtual; +import jd.core.model.instruction.bytecode.instruction.Pop; +import jd.core.model.instruction.bytecode.instruction.PutField; +import jd.core.model.instruction.bytecode.instruction.PutStatic; +import jd.core.model.instruction.bytecode.instruction.ReturnInstruction; +import jd.core.model.instruction.fast.FastConstants; +import jd.core.model.instruction.fast.instruction.FastLabel; +import jd.core.model.reference.ReferenceMap; +import jd.core.process.analyzer.classfile.reconstructor.AssignmentInstructionReconstructor; +import jd.core.process.analyzer.classfile.reconstructor.DotClass118AReconstructor; +import jd.core.process.analyzer.classfile.reconstructor.DotClass14Reconstructor; +import jd.core.process.analyzer.classfile.reconstructor.DupStoreThisReconstructor; +import jd.core.process.analyzer.classfile.reconstructor.InitDexEnumFieldsReconstructor; +import jd.core.process.analyzer.classfile.reconstructor.InitInstanceFieldsReconstructor; +import jd.core.process.analyzer.classfile.reconstructor.InitStaticFieldsReconstructor; +import jd.core.process.analyzer.classfile.reconstructor.NewInstructionReconstructor; +import jd.core.process.analyzer.classfile.reconstructor.OuterReferenceReconstructor; +import jd.core.process.analyzer.classfile.reconstructor.PostIncReconstructor; +import jd.core.process.analyzer.classfile.reconstructor.PreIncReconstructor; +import jd.core.process.analyzer.classfile.reconstructor.SimpleNewInstructionReconstructor; +import jd.core.process.analyzer.classfile.visitor.CheckCastAndConvertInstructionVisitor; +import jd.core.process.analyzer.classfile.visitor.ReplaceStringBuxxxerVisitor; +import jd.core.process.analyzer.classfile.visitor.SetConstantTypeInStringIndexOfMethodsVisitor; +import jd.core.process.analyzer.instruction.bytecode.InstructionListBuilder; +import jd.core.process.analyzer.instruction.fast.DupLocalVariableAnalyzer; +import jd.core.process.analyzer.instruction.fast.FastInstructionListBuilder; +import jd.core.process.analyzer.instruction.fast.ReturnLineNumberAnalyzer; +import jd.core.process.analyzer.variable.DefaultVariableNameGenerator; +import jd.core.util.SignatureUtil; +import jd.core.util.StringConstants; + + +public class ClassFileAnalyzer +{ + public static void Analyze(ReferenceMap referenceMap, ClassFile classFile) + { + // Creation du tableau associatif [nom de classe interne, objet class]. + // Ce tableau est utilis� pour la suppression des accesseurs des + // classes internes. + HashMap innerClassesMap; + if (classFile.getInnerClassFiles() != null) + { + innerClassesMap = new HashMap(10); + innerClassesMap.put(classFile.getThisClassName(), classFile); + PopulateInnerClassMap(innerClassesMap, classFile); + } + else + { + innerClassesMap = null; + } + + // Generation des listes d'instructions + // Creation du tableau des variables locales si necessaire + AnalyzeClass(referenceMap, innerClassesMap, classFile); + } + + private static void PopulateInnerClassMap( + HashMap innerClassesMap, ClassFile classFile) + { + ArrayList innerClassFiles = classFile.getInnerClassFiles(); + + if (innerClassFiles != null) + { + int length = innerClassFiles.size(); + + for (int i=0; i innerClassesMap, + ClassFile classFile) + { + if ((classFile.access_flags & ClassFileConstants.ACC_SYNTHETIC) != 0) + { + AnalyzeSyntheticClass(classFile); + } + else + { + HashMap > eclipseSwitchMaps = + new HashMap >(); + + // L'analyse preliminaire permet d'identifier l'attribut de chaque + // classe interne non statique portant la reference vers la classe + // externe. 'PreAnalyzeMethods' doit etre execute avant l'analyse + // des classes internes. Elle permet egalement de construire la liste + // des accesseurs et de parser les tableaux "SwitchMap" produit par le + // compilateur d'Eclipse et utilis� pour le Switch+Enum. + PreAnalyzeMethods(eclipseSwitchMaps, classFile); + + // Analyse des classes internes avant l'analyse de la classe pour + // afficher correctement des classes anonymes. + ArrayList innerClassFiles = classFile.getInnerClassFiles(); + if (innerClassFiles != null) + { + int length = innerClassFiles.size(); + for (int i=0; i 0) && + (classFile.getMethods().length == 1) && + ((classFile.getMethods()[0].access_flags & + (ClassFileConstants.ACC_PUBLIC|ClassFileConstants.ACC_PROTECTED|ClassFileConstants.ACC_PRIVATE|ClassFileConstants.ACC_STATIC|ClassFileConstants.ACC_FINAL|ClassFileConstants.ACC_SYNTHETIC)) == + (ClassFileConstants.ACC_STATIC))) + { + ClassFile outerClassFile = classFile.getOuterClass(); + ConstantPool outerConstants = outerClassFile.getConstantPool(); + ConstantPool constants = classFile.getConstantPool(); + Method method = classFile.getMethods()[0]; + + try + { + AnalyzeMethodref(classFile); + + // Build instructions + List list = new ArrayList(); + List listForAnalyze = new ArrayList(); + + InstructionListBuilder.Build( + classFile, method, list, listForAnalyze); + + /* Parse static method + * static { + * $SwitchMap$basic$data$TestEnum$enum2 = new int[enum2.values().length]; + * try { $SwitchMap$basic$data$TestEnum$enum2[enum2.E.ordinal()] = 1; } catch(NoSuchFieldError ex) { } + * try { $SwitchMap$basic$data$TestEnum$enum2[enum2.F.ordinal()] = 2; } catch(NoSuchFieldError ex) { } + * $SwitchMap$basic$data$TestEnum$enum1 = new int[enum1.values().length]; + * try { $SwitchMap$basic$data$TestEnum$enum1[enum1.A.ordinal()] = 1; } catch(NoSuchFieldError ex) { } + * try { $SwitchMap$basic$data$TestEnum$enum1[enum1.B.ordinal()] = 2; } catch(NoSuchFieldError ex) { } + * } + */ + int length = list.size(); + + for (int index=0; index enumNameIndexes = new ArrayList(); + + for (index+=3; index 0) + { + Field field = fields[i]; + + if ((field.name_index == cnat.name_index) && + (field.descriptor_index == cnat.descriptor_index)) + return field; + } + + return null; + } + + private static void AnalyzeMethodref(ClassFile classFile) + { + ConstantPool constants = classFile.getConstantPool(); + + for (int i=constants.size()-1; i>=0; --i) + { + Constant constant = constants.get(i); + + if ((constant != null) && + ((constant.tag == ConstantConstant.CONSTANT_Methodref) || + (constant.tag == ConstantConstant.CONSTANT_InterfaceMethodref))) + { + ConstantMethodref cmr = (ConstantMethodref)constant; + ConstantNameAndType cnat = + constants.getConstantNameAndType(cmr.name_and_type_index); + + if (cnat != null) + { + String signature = constants.getConstantUtf8( + cnat.descriptor_index); + cmr.setParameterSignatures( + SignatureUtil.GetParameterSignatures(signature)); + cmr.setReturnedSignature( + SignatureUtil.GetMethodReturnedSignature(signature)); + } + } + } + } + + private static void CheckUnicityOfFieldNames(ClassFile classFile) + { + Field[] fields = classFile.getFields(); + if (fields == null) + return; + + ConstantPool constants = classFile.getConstantPool(); + HashMap> map = + new HashMap>(); + + // Populate map + int i = fields.length; + while (i-- > 0) + { + Field field = fields[i]; + + if ((field.access_flags & (ClassFileConstants.ACC_PUBLIC|ClassFileConstants.ACC_PROTECTED)) != 0) + continue; + + String name = constants.getConstantUtf8(field.name_index); + ArrayList list = map.get(name); + + if (list == null) + { + list = new ArrayList(5); + map.put(name, list); + } + + list.add(field); + } + + // Check unicity + Iterator iteratorName = map.keySet().iterator(); + while (iteratorName.hasNext()) + { + String name = iteratorName.next(); + ArrayList list = map.get(name); + + int j = list.size(); + if (j < 2) + continue; + + // Change attribute names; + while (j-- > 0) + { + Field field = list.get(j); + + // Generate new attribute names + String newName = FieldNameGenerator.GenerateName( + constants.getConstantUtf8(field.descriptor_index), + constants.getConstantUtf8(field.name_index)); + // Add new constant string + int newNameIndex = constants.addConstantUtf8(newName); + // Update name index + field.name_index = newNameIndex; + } + } + } + + @SuppressWarnings("unchecked") + private static void CheckUnicityOfFieldrefNames(ClassFile classFile) + { + ConstantPool constants = classFile.getConstantPool(); + + // Popuplate array + int i = constants.size(); + Object[] array = new Object[i]; + + while (i-- > 0) + { + Constant constant = constants.get(i); + + if ((constant == null) || + (constant.tag != ConstantConstant.CONSTANT_Fieldref)) + continue; + + ConstantFieldref cfr = (ConstantFieldref)constant; + HashMap> map = + (HashMap>)array[cfr.class_index]; + + if (map == null) + { + map = new HashMap>(); + array[cfr.class_index] = map; + } + + ConstantNameAndType cnat = + constants.getConstantNameAndType(cfr.name_and_type_index); + String name = constants.getConstantUtf8(cnat.name_index); + ArrayList list = map.get(name); + + if (list != null) + { + if (list.get(0).descriptor_index != cnat.descriptor_index) + { + // Same name and different signature + list.add(cnat); + } + } + else + { + list = new ArrayList(5); + map.put(name, list); + list.add(cnat); + } + } + + // For each class in constant pool, check unicity of name of 'Fieldref' + i = array.length; + while (i-- > 0) + { + if (array[i] == null) + continue; + + HashMap> map = + (HashMap>)array[i]; + + Iterator iterator = map.keySet().iterator(); + while (iterator.hasNext()) + { + String name = iterator.next(); + ArrayList list = map.get(name); + + int k = list.size(); + if (k < 2) + continue; + + while (k-- > 0) + { + ConstantNameAndType cnat = list.get(k); + String signature = + constants.getConstantUtf8(cnat.descriptor_index); + String newName = + FieldNameGenerator.GenerateName(signature, name); + cnat.name_index = constants.addConstantUtf8(newName); + } + } + } + } + + private static void CheckAssertionsDisabledField(ClassFile classFile) + { + ConstantPool constants = classFile.getConstantPool(); + Field[] fields = classFile.getFields(); + + if (fields == null) + return; + + int i = fields.length; + while (i-- > 0) + { + Field field = fields[i]; + + if ((field.access_flags & + (ClassFileConstants.ACC_PUBLIC|ClassFileConstants.ACC_PROTECTED| + ClassFileConstants.ACC_PRIVATE|ClassFileConstants.ACC_SYNTHETIC| + ClassFileConstants.ACC_STATIC|ClassFileConstants.ACC_FINAL)) + != (ClassFileConstants.ACC_STATIC|ClassFileConstants.ACC_FINAL)) + continue; + if (field.getValueAndMethod() == null) + continue; + + String name = constants.getConstantUtf8(field.name_index); + if (! name.equals("$assertionsDisabled")) + continue; + + field.access_flags |= ClassFileConstants.ACC_SYNTHETIC; + } + } + + private static boolean HasAAccessorMethodName(ClassFile classFile, Method method) + { + String methodName = + classFile.getConstantPool().getConstantUtf8(method.name_index); + + if (! methodName.startsWith("access$")) + return false; + + int i = methodName.length(); + + while (i-- > "access$".length()) + { + if (! Character.isDigit(methodName.charAt(i))) + return false; + } + + return true; + } + + private static boolean HasAEclipseSwitchTableMethodName( + ClassFile classFile, Method method) + { + String methodName = + classFile.getConstantPool().getConstantUtf8(method.name_index); + + if (! methodName.startsWith("$SWITCH_TABLE$")) + return false; + + String methodDescriptor = + classFile.getConstantPool().getConstantUtf8(method.descriptor_index); + + return methodDescriptor.equals("()[I"); + } + + /* Parse Eclipse SwitchTable method + * static int[] $SWITCH_TABLE$basic$data$TestEnum$enum1() + * { + * if($SWITCH_TABLE$basic$data$TestEnum$enum1 != null) + * return $SWITCH_TABLE$basic$data$TestEnum$enum1; + * int ai[] = new int[enum1.values().length]; + * try { ai[enum1.A.ordinal()] = 1; } catch(NoSuchFieldError _ex) { } + * try { ai[enum1.B.ordinal()] = 2; } catch(NoSuchFieldError _ex) { } + * return $SWITCH_TABLE$basic$data$TestEnum$enum1 = ai; + * } + * + * and parse DEX SwitchTable method + * static int[] $SWITCH_TABLE$gr$androiddev$FuelPrices$StaticTools$LocationProvider() + * { + * int[] local0 = $SWITCH_TABLE$gr$androiddev$FuelPrices$StaticTools$LocationProvider; + * if (local0 != null) + * return local0; + * int array = new int[StaticTools$LocationProvider.values().length()]; + * try { array[StaticTools$LocationProvider.ANY.ordinal()] = 2; } catch (java/lang/NoSuchFieldError) --> 73 + * try { array[StaticTools$LocationProvider.BESTOFBOTH.ordinal()] = 1; } catch (java/lang/NoSuchFieldError) --> 69 + * try { array[StaticTools$LocationProvider.GPS.ordinal()] = 3; } catch (java/lang/NoSuchFieldError) --> 64 + * try { array[StaticTools$LocationProvider.NETWORK.ordinal()] = 4; } catch (java/lang/NoSuchFieldError) --> 59 + * $SWITCH_TABLE$gr$androiddev$FuelPrices$StaticTools$LocationProvider = array; + * return array; + * 59: catch (java/lang/NoSuchFieldError) {} + * 64: catch (java/lang/NoSuchFieldError) {} + * 69: catch (java/lang/NoSuchFieldError) {} + * 73: catch (java/lang/NoSuchFieldError) {} + * } + */ + private static void ParseEclipseOrDexSwitchTableMethod( + ClassFile classFile, Method method) + { + List list = method.getInstructions(); + int length = list.size(); + + if ((length >= 6) && + (list.get(0).opcode == ByteCodeConstants.DUPSTORE) && + (list.get(1).opcode == ByteCodeConstants.IFXNULL) && + (list.get(2).opcode == ByteCodeConstants.XRETURN) && + (list.get(3).opcode == ByteCodeConstants.POP) && + (list.get(4).opcode == ByteCodeConstants.ASTORE)) + { + // Eclipse pattern + ConstantPool constants = classFile.getConstantPool(); + ArrayList enumNameIndexes = new ArrayList(); + + for (int index=5+2; index= 7) && + (list.get(0).opcode == ByteCodeConstants.ASTORE) && + (list.get(1).opcode == ByteCodeConstants.IFXNULL) && + (list.get(2).opcode == ByteCodeConstants.XRETURN) && + (list.get(3).opcode == ByteCodeConstants.ASTORE) && + (list.get(4).opcode == ByteCodeConstants.ARRAYSTORE)) + { + // Dalvik pattern + ConstantPool constants = classFile.getConstantPool(); + ArrayList enumNameIndexes = new ArrayList(); + + for (int index=4; index > eclipseSwitchMaps, + ClassFile classFile) + { + AnalyzeMethodref(classFile); + + Method[] methods = classFile.getMethods(); + + if (methods == null) + return; + + int length = methods.length; + DefaultVariableNameGenerator variableNameGenerator = + new DefaultVariableNameGenerator(classFile); + int outerThisFieldrefIndex = 0; + + for (int i=0; i list = new ArrayList(); + List listForAnalyze = new ArrayList(); + + InstructionListBuilder.Build( + classFile, method, list, listForAnalyze); + method.setInstructions(list); + + if (((method.access_flags & (ClassFileConstants.ACC_PUBLIC|ClassFileConstants.ACC_PROTECTED|ClassFileConstants.ACC_PRIVATE|ClassFileConstants.ACC_STATIC)) == ClassFileConstants.ACC_STATIC) && + HasAAccessorMethodName(classFile, method)) + { + // Recherche des accesseurs + AccessorAnalyzer.Analyze(classFile, method); + // Setup access flag : JDK 1.4 not set synthetic flag... + method.access_flags |= ClassFileConstants.ACC_SYNTHETIC; + } + else if (((method.access_flags & + (ClassFileConstants.ACC_SYNTHETIC|ClassFileConstants.ACC_BRIDGE)) == 0)) + { + // Create missing local variable table + LocalVariableAnalyzer.Analyze( + classFile, method, variableNameGenerator, list, listForAnalyze); + + // Recherche du numero de l'attribut contenant la reference + // de la classe externe + outerThisFieldrefIndex = SearchOuterThisFieldrefIndex( + classFile, method, list, outerThisFieldrefIndex); + } + else if (((method.access_flags & (ClassFileConstants.ACC_PUBLIC|ClassFileConstants.ACC_PROTECTED|ClassFileConstants.ACC_PRIVATE|ClassFileConstants.ACC_STATIC|ClassFileConstants.ACC_SYNTHETIC)) + == (ClassFileConstants.ACC_STATIC|ClassFileConstants.ACC_SYNTHETIC)) && + HasAEclipseSwitchTableMethodName(classFile, method)) + { + // Parse "static int[] $SWITCH_TABLE$...()" method + ParseEclipseOrDexSwitchTableMethod(classFile, method); + } + } + } + catch (Exception e) + { + // DEBUG e.printStackTrace(); + method.setContainsError(true); + } + } + + if (outerThisFieldrefIndex != 0) + AnalyzeOuterReferences(classFile, outerThisFieldrefIndex); + } + + private static void AnalyzeMethods( + ReferenceMap referenceMap, + HashMap innerClassesMap, + ClassFile classFile) + { + Method[] methods = classFile.getMethods(); + + if (methods == null) + return; + + int length = methods.length; + + // Initialisation du reconstructeur traitant l'acces des champs et + // methodes externes si la classe courante est une classe interne ou + // si elle contient des classes internes + OuterReferenceReconstructor outerReferenceReconstructor = + (innerClassesMap != null) ? + new OuterReferenceReconstructor(innerClassesMap, classFile) : null; + + for (int i=0; i list = method.getInstructions(); + + // Recontruct access to outer fields and methods + if (outerReferenceReconstructor != null) + outerReferenceReconstructor.reconstruct(method, list); + // Re-construct 'new' intruction + NewInstructionReconstructor.Reconstruct(classFile, method, list); + SimpleNewInstructionReconstructor.Reconstruct(classFile, method, list); + // Recontruction des instructions de pre-incrementation non entier + PreIncReconstructor.Reconstruct(list); + // Recontruction des instructions de post-incrementation non entier + PostIncReconstructor.Reconstruct(list); + // Recontruction du mot cl� '.class' pour le JDK 1.1.8 - A + DotClass118AReconstructor.Reconstruct( + referenceMap, classFile, list); + // Recontruction du mot cl� '.class' pour le JDK 1.4 + DotClass14Reconstructor.Reconstruct( + referenceMap, classFile, list); + // Replace StringBuffer and StringBuilder in java source line + ReplaceStringBufferAndStringBuilder(classFile, list); + // Remove unused pop instruction + RemoveUnusedPopInstruction(list); + // Transformation des tests sur des types 'long' et 'double' + TransformTestOnLongOrDouble(list); + // Set constant type of "String.indexOf(...)" methods + SetConstantTypeInStringIndexOfMethods(classFile, list); + // Elimine la s�quence DupStore(this) ... DupLoad() ... DupLoad(). + // Cette operation doit etre executee avant + // 'AssignmentInstructionReconstructor'. + DupStoreThisReconstructor.Reconstruct(list); + // Recontruction des affectations multiples + // Cette operation doit etre executee avant + // 'InitArrayInstructionReconstructor', 'TernaryOpReconstructor' + // et la construction des instructions try-catch et finally. + // Cette operation doit etre executee apr�s 'DupStoreThisReconstructor'. + AssignmentInstructionReconstructor.Reconstruct(list); + // Elimine les doubles casts et ajoute des casts devant les + // constantes numeriques si necessaire. + CheckCastAndConvertInstructionVisitor.visit( + classFile.getConstantPool(), list); + + // Build fast instructions + ArrayList fastList = + new ArrayList(list); + method.setFastNodes(fastList); + + // DEBUG // + //ConstantPool debugConstants = classFile.getConstantPool(); + //String debugMethodName = debugConstants.getConstantUtf8(method.name_index); + // DEBUG // + FastInstructionListBuilder.Build( + referenceMap, classFile, method, fastList); + + // Ajout des d�clarations des variables locales temporaires + DupLocalVariableAnalyzer.Declare(classFile, method, fastList); + } + catch (Exception e) + { + // DEBUG e.printStackTrace(); + method.setContainsError(true); + } + } + + // Recherche des initialisations des attributs statiques Enum + InitDexEnumFieldsReconstructor.Reconstruct(classFile); + // Recherche des initialisations des attributs statiques + InitStaticFieldsReconstructor.Reconstruct(classFile); + // Recherche des initialisations des attributs d'instance + InitInstanceFieldsReconstructor.Reconstruct(classFile); + + for (int i=0; i list, int outerThisFieldrefIndex) + { + // Is classFile an inner class ? + if (!classFile.isAInnerClass() || + ((classFile.access_flags & ClassFileConstants.ACC_STATIC) != 0)) + return 0; + + ConstantPool constants = classFile.getConstantPool(); + + // Is method a constructor ? + if (method.name_index != constants.instanceConstructorIndex) + return outerThisFieldrefIndex; + + // Is parameters counter greater than 0 ? + AttributeSignature as = method.getAttributeSignature(); + String methodSignature = constants.getConstantUtf8( + (as==null) ? method.descriptor_index : as.signature_index); + + if (methodSignature.charAt(1) == ')') + return 0; + + // Search instruction 'PutField(#, ALoad(1))' before super + // method call. + int length = list.size(); + + for (int i=0; i=0; --i) + { + Field field = fields[i]; + + if ((field.name_index == cnat.name_index) && + (field.descriptor_index == cnat.descriptor_index)) + { + classFile.setOuterThisField(field); + // Ensure outer this field is a synthetic field. + field.access_flags |= ClassFileConstants.ACC_SYNTHETIC; + break; + } + } + } + } + + for (int i=0; i list = method.getInstructions(); + + if (list == null) + continue; + + int listLength = list.size(); + + if (method.name_index == constants.instanceConstructorIndex) + { + // Remove PutField instruction with index = outerThisFieldrefIndex + // in constructors + for (int index=0; index, [ ]) + * 2) Store super constructor parameter count to display anonymous + * class instanciation + * 3) Store outer parameter position on field for inner and anonymous classes + */ + private static void AnalyseAndModifyConstructors( + ClassFile classFile, Method method) + { + ConstantPool constants = classFile.getConstantPool(); + + if (method.name_index == constants.instanceConstructorIndex) + { + List list = method.getFastNodes(); + + while (list.size() > 0) + { + Instruction instruction = list.get(0); + + if (instruction.opcode == ByteCodeConstants.INVOKESPECIAL) + { + Invokespecial is = (Invokespecial)instruction; + + if ((is.objectref.opcode == ByteCodeConstants.ALOAD) && + (((ALoad)is.objectref).index == 0)) + { + ConstantMethodref cmr = constants.getConstantMethodref(is.index); + ConstantNameAndType cnat = + constants.getConstantNameAndType(cmr.name_and_type_index); + + if (cnat.name_index == constants.instanceConstructorIndex) + { + if (cmr.class_index == classFile.getSuperClassIndex()) + { + int count = is.args.size(); + + method.setSuperConstructorParameterCount(count); + + if ((classFile.access_flags & ClassFileConstants.ACC_ENUM) != 0) + { + if (count == 2) + { + // Retrait de l'appel du constructeur s'il + // n'a que les deux param�tres standard. + list.remove(0); + } + } + else + { + if (count == 0) + { + // Retrait de l'appel du constructeur s'il + // n'a aucun parametre. + list.remove(0); + } + } + } + + break; + } + } + } + else if (instruction.opcode == ByteCodeConstants.PUTFIELD) + { + PutField pf = (PutField)instruction; + + switch (pf.valueref.opcode) + { + case ByteCodeConstants.LOAD: + case ByteCodeConstants.ALOAD: + case ByteCodeConstants.ILOAD: + IndexInstruction ii = (IndexInstruction)pf.valueref; + // Rappel sur l'ordre des parametres passes aux constructeurs: + // (outer this, p1, p2, ..., outer local var1, ...) + // Rappel sur l'organisation des variables locales: + // 0: this + // 1: outer this + // 2: p1 + // ... + if (ii.index > 1) + { + // Stockage de la position du parametre du + // constructeur initialisant le champs + ConstantFieldref cfr = + constants.getConstantFieldref(pf.index); + ConstantNameAndType cnat = + constants.getConstantNameAndType(cfr.name_and_type_index); + Field field = + classFile.getField(cnat.name_index, cnat.descriptor_index); + field.anonymousClassConstructorParameterIndex = ii.index - 1; + // Ensure this field is a synthetic field. + field.access_flags |= ClassFileConstants.ACC_SYNTHETIC; + } + } + } + + // Retrait des instructions precedents l'appel au constructeur + // de la classe mere. + list.remove(0); + } + } + } + + private static void RemoveLastReturnInstruction(Method method) + { + List list = method.getFastNodes(); + + if (list != null) + { + int length = list.size(); + + if (length > 0) + { + switch (list.get(length-1).opcode) + { + case FastConstants.RETURN: + list.remove(length-1); + break; + case FastConstants.LABEL: + FastLabel fl = (FastLabel)list.get(length-1); + if (fl.instruction.opcode == FastConstants.RETURN) + fl.instruction = null; + } + } + } + } + + private static void ReplaceStringBufferAndStringBuilder( + ClassFile classFile, List list) + { + ReplaceStringBuxxxerVisitor visitor = new ReplaceStringBuxxxerVisitor( + classFile.getConstantPool()); + + int length = list.size(); + + for (int i=0; i list) + { + int index = list.size(); + + while (index-- > 0) + { + Instruction instruction = list.get(index); + + if (instruction.opcode == ByteCodeConstants.POP) + { + switch (((Pop)instruction).objectref.opcode) + { + case ByteCodeConstants.GETFIELD: + case ByteCodeConstants.GETSTATIC: + case ByteCodeConstants.OUTERTHIS: + case ByteCodeConstants.ALOAD: + case ByteCodeConstants.ILOAD: + case ByteCodeConstants.LOAD: + list.remove(index); + } + } + } + } + + private static void TransformTestOnLongOrDouble(List list) + { + int index = list.size(); + + while (index-- > 0) + { + Instruction instruction = list.get(index); + + if (instruction.opcode == ByteCodeConstants.IF) + { + IfInstruction ii = (IfInstruction)instruction; + + switch (ii.cmp) + { + case ByteCodeConstants.CMP_EQ: + case ByteCodeConstants.CMP_NE: + case ByteCodeConstants.CMP_LT: + case ByteCodeConstants.CMP_GE: + case ByteCodeConstants.CMP_GT: + case ByteCodeConstants.CMP_LE: + if (ii.value.opcode == ByteCodeConstants.BINARYOP) + { + BinaryOperatorInstruction boi = + (BinaryOperatorInstruction)ii.value; + if ("<".equals(boi.operator)) + { + // Instruction 'boi' = ?CMP, ?CMPL or ?CMPG + list.set(index, new IfCmp( + ByteCodeConstants.IFCMP, ii.offset, + ii.lineNumber, ii.cmp, + boi.value1, boi.value2, ii.branch)); + } + } + break; + } + } + } + } + + private static void SetConstantTypeInStringIndexOfMethods( + ClassFile classFile, List list) + { + SetConstantTypeInStringIndexOfMethodsVisitor visitor = + new SetConstantTypeInStringIndexOfMethodsVisitor( + classFile.getConstantPool()); + + visitor.visit(list); + } + + private static void AnalyzeEnum(ClassFile classFile) + { + if (classFile.getFields() == null) + return; + + ConstantPool constants = classFile.getConstantPool(); + String enumArraySignature = "[" + classFile.getInternalClassName(); + + // Recherche du champ statique possedant un acces ACC_ENUM et un + // type '[LenumXXXX;' + Field[] fields = classFile.getFields(); + for (int i=fields.length-1; i>=0; --i) + { + Field field = fields[i]; + + if (((field.access_flags & (ClassFileConstants.ACC_SYNTHETIC|ClassFileConstants.ACC_ENUM)) == 0) || + (field.getValueAndMethod() == null)) + continue; + + Instruction instruction = field.getValueAndMethod().getValue(); + + if (((instruction.opcode != ByteCodeConstants.INITARRAY) && + (instruction.opcode != ByteCodeConstants.NEWANDINITARRAY)) || + !constants.getConstantUtf8(field.descriptor_index).equals(enumArraySignature)) + continue; + + String fieldName = constants.getConstantUtf8(field.name_index); + if (! fieldName.equals(StringConstants.ENUM_VALUES_ARRAY_NAME) && + ! fieldName.equals(StringConstants.ENUM_VALUES_ARRAY_NAME_ECLIPSE)) + continue; + + // Stockage des valeurs de l'enumeration + classFile.setEnumValues(((InitArrayInstruction)instruction).values); + break; + } + } +} \ No newline at end of file diff --git a/src/jd/core/process/analyzer/classfile/FieldNameGenerator.java b/src/jd/core/process/analyzer/classfile/FieldNameGenerator.java new file mode 100644 index 00000000..b519bedb --- /dev/null +++ b/src/jd/core/process/analyzer/classfile/FieldNameGenerator.java @@ -0,0 +1,193 @@ +package jd.core.process.analyzer.classfile; + +import jd.core.util.CharArrayUtil; +import jd.core.util.StringConstants; + +public class FieldNameGenerator +{ + public static String GenerateName( + String signature, String name) + { + StringBuffer sbName = new StringBuffer(StringConstants.JD_FIELD_PREFIX); + + sbName.append(name); + sbName.append("_of_type"); + + char[] caSignature = signature.toCharArray(); + int length = caSignature.length; + + GenerateName(sbName, caSignature, length, 0); + + return sbName.toString(); + } + + private static int GenerateName( + StringBuffer sbName, char[] caSignature, int length, int index) + { + char c; + int beginIndex; + + sbName.append('_'); + + while (true) + { + int nbrOfDimensions = 0; + + while (caSignature[index] == '[') + { + index++; + nbrOfDimensions++; + } + + if (nbrOfDimensions > 0) + { + sbName.append("Array"); + if (nbrOfDimensions > 1) + { + sbName.append(nbrOfDimensions); + sbName.append('d'); + } + sbName.append("Of"); + } + + switch(caSignature[index]) + { + case 'B' : + sbName.append("Byte"); + index++; + break; + case 'C' : + sbName.append("Char"); + index++; + break; + case 'D' : + sbName.append("Double"); + index++; + break; + case 'F' : + sbName.append("Float"); + index++; + break; + case 'I' : + sbName.append("Int"); + index++; + break; + case 'J' : + sbName.append("Long"); + index++; + break; + case 'L' : + case '.' : + beginIndex = ++index; + c = '.'; + + // Recherche de ; ou de < + while (index < length) + { + c = caSignature[index]; + if ((c == ';') || (c == '<')) + break; + index++; + } + + String internalClassName = + CharArrayUtil.Substring(caSignature, beginIndex, index); + InternalClassNameToCapitalizedClassName( + sbName, internalClassName); + + if (c == '<') + { + sbName.append("_of"); + index = GenerateName( + sbName, caSignature, length, index+1); + + while (caSignature[index] != '>') + { + sbName.append("_and"); + index = GenerateName( + sbName, caSignature, length, index); + } + + // pass '>' + index++; + } + + // pass ';' + if (caSignature[index] == ';') + index++; + break; + case 'S' : + sbName.append("Short"); + index++; + break; + case 'T' : + beginIndex = ++index; + index = CharArrayUtil.IndexOf(caSignature, ';', beginIndex); + sbName.append(caSignature, beginIndex, index-beginIndex); + index++; + break; + case 'V' : + sbName.append("Void"); + index++; + break; + case 'Z' : + sbName.append("Boolean"); + index++; + break; + case '-' : + sbName.append("_super_"); + index = GenerateName(sbName, caSignature, length, index+1); + break; + case '+' : + sbName.append("_extends_"); + index = GenerateName(sbName, caSignature, length, index+1); + break; + case '*' : + sbName.append('X'); + index++; + break; + case 'X' : + case 'Y' : + sbName.append('X'); + System.err.println(""); + index++; + break; + default: + // DEBUG + new Throwable( + "SignatureWriter.WriteSignature: invalid signature '" + + String.valueOf(caSignature) + "'").printStackTrace(); + // DEBUG + } + + if ((index >= length) || (caSignature[index] != '.')) + break; + + sbName.append("_"); + } + + return index; + } + + private static void InternalClassNameToCapitalizedClassName( + StringBuffer sbName, String internalClassName) + { + int index1 = 0; + int index2 = internalClassName.indexOf( + StringConstants.INTERNAL_PACKAGE_SEPARATOR); + + while (index2 != -1) + { + sbName.append(Character.toUpperCase( + internalClassName.charAt(index1))); + sbName.append(internalClassName.substring(index1+1, index2)); + index1 = index2+1; + index2 = internalClassName.indexOf( + StringConstants.INTERNAL_PACKAGE_SEPARATOR, index1); + } + + sbName.append(Character.toUpperCase( + internalClassName.charAt(index1))); + sbName.append(internalClassName.substring(index1+1)); + } +} diff --git a/src/jd/core/process/analyzer/classfile/LocalVariableAnalyzer.java b/src/jd/core/process/analyzer/classfile/LocalVariableAnalyzer.java new file mode 100644 index 00000000..f5ab3c6a --- /dev/null +++ b/src/jd/core/process/analyzer/classfile/LocalVariableAnalyzer.java @@ -0,0 +1,1850 @@ +package jd.core.process.analyzer.classfile; + +import java.util.List; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.ClassFileConstants; +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariable; +import jd.core.model.classfile.LocalVariables; +import jd.core.model.classfile.Method; +import jd.core.model.classfile.attribute.AttributeSignature; +import jd.core.model.classfile.constant.ConstantFieldref; +import jd.core.model.classfile.constant.ConstantNameAndType; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.ALoad; +import jd.core.model.instruction.bytecode.instruction.AStore; +import jd.core.model.instruction.bytecode.instruction.ArrayStoreInstruction; +import jd.core.model.instruction.bytecode.instruction.BinaryOperatorInstruction; +import jd.core.model.instruction.bytecode.instruction.DupLoad; +import jd.core.model.instruction.bytecode.instruction.ExceptionLoad; +import jd.core.model.instruction.bytecode.instruction.IConst; +import jd.core.model.instruction.bytecode.instruction.ILoad; +import jd.core.model.instruction.bytecode.instruction.IfCmp; +import jd.core.model.instruction.bytecode.instruction.IncInstruction; +import jd.core.model.instruction.bytecode.instruction.IndexInstruction; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.InvokeInstruction; +import jd.core.model.instruction.bytecode.instruction.LoadInstruction; +import jd.core.model.instruction.bytecode.instruction.MonitorEnter; +import jd.core.model.instruction.bytecode.instruction.MonitorExit; +import jd.core.model.instruction.bytecode.instruction.PutField; +import jd.core.model.instruction.bytecode.instruction.PutStatic; +import jd.core.model.instruction.bytecode.instruction.ReturnInstruction; +import jd.core.model.instruction.bytecode.instruction.StoreInstruction; +import jd.core.model.instruction.bytecode.instruction.TernaryOpStore; +import jd.core.model.instruction.fast.FastConstants; +import jd.core.process.analyzer.classfile.visitor.AddCheckCastVisitor; +import jd.core.process.analyzer.classfile.visitor.SearchInstructionByOffsetVisitor; +import jd.core.process.analyzer.instruction.bytecode.util.ByteCodeUtil; +import jd.core.process.analyzer.util.InstructionUtil; +import jd.core.process.analyzer.variable.DefaultVariableNameGenerator; +import jd.core.util.SignatureUtil; +import jd.core.util.StringConstants; +import jd.core.util.UtilConstants; + + +public class LocalVariableAnalyzer +{ + /** + * Indexe de signature pour les variables locales de type inconnu. Si le + * type de la variable n'a pu etre determin�, la variable sera type + * 'Object'. + */ + private static final int UNDEFINED_TYPE = -1; + /** + * Indexe de signature pour les variables locales de type num�rique inconnu. + * Si le type de la variable n'a pu etre determin�, la variable sera type + * 'int'. + */ + private static final int NUMBER_TYPE = -2; + /** + * Indexe de signature pour les variables locales de type 'Object' et + * n�c�ssitant l'insertion d'instructions 'cast'. + */ + private static final int OBJECT_TYPE = -3; + + public static void Analyze( + ClassFile classFile, Method method, + DefaultVariableNameGenerator variableNameGenerator, + List list, List listForAnalyze) + { + ConstantPool constants = classFile.getConstantPool(); + variableNameGenerator.clearLocalNames(); + + // DEBUG String debugClassName = classFile.getInternalClassName(); + // DEBUG String debugMethodName = constants.getConstantUtf8(method.name_index); + + // Reconstruction de la Liste des variables locales + byte[] code = method.getCode(); + int codeLength = (code == null) ? 0 : code.length; + LocalVariables localVariables = method.getLocalVariables(); + + if (localVariables == null) + { + // Ajout d'entr�es dans le tableau pour les parametres + localVariables = new LocalVariables(); + method.setLocalVariables(localVariables); + + // Add this + if ((method.access_flags & ClassFileConstants.ACC_STATIC) == 0) + { + int nameIndex = constants.addConstantUtf8( + StringConstants.THIS_LOCAL_VARIABLE_NAME); + int signatureIndex = + constants.addConstantUtf8(classFile.getInternalClassName()); + LocalVariable lv = + new LocalVariable(0, codeLength, nameIndex, signatureIndex, 0); + localVariables.add(lv); + } + + if ((method.name_index == constants.instanceConstructorIndex) && + classFile.isAInnerClass() && + ((classFile.access_flags & ClassFileConstants.ACC_STATIC) == 0)) + { + // Add outer this + int nameIndex = constants.addConstantUtf8( + StringConstants.OUTER_THIS_LOCAL_VARIABLE_NAME); + String internalClassName = classFile.getInternalClassName(); + int lastInnerClassSeparatorIndex = + internalClassName.lastIndexOf(StringConstants.INTERNAL_INNER_SEPARATOR); + + String internalOuterClassName = + internalClassName.substring(0, lastInnerClassSeparatorIndex) + ';'; + + int signatureIndex = constants.addConstantUtf8(internalOuterClassName); + LocalVariable lv = + new LocalVariable(0, codeLength, nameIndex, signatureIndex, 1); + localVariables.add(lv); + } + + // Add Parameters + AnalyzeMethodParameter( + classFile, constants, method, localVariables, + variableNameGenerator, codeLength); + + localVariables.setIndexOfFirstLocalVariable(localVariables.size()); + + if (code != null) + { + GenerateMissingMonitorLocalVariables( + constants, localVariables, listForAnalyze); + } + } + else + { + // Traitement des entr�es correspondant aux parametres + AttributeSignature as = method.getAttributeSignature(); + String methodSignature = constants.getConstantUtf8( + (as==null) ? method.descriptor_index : as.signature_index); + + int indexOfFirstLocalVariable = + (((method.access_flags & ClassFileConstants.ACC_STATIC) == 0) ? 1 : 0) + + SignatureUtil.GetParameterSignatureCount(methodSignature); + + if (indexOfFirstLocalVariable > localVariables.size()) + { + // Dans le cas des m�thodes g�n�r�e automatiquement par le + // compilateur (comme par exemple les m�thode des enums), le + // tableau des variables locales est incomplet. + // Add Parameters + AnalyzeMethodParameter( + classFile, constants, method, localVariables, + variableNameGenerator, codeLength); + } + + localVariables.setIndexOfFirstLocalVariable( + indexOfFirstLocalVariable); + + if (code != null) + { + GenerateMissingMonitorLocalVariables( + constants, localVariables, listForAnalyze); + CheckLocalVariableRanges( + constants, code, localVariables, + variableNameGenerator, listForAnalyze); + } + + // La fusion des variables locales genere des erreurs. Mise en + // commentaire a la version 0.5.3. + // fr.oseo.fui.actions.partenaire.FicheInformationAction: + // InterlocuteurBO interlocuteur; + // for (InterlocuteurBO partenaire = projet.getPartenaires().iterator(); partenaire.hasNext(); ) + // { + // interlocuteur = (InterlocuteurBO)partenaire.next(); + // ... + // } + // ... + // for (partenaire = projet.getPartenaires().iterator(); partenaire.hasNext(); ) + // { + // interlocuteur = (InterlocuteurBO)partenaire.next(); + // ... + // } + //MergeLocalVariables(localVariables); + } + + // Add local variables + // Create new local variables, set range and type + if (code != null) + { + String returnedSignature = GetReturnedSignature(classFile, method); + + AnalyzeMethodCode( + constants, localVariables, list, listForAnalyze, + returnedSignature); + + // Upgrade byte type to char type + // Substitution des types byte par char dans les instructions + // bipush et sipush + SetConstantTypes( + classFile, constants, method, localVariables, + list, listForAnalyze, returnedSignature); + + InitialyzeExceptionLoad(listForAnalyze, localVariables); + } + + GenerateLocalVariableNames( + constants, localVariables, variableNameGenerator); + } + + private static void AnalyzeMethodParameter( + ClassFile classFile, ConstantPool constants, + Method method, LocalVariables localVariables, + DefaultVariableNameGenerator variableNameGenerator, int codeLength) + { + // Le descripteur et la signature sont differentes pour les + // constructeurs des Enums ! + AttributeSignature as = method.getAttributeSignature(); + boolean descriptorFlag = (as == null); + String methodSignature = constants.getConstantUtf8( + descriptorFlag ? method.descriptor_index : as.signature_index); + List parameterTypes = + SignatureUtil.GetParameterSignatures(methodSignature); + + if (parameterTypes != null) + { + // Arguments + // Constructeur des classes interne non static : + // - var 1: outer this => ne pas generer de nom + // Constructeur des Enum : + // Descripteur: + // - var 1: nom de la valeur => ne pas afficher + // - var 2: index de la valeur => ne pas afficher + // Signature: + // - variableIndex = 1 + 1 + 1 + // Le premier parametre des m�thodes non statiques est 'this' + boolean staticMethodFlag = + ((method.access_flags & ClassFileConstants.ACC_STATIC) != 0); + int variableIndex = staticMethodFlag ? 0 : 1; + + int firstVisibleParameterCounter = 0; + + if (method.name_index == constants.instanceConstructorIndex) + { + if ((classFile.access_flags & ClassFileConstants.ACC_ENUM) != 0) + { + if (descriptorFlag) + firstVisibleParameterCounter = 2; + else + variableIndex = 3; + } + else if (classFile.isAInnerClass()) + { + if ((classFile.access_flags & ClassFileConstants.ACC_STATIC) == 0) + firstVisibleParameterCounter = 1; + } + } + + // + int anonymousClassDepth = 0; + ClassFile anonymousClassFile = classFile; + + while ((anonymousClassFile != null) && + (anonymousClassFile.getInternalAnonymousClassName() != null)) + { + anonymousClassDepth++; + anonymousClassFile = anonymousClassFile.getOuterClass(); + } + + // + final int length = parameterTypes.size(); + + // + final int varargsParameterIndex; + + if ((method.access_flags & ClassFileConstants.ACC_VARARGS) == 0) + { + varargsParameterIndex = Integer.MAX_VALUE; + } + else + { + varargsParameterIndex = length - 1; + } + + for (int parameterIndex=0; parameterIndex= firstVisibleParameterCounter) &&*/ + (localVariables.getLocalVariableWithIndexAndOffset(variableIndex, 0) == null)) + { + boolean appearsOnceFlag = SignatureAppearsOnceInParameters( + parameterTypes, firstVisibleParameterCounter, + length, signature); + final String name = + variableNameGenerator.generateParameterNameFromSignature( + signature, appearsOnceFlag, + (parameterIndex==varargsParameterIndex), + anonymousClassDepth); + + int nameIndex = constants.addConstantUtf8(name); + int signatureIndex = constants.addConstantUtf8(signature); + LocalVariable lv = new LocalVariable( + 0, codeLength, nameIndex, signatureIndex, variableIndex); + localVariables.add(lv); + } + + final char firstChar = signature.charAt(0); + variableIndex += + ((firstChar == 'D') || (firstChar == 'J')) ? 2 : 1; + } + } + } + + private static void GenerateMissingMonitorLocalVariables( + ConstantPool constants, LocalVariables localVariables, + List listForAnalyze) + { + int length = listForAnalyze.size(); + + for (int i=1; i 0) + { + instruction = listForAnalyze.get(j); + if (instruction.opcode != ByteCodeConstants.MONITOREXIT) + continue; + if (((MonitorExit)instruction).objectref.opcode != ByteCodeConstants.ALOAD) + continue; + ALoad al = (ALoad)((MonitorExit)instruction).objectref; + if (al.index == monitorLocalVariableIndex) + { + monitorLocalVariableLenght += + monitorLocalVariableOffset - al.offset; + monitorLocalVariableOffset = al.offset; + + monitorExitCount++; + break; + } + } + } + + if (monitorExitCount < 2) + continue; + + // Verification de l'existance d'une variable locale + LocalVariable lv = + localVariables.getLocalVariableWithIndexAndOffset( + monitorLocalVariableIndex, monitorLocalVariableOffset); + + // Creation d'une variable locale + if ((lv == null) || + (lv.start_pc+lv.length < monitorLocalVariableOffset+monitorLocalVariableLenght)) + { + int signatureIndex = + constants.addConstantUtf8(StringConstants.INTERNAL_OBJECT_SIGNATURE); + localVariables.add(new LocalVariable( + monitorLocalVariableOffset, monitorLocalVariableLenght, + signatureIndex, signatureIndex, monitorLocalVariableIndex)); + } + } + } + + /* + * Verification de la portee de chaque variable : la portee generee par les + * compilateurs est incorrecte : elle commence une instruction trop tard! + * De plus, la longueur de la portee est tres importante. Elle est + * recalcul�e. + */ + private static void CheckLocalVariableRanges( + ConstantPool constants, byte[] code, LocalVariables localVariables, + DefaultVariableNameGenerator variableNameGenerator, + List listForAnalyze) + { + // Reset length + int length = localVariables.size(); + + // Remise � 1 de la longueur des port�es + for (int i=localVariables.getIndexOfFirstLocalVariable(); i0; --i) +// { +// LocalVariable lv1 = localVariables.getLocalVariableAt(i); +// +// for (int j=i-1; j>=0; --j) +// { +// LocalVariable lv2 = localVariables.getLocalVariableAt(j); +// +// if ((lv1.index == lv2.index) && +// (lv1.signature_index == lv2.signature_index) && +// (lv1.name_index == lv2.name_index)) +// { +// localVariables.remove(i); +// lv2.updateRange(lv1.start_pc); +// lv2.updateRange(lv1.start_pc+lv1.length-1); +// break; +// } +// } +// } +// } + + // Create new local variables, set range and type, update attribute + // 'exception' + /* + * Strategie : + * - Recherche de tous les instructions '?store' et '?load' + * - Determiner le type de la viariable + * - Si la variable n'est pas encore definie, ajouter une entr�e dans la + * Liste + * - Sinon, si le type est compatible + */ + private static void AnalyzeMethodCode( + ConstantPool constants, + LocalVariables localVariables, List list, + List listForAnalyze, String returnedSignature) + { + // Recherche des instructions d'ecriture des variables locales. + int length = listForAnalyze.size(); + + for (int i=0; i list, List listForAnalyze, + int varIndex, int startIndex, String returnedSignature) + { + IndexInstruction firstInstruction = + (IndexInstruction)listForAnalyze.get(startIndex); + + LocalVariable lv = + localVariables.getLocalVariableWithIndexAndOffset( + firstInstruction.index, firstInstruction.offset); + + if (lv != null) + { + // Variable locale deja traitee + + // Verification que l'attribut 'exception' est correctement + // positionn�. + if (firstInstruction.opcode == ByteCodeConstants.ASTORE) + { + AStore astore = (AStore)firstInstruction; + if (astore.valueref.opcode == ByteCodeConstants.EXCEPTIONLOAD) + lv.exceptionOrReturnAddress = true; + } + + return; + } + + final int length = listForAnalyze.size(); + + // Recherche des instructions de lecture, d'ecriture et de comparaison + // des variables locales. + for (int i=startIndex; i creation de variables + localVariables.add(new LocalVariable( + offset, 1, -1, NUMBER_TYPE, index, typesBitField)); + } + break; + case UNDEFINED_TYPE: + case OBJECT_TYPE: + // Type incompatible => creation de variables + localVariables.add(new LocalVariable( + offset, 1, -1, NUMBER_TYPE, index, typesBitField)); + break; + default: + String signatureLV = + constants.getConstantUtf8(lv.signature_index); + int typesBitFieldLV = + SignatureUtil.CreateTypesBitField(signatureLV); + + if ((typesBitField & typesBitFieldLV) != 0) + { + lv.updateRange(offset); + } + else + { + // Type incompatible => creation de variables + localVariables.add(new LocalVariable( + offset, 1, -1, NUMBER_TYPE, index, typesBitField)); + } + } + } + } + } + + private static void AnalyzeILoad( + LocalVariables localVariables, Instruction instruction) + { + IndexInstruction load = (IndexInstruction)instruction; + int index = load.index; + int offset = load.offset; + + LocalVariable lv = + localVariables.searchLocalVariableWithIndexAndOffset(index, offset); + + if (lv == null) + { + // La premiere instruction utilisant ce slot est de type 'Load'. + // Impossible de determiner le type d'entier pour le moment. + localVariables.add(new LocalVariable( + offset, 1, -1, NUMBER_TYPE, index, + ByteCodeConstants.TBF_INT_INT|ByteCodeConstants.TBF_INT_SHORT| + ByteCodeConstants.TBF_INT_BYTE|ByteCodeConstants.TBF_INT_CHAR| + ByteCodeConstants.TBF_INT_BOOLEAN)); + } + else + { + lv.updateRange(offset); + } + } + + private static void AnalyzeLoad( + LocalVariables localVariables, Instruction instruction) + { + IndexInstruction load = (IndexInstruction)instruction; + int index = load.index; + int offset = load.offset; + + LocalVariable lv = + localVariables.searchLocalVariableWithIndexAndOffset(index, offset); + + if (lv == null) + { + localVariables.add(new LocalVariable( + offset, 1, -1, -1, index)); + } + else + { + lv.updateRange(offset); + } + } + + private static void AnalyzeALoad( + LocalVariables localVariables, Instruction instruction) + { + IndexInstruction load = (IndexInstruction)instruction; + int index = load.index; + int offset = load.offset; + + LocalVariable lv = + localVariables.searchLocalVariableWithIndexAndOffset(index, offset); + + if (lv == null) + { + localVariables.add(new LocalVariable( + offset, 1, -1, UNDEFINED_TYPE, index)); + } + else + { + lv.updateRange(offset); + } + } + + private static void AnalyzeInvokeInstruction( + ConstantPool constants, LocalVariables localVariables, + Instruction instruction, int varIndex) + { + final InvokeInstruction invokeInstruction = + (InvokeInstruction)instruction; + final List args = invokeInstruction.args; + final List argSignatures = + invokeInstruction.getListOfParameterSignatures(constants); + final int nbrOfArgs = args.size(); + + for (int j=0; j creation de variables + localVariables.add(new LocalVariable( + offset, 1, -1, signatureIndex, index)); + } + } + } + + private static void AnalyzeAStore( + ConstantPool constants, LocalVariables localVariables, + Instruction instruction) + { + StoreInstruction store = (StoreInstruction)instruction; + int index = store.index; + int offset = store.offset; + + LocalVariable lv = + localVariables.searchLocalVariableWithIndexAndOffset(index, offset); + String signatureInstruction = + instruction.getReturnedSignature(constants, localVariables); + int signatureInstructionIndex = (signatureInstruction != null) ? + constants.addConstantUtf8(signatureInstruction) : UNDEFINED_TYPE; + boolean isExceptionOrReturnAddress = + (store.valueref.opcode == FastConstants.EXCEPTIONLOAD) || + (store.valueref.opcode == FastConstants.RETURNADDRESSLOAD); + + if ((lv == null) || lv.exceptionOrReturnAddress || + (isExceptionOrReturnAddress && (lv.start_pc + lv.length < offset))) + { + localVariables.add(new LocalVariable( + offset, 1, -1, signatureInstructionIndex, index, + isExceptionOrReturnAddress)); + } + else if (isExceptionOrReturnAddress == false) + { + // Une variable est trouv�e. Le type est il compatible ? + if (lv.signature_index == UNDEFINED_TYPE) + { + // Cas particulier Jikes 1.2.2 bloc finally : + // Une instruction ALoad apparait avant AStore + lv.signature_index = signatureInstructionIndex; + lv.updateRange(offset); + } + else if (lv.signature_index == NUMBER_TYPE) + { + // Creation de variables + localVariables.add(new LocalVariable( + offset, 1, -1, signatureInstructionIndex, index)); + } + else if ((lv.signature_index == signatureInstructionIndex) || + (lv.signature_index == OBJECT_TYPE)) + { + lv.updateRange(offset); + } + else + { + // Type incompatible => 2 cas : + // 1) si une signature est de type 'Object' et la seconde est + // un type primitif, creation d'une nouvelle variable. + // 2) si les deux signatures sont de type 'Object', + // modification du type de la variable en 'Object' puis + // ajout d'instruction cast. + String signatureLV = + constants.getConstantUtf8(lv.signature_index); + + if (SignatureUtil.IsPrimitiveSignature(signatureLV)) + { + // Creation de variables + localVariables.add(new LocalVariable( + offset, 1, -1, signatureInstructionIndex, index)); + } + else if (signatureInstructionIndex != UNDEFINED_TYPE) + { + // Modification du type de variable + lv.signature_index = OBJECT_TYPE; + lv.updateRange(offset); + } + else + { + // Affectation de NULL a une variable de type connu et non + // primitif + lv.updateRange(offset); + } + } + } + } + + // Substitution des types byte par char dans les instructions + // bipush, sipush et iconst suivants les instructions istore et invoke. + private static void SetConstantTypes( + ClassFile classFile, ConstantPool constants, Method method, + LocalVariables localVariables, List list, + List listForAnalyze, String returnedSignature) + { + final int length = listForAnalyze.size(); + + // Affection du type des constantes depuis les instructions m�res + for (int i=0; i args = invokeInstruction.args; + final List types = + invokeInstruction.getListOfParameterSignatures(constants); + final int nbrOfArgs = args.size(); + + for (int j=0; j list, TernaryOpStore tos) + { + switch (tos.objectref.opcode) + { + case ByteCodeConstants.BIPUSH: + case ByteCodeConstants.ICONST: + case ByteCodeConstants.SIPUSH: + // Recherche de la seconde valeur de l'instruction ternaire + int index = InstructionUtil.getIndexForOffset( + list, tos.ternaryOp2ndValueOffset); + + if (index != -1) + { + int length = list.size(); + + while (index < length) + { + Instruction result = + SearchInstructionByOffsetVisitor.visit( + list.get(index), tos.ternaryOp2ndValueOffset); + + if (result != null) + { + String signature = + result.getReturnedSignature(constants, localVariables); + ((IConst)tos.objectref).setReturnedSignature(signature); + break; + } + + index++; + } + } + break; + } + } + + private static void SetConstantTypesArrayStore( + ConstantPool constants, + LocalVariables localVariables, + ArrayStoreInstruction asi) + { + switch (asi.valueref.opcode) + { + case ByteCodeConstants.BIPUSH: + case ByteCodeConstants.ICONST: + case ByteCodeConstants.SIPUSH: + switch (asi.arrayref.opcode) + { + case ByteCodeConstants.ALOAD: + { + ALoad aload = (ALoad)asi.arrayref; + LocalVariable lv = localVariables.getLocalVariableWithIndexAndOffset( + aload.index, aload.offset); + + if (lv == null) + { + new Throwable("lv is null. index=" + aload.index).printStackTrace(); + return; + } + + String signature = + constants.getConstantUtf8(lv.signature_index); + ((IConst)asi.valueref).setReturnedSignature( + SignatureUtil.CutArrayDimensionPrefix(signature)); + } + break; + case ByteCodeConstants.GETFIELD: + case ByteCodeConstants.GETSTATIC: + { + IndexInstruction ii = (IndexInstruction)asi.arrayref; + ConstantFieldref cfr = + constants.getConstantFieldref(ii.index); + ConstantNameAndType cnat = + constants.getConstantNameAndType(cfr.name_and_type_index); + String signature = + constants.getConstantUtf8(cnat.descriptor_index); + ((IConst)asi.valueref).setReturnedSignature( + SignatureUtil.CutArrayDimensionPrefix(signature)); + } + break; + } + break; + } + } + + private static void SetConstantTypesIStore( + ConstantPool constants, + LocalVariables localVariables, + Instruction instruction) + { + StoreInstruction store = (StoreInstruction)instruction; + + switch (store.valueref.opcode) + { + case ByteCodeConstants.BIPUSH: + case ByteCodeConstants.ICONST: + case ByteCodeConstants.SIPUSH: + final LocalVariable lv = + localVariables.getLocalVariableWithIndexAndOffset( + store.index, store.offset); + String signature = constants.getConstantUtf8(lv.signature_index); + ((IConst)store.valueref).setReturnedSignature(signature); + break; + } + } + + private static void SetConstantTypesBinaryOperator( + ConstantPool constants, + LocalVariables localVariables, + Instruction i1, Instruction i2) + { + switch (i1.opcode) + { + case ByteCodeConstants.BIPUSH: + case ByteCodeConstants.ICONST: + case ByteCodeConstants.SIPUSH: + switch (i2.opcode) + { + case ByteCodeConstants.BIPUSH: + case ByteCodeConstants.ICONST: + case ByteCodeConstants.SIPUSH: + break; + default: + String signature = i2.getReturnedSignature( + constants, localVariables); + if (signature != null) + ((IConst)i1).setReturnedSignature(signature); + } + break; + default: + switch (i2.opcode) + { + case ByteCodeConstants.BIPUSH: + case ByteCodeConstants.ICONST: + case ByteCodeConstants.SIPUSH: + String signature = i1.getReturnedSignature( + constants, localVariables); + if (signature != null) + ((IConst)i2).setReturnedSignature(signature); + break; + } + } + } + + private static void SetConstantTypesXReturn( + Instruction instruction, String returnedSignature) + { + ReturnInstruction ri = (ReturnInstruction)instruction; + + int opcode = ri.valueref.opcode; + + if ((opcode != ByteCodeConstants.SIPUSH) && + (opcode != ByteCodeConstants.BIPUSH) && + (opcode != ByteCodeConstants.ICONST)) + return; + + ((IConst)ri.valueref).signature = returnedSignature; + } + + + private static String GetReturnedSignature( + ClassFile classFile, Method method) + { + AttributeSignature as = method.getAttributeSignature(); + int signatureIndex = (as == null) ? + method.descriptor_index : as.signature_index; + String signature = + classFile.getConstantPool().getConstantUtf8(signatureIndex); + + return SignatureUtil.GetMethodReturnedSignature(signature); + } + + private static void InitialyzeExceptionLoad( + List listForAnalyze, LocalVariables localVariables) + { + int length = listForAnalyze.size(); + + /* + * Methode d'initialisation des instructions ExceptionLoad non + * initialis�es. Cela se produit lorsque les methodes poss�dent un bloc + * de definition de variables locales. + * Les instructions ExceptionLoad appartenant aux blocs 'finally' ne + * sont pas initialis�e. + */ + for (int index=0; index 0)) + { + int varIndex = localVariables.size(); + LocalVariable localVariable = new LocalVariable( + el.offset, 1, UtilConstants.INVALID_INDEX, + el.exceptionNameIndex, varIndex, true); + localVariables.add(localVariable); + el.index = varIndex; + } + } + } + } + + private static void GenerateLocalVariableNames( + ConstantPool constants, + LocalVariables localVariables, + DefaultVariableNameGenerator variableNameGenerator) + { + final int length = localVariables.size(); + + for (int i=localVariables.getIndexOfFirstLocalVariable(); i parameterTypes, int firstIndex, + int length, String signature) + { + int counter = 0; + + for (int i=firstIndex; (i= 0) && + (lvStore.signature_index != lvLoad.signature_index)) + { + lvLoad.signature_index = lvStore.signature_index; + return true; + } + + return false; + } + + private static boolean ReverseAnalyzePutStaticPutField( + ConstantPool constants, LocalVariables localVariables, + IndexInstruction ii, LoadInstruction load) + { + LocalVariable lvLoad = + localVariables.getLocalVariableWithIndexAndOffset( + load.index, load.offset); + + if (lvLoad != null) + { + ConstantFieldref cfr = constants.getConstantFieldref(ii.index); + ConstantNameAndType cnat = + constants.getConstantNameAndType(cfr.name_and_type_index); + + if (lvLoad.signature_index == NUMBER_TYPE) + { + String descriptor = constants.getConstantUtf8(cnat.descriptor_index); + int typesBitField = SignatureUtil.CreateArgOrReturnBitFields(descriptor); + int old = lvLoad.typesBitField; + lvLoad.typesBitField &= typesBitField; + return (old != lvLoad.typesBitField); + } + else if (lvLoad.signature_index == UNDEFINED_TYPE) + { + lvLoad.signature_index = cnat.descriptor_index; + return true; + } + } + + return false; + } + + private static void AddCastInstruction( + ConstantPool constants, List list, + LocalVariables localVariables, LocalVariable lv) + { + // Add cast instruction before all 'ALoad' instruction for local + // variable le used type is not 'Object'. + AddCheckCastVisitor visitor = new AddCheckCastVisitor( + constants, localVariables, lv); + + final int length = list.size(); + + for (int i=0; i=0; --i) + { + String internalInterfaceName = + classFile.getConstantPool().getConstantClassName(interfaces[i]); + referenceMap.add(internalInterfaceName); + } + } + } + else + { + String signature = + classFile.getConstantPool().getConstantUtf8(as.signature_index); + SignatureAnalyzer.AnalyzeClassSignature(referenceMap, signature); + } + + // Class annotations + CountReferencesInAttributes( + referenceMap, classFile.getConstantPool(), classFile.getAttributes()); + + // Inner classes + ArrayList innerClassFiles = classFile.getInnerClassFiles(); + if (innerClassFiles != null) + for (int i=innerClassFiles.size()-1; i>=0; --i) + CountReferences(referenceMap, innerClassFiles.get(i)); + + ReferenceVisitor visitor = + new ReferenceVisitor(classFile.getConstantPool(), referenceMap); + + // Fields + CountReferencesInFields(referenceMap, visitor, classFile); + + // Methods + CountReferencesInMethods(referenceMap, visitor, classFile); + } + + private static void CountReferencesInAttributes( + ReferenceMap referenceMap, ConstantPool constants, + Attribute[] attributes) + { + if (attributes != null) + { + for (int i=attributes.length-1; i>=0; --i) + switch (attributes[i].tag) + { + case AttributeConstants.ATTR_RUNTIME_INVISIBLE_ANNOTATIONS: + case AttributeConstants.ATTR_RUNTIME_VISIBLE_ANNOTATIONS: + { + Annotation[] annotations = + ((AttributeRuntimeAnnotations)attributes[i]) + .annotations; + for (int j=annotations.length-1; j>=0; --j) + CountAnnotationReference(referenceMap, constants, annotations[j]); + } + break; + + case AttributeConstants.ATTR_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS: + case AttributeConstants.ATTR_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS: + { + ParameterAnnotations[] parameterAnnotations = + ((AttributeRuntimeParameterAnnotations) + attributes[i]).parameter_annotations; + CountParameterAnnotationsReference( + referenceMap, constants, parameterAnnotations); + } + break; + } + } + } + + private static void CountAnnotationReference( + ReferenceMap referenceMap, ConstantPool constants, + Annotation annotation) + { + String typeName = constants.getConstantUtf8(annotation.type_index); + SignatureAnalyzer.AnalyzeSimpleSignature(referenceMap, typeName); + + ElementValuePair[] elementValuePairs = + annotation.elementValuePairs; + if (elementValuePairs != null) + { + for (int j=elementValuePairs.length-1; j>=0; --j) + CountElementValue( + referenceMap, constants, elementValuePairs[j].element_value); + } + } + + private static void CountParameterAnnotationsReference( + ReferenceMap referenceMap, ConstantPool constants, + ParameterAnnotations[] parameterAnnotations) + { + if (parameterAnnotations != null) + { + for (int i=parameterAnnotations.length-1; i>=0; --i) + { + Annotation[] annotations = parameterAnnotations[i].annotations; + if (annotations != null) + { + for (int j=annotations.length-1; j>=0; --j) + CountAnnotationReference( + referenceMap, constants, annotations[j]); + } + } + } + } + + private static void CountElementValue( + ReferenceMap referenceMap, ConstantPool constants, ElementValue ev) + { + String signature; + ElementValueClassInfo evci; + + switch (ev.tag) + { + case ElementValueContants.EV_CLASS_INFO: + { + evci = (ElementValueClassInfo)ev; + signature = constants.getConstantUtf8(evci.class_info_index); + SignatureAnalyzer.AnalyzeSimpleSignature(referenceMap, signature); + } + break; + case ElementValueContants.EV_ANNOTATION_VALUE: + { + ElementValueAnnotationValue evanv = (ElementValueAnnotationValue)ev; + CountAnnotationReference( + referenceMap, constants, evanv.annotation_value); + } + break; + case ElementValueContants.EV_ARRAY_VALUE: + { + ElementValueArrayValue evarv = (ElementValueArrayValue)ev; + ElementValue[] values = evarv.values; + + if (values != null) + { + for (int i=values.length-1; i>=0; --i) + if (values[i].tag == ElementValueContants.EV_CLASS_INFO) + { + evci = (ElementValueClassInfo)values[i]; + signature = + constants.getConstantUtf8(evci.class_info_index); + SignatureAnalyzer.AnalyzeSimpleSignature(referenceMap, signature); + } + } + } + break; + case ElementValueContants.EV_ENUM_CONST_VALUE: + { + ElementValueEnumConstValue evecv = (ElementValueEnumConstValue)ev; + signature = constants.getConstantUtf8(evecv.type_name_index); + SignatureAnalyzer.AnalyzeSimpleSignature(referenceMap, signature); + } + break; + } + } + + private static void CountReferencesInFields( + ReferenceMap referenceMap, ReferenceVisitor visitor, + ClassFile classFile) + { + Field[] fields = classFile.getFields(); + + if (fields == null) + return; + + for (int i=fields.length-1; i>=0; --i) + { + Field field = fields[i]; + + if ((field.access_flags & ClassFileConstants.ACC_SYNTHETIC) != 0) + continue; + + CountReferencesInAttributes( + referenceMap, classFile.getConstantPool(), field.getAttributes()); + + AttributeSignature as = field.getAttributeSignature(); + String signature = classFile.getConstantPool().getConstantUtf8( + (as==null) ? field.descriptor_index : as.signature_index); + SignatureAnalyzer.AnalyzeSimpleSignature(referenceMap, signature); + + if (field.getValueAndMethod() != null) + visitor.visit(field.getValueAndMethod().getValue()); + } + } + + private static void CountReferencesInMethods( + ReferenceMap referenceMap, ReferenceVisitor visitor, + ClassFile classFile) + { + Method[] methods = classFile.getMethods(); + + if (methods == null) + return; + + ConstantPool constants = classFile.getConstantPool(); + + for (int i=methods.length-1; i>=0; --i) + { + Method method = methods[i]; + + if (((method.access_flags & + (ClassFileConstants.ACC_SYNTHETIC|ClassFileConstants.ACC_BRIDGE)) != 0) || + method.containsError()) + continue; + + CountReferencesInAttributes( + referenceMap, classFile.getConstantPool(), method.getAttributes()); + + // Signature + AttributeSignature as = method.getAttributeSignature(); + String signature = constants.getConstantUtf8( + (as==null) ? method.descriptor_index : as.signature_index); + SignatureAnalyzer.AnalyzeMethodSignature(referenceMap, signature); + + // Exceptions + int[] exceptionIndexes = method.getExceptionIndexes(); + if (exceptionIndexes != null) + for (int j=exceptionIndexes.length-1; j>=0; --j) + referenceMap.add( + constants.getConstantClassName(exceptionIndexes[j])); + + // Default annotation method value + ElementValue defaultAnnotationValue = method.getDefaultAnnotationValue(); + if (defaultAnnotationValue != null) + CountElementValue( + referenceMap, constants, defaultAnnotationValue); + + // Local variables + LocalVariables localVariables = method.getLocalVariables(); + if (localVariables != null) + CountReferencesInLocalVariables( + referenceMap, constants, localVariables); + + // Code exceptions + CodeException[] codeExceptions = method.getCodeExceptions(); + if (codeExceptions != null) + CountReferencesInCodeExceptions( + referenceMap, constants, codeExceptions); + + // Code + CountReferencesInCode(visitor, method); + } + } + + private static void CountReferencesInLocalVariables( + ReferenceMap referenceMap, ConstantPool constants, + LocalVariables localVariables) + { + for (int i=localVariables.size()-1; i>=0; --i) + { + LocalVariable lv = localVariables.getLocalVariableAt(i); + + if ((lv != null) && (lv.signature_index > 0)) + { + String signature = + constants.getConstantUtf8(lv.signature_index); + SignatureAnalyzer.AnalyzeSimpleSignature(referenceMap, signature); + } + } + } + + private static void CountReferencesInCodeExceptions( + ReferenceMap referenceMap, ConstantPool constants, + CodeException[] codeExceptions) + { + for (int i=codeExceptions.length-1; i>=0; --i) + { + CodeException ce = codeExceptions[i]; + + if (ce.catch_type != 0) + { + String internalClassName = + constants.getConstantClassName(ce.catch_type); + referenceMap.add(internalClassName); + } + } + } + + private static void CountReferencesInCode( + ReferenceVisitor visitor, Method method) + { + List instructions = method.getFastNodes(); + + if (instructions != null) + { + for (int i=instructions.size()-1; i>=0; --i) + visitor.visit(instructions.get(i)); + } + } + + private static void ReduceReferences( + ReferenceMap referenceMap, ClassFile classFile) + { + HashMap multipleInternalClassName = + new HashMap(); + + Iterator iterator = referenceMap.values().iterator(); + while (iterator.hasNext()) + { + Reference reference = iterator.next(); + String internalName = reference.getInternalName(); + + int index = + internalName.lastIndexOf(StringConstants.INTERNAL_PACKAGE_SEPARATOR); + String internalClassName = + (index != -1) ? internalName.substring(index+1) : internalName; + + if (multipleInternalClassName.containsKey(internalClassName)) + multipleInternalClassName.put(internalClassName, Boolean.TRUE); + else + multipleInternalClassName.put(internalClassName, Boolean.FALSE); + } + + iterator = referenceMap.values().iterator(); + while (iterator.hasNext()) + { + Reference reference = iterator.next(); + String internalName = reference.getInternalName(); + int index = + internalName.lastIndexOf(StringConstants.INTERNAL_PACKAGE_SEPARATOR); + String internalPackageName; + String internalClassName; + + if (index != -1) + { + internalPackageName = internalName.substring(0, index); + internalClassName = internalName.substring(index+1); + } + else + { + internalPackageName = ""; + internalClassName = internalName; + } + + String internalPackageName_className = + classFile.getInternalPackageName() + + StringConstants.INTERNAL_PACKAGE_SEPARATOR + internalClassName; + + if (!classFile.getInternalPackageName().equals(internalPackageName) && + multipleInternalClassName.get(internalClassName).booleanValue()) + { + // Remove references with same name and different packages + iterator.remove(); + } + else if (referenceMap.contains(internalPackageName_className)) + { + // Remove references with a name of same package of current class + iterator.remove(); + } + } + } +} \ No newline at end of file diff --git a/src/jd/core/process/analyzer/classfile/SignatureAnalyzer.java b/src/jd/core/process/analyzer/classfile/SignatureAnalyzer.java new file mode 100644 index 00000000..5c1df593 --- /dev/null +++ b/src/jd/core/process/analyzer/classfile/SignatureAnalyzer.java @@ -0,0 +1,199 @@ +package jd.core.process.analyzer.classfile; + +import jd.core.model.reference.ReferenceMap; +import jd.core.util.CharArrayUtil; +import jd.core.util.SignatureFormatException; + + +public class SignatureAnalyzer +{ + public static void AnalyzeClassSignature( + ReferenceMap referenceMap, String signature) + { + try // DEBUG // + { + char[] caSignature = signature.toCharArray(); + int length = caSignature.length; + int index = 0; + + // Generics + index = AnalyzeGenerics(referenceMap, caSignature, length, index); + + // Superclass + index = AnalyzeSignature(referenceMap, caSignature, length, index); + + //Interfaces + while (index < signature.length()) + index = AnalyzeSignature(referenceMap, caSignature, length, index); + } + catch (RuntimeException e) // DEBUG // + { + System.err.println("SignatureAnalyzer.AnalyzeClassSignature: Infinite loop, signature=" + signature); + throw e; + } + } + + public static void AnalyzeMethodSignature( + ReferenceMap referenceMap, String signature) + { + try // DEBUG // + { + char[] caSignature = signature.toCharArray(); + int length = caSignature.length; + int index = 0; + + // Affichage des generics + index = AnalyzeGenerics(referenceMap, caSignature, length, index); + + if (caSignature[index] != '(') + throw new SignatureFormatException(signature); + + // pass '(' + index++; + + // Arguments + while (caSignature[index] != ')') + index = AnalyzeSignature(referenceMap, caSignature, length, index); + + // pass ')' + index++; + + AnalyzeSignature(referenceMap, caSignature, length, index); + } + catch (RuntimeException e) // DEBUG // + { + System.err.println("SignatureAnalyzer.AnalyzeMethodSignature: Infinite loop, signature=" + signature); + throw e; + } + } + + public static void AnalyzeSimpleSignature( + ReferenceMap referenceMap, String signature) + { + try // DEBUG // + { + char[] caSignature = signature.toCharArray(); + AnalyzeSignature(referenceMap, caSignature, caSignature.length, 0); + } + catch (RuntimeException e) // DEBUG // + { + System.err.println("SignatureAnalyzer.AnalyzeSimpleSignature: Infinite loop, signature=" + signature); + throw e; + } + } + + private static int AnalyzeGenerics( + ReferenceMap referenceMap, char[] caSignature, int length, int index) + { + if (caSignature[index] == '<') + { + index++; + + while (index < length) + { + index = CharArrayUtil.IndexOf(caSignature, ':', index) + 1; + + // Mystere ... + if (caSignature[index] == ':') + index++; + + index = AnalyzeSignature(referenceMap, caSignature, length, index); + + if (caSignature[index] == '>') + break; + } + + index++; + } + + return index; + } + + private static int AnalyzeSignature( + ReferenceMap referenceMap, char[] caSignature, int length, int index) + { + int debugCounter = 0; // DEBUG // + char c; + + while (true) + { + // Retrait des prefixes de tableau : '[[?' ou '[L[?;' + if (caSignature[index] == '[') + { + while (++index < length) + { + if ((caSignature[index] == 'L') && + (index+1 < length) && + (caSignature[index+1] == '[')) + { + index++; + length--; + } + else if (caSignature[index] != '[') + { + break; + } + } + } + + switch(caSignature[index]) + { + case 'L' : case '.' : + boolean classFlag = (caSignature[index] == 'L'); + int beginIndex = ++index; + c = '.'; + + // Recherche de ; ou de < + while (index < length) + { + c = caSignature[index]; + if ((c == ';') || (c == '<')) + break; + index++; + } + + if (classFlag) + referenceMap.add( + CharArrayUtil.Substring(caSignature, beginIndex, index)); + + if (c == '<') + { + // pass '<' + index++; + + while (caSignature[index] != '>') + index = AnalyzeSignature( + referenceMap, caSignature, length, index); + + // pass '>' + index++; + } + + // pass ';' + if (caSignature[index] == ';') + index++; + break; + case '-' : case '+' : + index = AnalyzeSignature( + referenceMap, caSignature, length, index+1); + break; + case 'T' : + index = CharArrayUtil.IndexOf(caSignature, ';', index+1) + 1; + break; + case 'B' : case 'C' : case 'D' : case 'F' : case 'I' : + case 'J' : case 'S' : case 'V' : case 'Z' : case '*' : + index++; + } + + if ((index >= length) || (caSignature[index] != '.')) + break; + + debugCounter++; + + if (debugCounter > 3000) // DEBUG // + throw new RuntimeException("Infinite loop"); + } + + return index; + } +} \ No newline at end of file diff --git a/src/jd/core/process/analyzer/classfile/reconstructor/AssignmentInstructionReconstructor.java b/src/jd/core/process/analyzer/classfile/reconstructor/AssignmentInstructionReconstructor.java new file mode 100644 index 00000000..28165ec7 --- /dev/null +++ b/src/jd/core/process/analyzer/classfile/reconstructor/AssignmentInstructionReconstructor.java @@ -0,0 +1,378 @@ +package jd.core.process.analyzer.classfile.reconstructor; + +import java.util.List; + +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.AALoad; +import jd.core.model.instruction.bytecode.instruction.AAStore; +import jd.core.model.instruction.bytecode.instruction.ALoad; +import jd.core.model.instruction.bytecode.instruction.AStore; +import jd.core.model.instruction.bytecode.instruction.ArrayLoadInstruction; +import jd.core.model.instruction.bytecode.instruction.ArrayStoreInstruction; +import jd.core.model.instruction.bytecode.instruction.AssignmentInstruction; +import jd.core.model.instruction.bytecode.instruction.BinaryOperatorInstruction; +import jd.core.model.instruction.bytecode.instruction.DupLoad; +import jd.core.model.instruction.bytecode.instruction.DupStore; +import jd.core.model.instruction.bytecode.instruction.GetField; +import jd.core.model.instruction.bytecode.instruction.GetStatic; +import jd.core.model.instruction.bytecode.instruction.ILoad; +import jd.core.model.instruction.bytecode.instruction.IStore; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.LoadInstruction; +import jd.core.model.instruction.bytecode.instruction.PutField; +import jd.core.model.instruction.bytecode.instruction.PutStatic; +import jd.core.model.instruction.bytecode.instruction.StoreInstruction; +import jd.core.model.instruction.bytecode.instruction.TernaryOpStore; +import jd.core.model.instruction.bytecode.instruction.attribute.ValuerefAttribute; +import jd.core.process.analyzer.classfile.visitor.CompareInstructionVisitor; +import jd.core.process.analyzer.classfile.visitor.ReplaceDupLoadVisitor; +import jd.core.process.analyzer.classfile.visitor.SearchDupLoadInstructionVisitor; + + +/* + * Recontruction des affectations multiples depuis le motif : + * DupStore( ??? ) + * ... + * {?Store | PutField | PutStatic}( DupLoad ) + * ... + * ???( DupLoad ) + * Deux types de reconstruction : + * - a = b = c; + * - b = c; ...; a = b; + */ +public class AssignmentInstructionReconstructor +{ + public static void Reconstruct(List list) + { + for (int dupStoreIndex=0; dupStoreIndex 0) + { + if (list.get(j).opcode == ByteCodeConstants.TERNARYOPSTORE) + { + // TernaryOpStore trouv� + TernaryOpStore tos = (TernaryOpStore)list.get(j); + if (tos.ternaryOp2ndValueOffset == dupStore.offset) + { + tos.ternaryOp2ndValueOffset = newInstruction.offset; + break; + } + } + } + + list.remove(xstorePutfieldPutstaticIndex); + list.remove(dupStoreIndex); + dupStoreIndex--; + length -= 2; + } + else + { + // Assignation multiple sur deux lignes : b = c; a = b; + + // Create new instruction + // {?Load | GetField | GetStatic | AALoad | ARRAYLoad } + Instruction newInstruction = + CreateInstruction(xstorePutfieldPutstatic); + + if (newInstruction != null) + { + // Remplacement du 1er DupLoad + ReplaceDupLoadVisitor visitor = + new ReplaceDupLoadVisitor(dupStore, dupStore.objectref); + visitor.visit(xstorePutfieldPutstatic); + + // Remplacement du 2eme DupLoad + visitor.init(dupStore, newInstruction); + visitor.visit(list.get(dupload2Index)); + + list.remove(dupStoreIndex); + dupStoreIndex--; + length--; + } + } + } + } + } + + private static Instruction CreateInstruction( + Instruction xstorePutfieldPutstatic) + { + switch (xstorePutfieldPutstatic.opcode) + { + case ByteCodeConstants.ASTORE: + return new ALoad( + ByteCodeConstants.ALOAD, + xstorePutfieldPutstatic.offset, + xstorePutfieldPutstatic.lineNumber, + ((AStore)xstorePutfieldPutstatic).index); + case ByteCodeConstants.ISTORE: + return new ILoad( + ByteCodeConstants.ILOAD, + xstorePutfieldPutstatic.offset, + xstorePutfieldPutstatic.lineNumber, + ((IStore)xstorePutfieldPutstatic).index); + case ByteCodeConstants.STORE: + return new LoadInstruction( + ByteCodeConstants.LOAD, + xstorePutfieldPutstatic.offset, + xstorePutfieldPutstatic.lineNumber, + ((StoreInstruction)xstorePutfieldPutstatic).index, + xstorePutfieldPutstatic.getReturnedSignature(null, null)); + case ByteCodeConstants.PUTFIELD: + return new GetField( + ByteCodeConstants.GETFIELD, + xstorePutfieldPutstatic.offset, + xstorePutfieldPutstatic.lineNumber, + ((PutField)xstorePutfieldPutstatic).index, + ((PutField)xstorePutfieldPutstatic).objectref); + case ByteCodeConstants.PUTSTATIC: + return new GetStatic( + ByteCodeConstants.GETSTATIC, + xstorePutfieldPutstatic.offset, + xstorePutfieldPutstatic.lineNumber, + ((PutStatic)xstorePutfieldPutstatic).index); + case ByteCodeConstants.AASTORE: + return new AALoad( + ByteCodeConstants.ARRAYLOAD, + xstorePutfieldPutstatic.offset, + xstorePutfieldPutstatic.lineNumber, + ((AAStore)xstorePutfieldPutstatic).arrayref, + ((AAStore)xstorePutfieldPutstatic).indexref); + case ByteCodeConstants.ARRAYSTORE: + return new ArrayLoadInstruction( + ByteCodeConstants.ARRAYLOAD, + xstorePutfieldPutstatic.offset, + xstorePutfieldPutstatic.lineNumber, + ((ArrayStoreInstruction)xstorePutfieldPutstatic).arrayref, + ((ArrayStoreInstruction)xstorePutfieldPutstatic).indexref, + ((ArrayStoreInstruction)xstorePutfieldPutstatic).signature); + default: + return null; + } + } + + private static Instruction CreateAssignmentInstruction( + Instruction xstorePutfieldPutstatic, DupStore dupStore) + { + if (dupStore.objectref.opcode == ByteCodeConstants.BINARYOP) + { + // Reconstruction de "a = b += c" + Instruction value1 = + ((BinaryOperatorInstruction)dupStore.objectref).value1; + + if (xstorePutfieldPutstatic.lineNumber == value1.lineNumber) + { + switch (xstorePutfieldPutstatic.opcode) + { + case ByteCodeConstants.ASTORE: + if ((value1.opcode == ByteCodeConstants.ALOAD) && + (((StoreInstruction)xstorePutfieldPutstatic).index == + ((LoadInstruction)value1).index)) + return CreateBinaryOperatorAssignmentInstruction( + xstorePutfieldPutstatic, dupStore); + break; + case ByteCodeConstants.ISTORE: + if ((value1.opcode == ByteCodeConstants.ILOAD) && + (((StoreInstruction)xstorePutfieldPutstatic).index == + ((LoadInstruction)value1).index)) + return CreateBinaryOperatorAssignmentInstruction( + xstorePutfieldPutstatic, dupStore); + break; + case ByteCodeConstants.STORE: + if ((value1.opcode == ByteCodeConstants.LOAD) && + (((StoreInstruction)xstorePutfieldPutstatic).index == + ((LoadInstruction)value1).index)) + return CreateBinaryOperatorAssignmentInstruction( + xstorePutfieldPutstatic, dupStore); + break; + case ByteCodeConstants.PUTFIELD: + if ((value1.opcode == ByteCodeConstants.GETFIELD) && + (((PutField)xstorePutfieldPutstatic).index == + ((GetField)value1).index)) + { + CompareInstructionVisitor visitor = + new CompareInstructionVisitor(); + + if (visitor.visit( + ((PutField)xstorePutfieldPutstatic).objectref, + ((GetField)value1).objectref)) + return CreateBinaryOperatorAssignmentInstruction( + xstorePutfieldPutstatic, dupStore); + } + break; + case ByteCodeConstants.PUTSTATIC: + if ((value1.opcode == ByteCodeConstants.GETFIELD) && + (((PutStatic)xstorePutfieldPutstatic).index == + ((GetStatic)value1).index)) + return CreateBinaryOperatorAssignmentInstruction( + xstorePutfieldPutstatic, dupStore); + break; + case ByteCodeConstants.AASTORE: + if (value1.opcode == ByteCodeConstants.AALOAD) + { + ArrayStoreInstruction aas = + (ArrayStoreInstruction)xstorePutfieldPutstatic; + ArrayLoadInstruction aal = + (ArrayLoadInstruction)value1; + CompareInstructionVisitor visitor = + new CompareInstructionVisitor(); + + if (visitor.visit( + aas.arrayref, aal.arrayref) && + visitor.visit( + aas.indexref, aal.indexref)) + return CreateBinaryOperatorAssignmentInstruction( + xstorePutfieldPutstatic, dupStore); + } + break; + case ByteCodeConstants.ARRAYSTORE: + if (value1.opcode == ByteCodeConstants.ARRAYLOAD) + { + ArrayStoreInstruction aas = + (ArrayStoreInstruction)xstorePutfieldPutstatic; + ArrayLoadInstruction aal = + (ArrayLoadInstruction)value1; + CompareInstructionVisitor visitor = + new CompareInstructionVisitor(); + + if (visitor.visit( + aas.arrayref, aal.arrayref) && + visitor.visit( + aas.indexref, aal.indexref)) + return CreateBinaryOperatorAssignmentInstruction( + xstorePutfieldPutstatic, dupStore); + } + break; + case ByteCodeConstants.DSTORE: + case ByteCodeConstants.FSTORE: + case ByteCodeConstants.LSTORE: + new RuntimeException("Unexpected instruction") + .printStackTrace(); + } + } + } + + Instruction newInstruction = CreateInstruction(xstorePutfieldPutstatic); + return new AssignmentInstruction( + ByteCodeConstants.ASSIGNMENT, xstorePutfieldPutstatic.offset, + dupStore.lineNumber, 14, "=", + newInstruction, dupStore.objectref); + } + + private static AssignmentInstruction CreateBinaryOperatorAssignmentInstruction( + Instruction xstorePutfieldPutstatic, DupStore dupstore) + { + BinaryOperatorInstruction boi = + (BinaryOperatorInstruction)dupstore.objectref; + + String newOperator = boi.operator + "="; + + return new AssignmentInstruction( + ByteCodeConstants.ASSIGNMENT, xstorePutfieldPutstatic.offset, + dupstore.lineNumber, boi.getPriority(), newOperator, + CreateInstruction(xstorePutfieldPutstatic), boi.value2); + } +} diff --git a/src/jd/core/process/analyzer/classfile/reconstructor/AssignmentOperatorReconstructor.java b/src/jd/core/process/analyzer/classfile/reconstructor/AssignmentOperatorReconstructor.java new file mode 100644 index 00000000..ae44771d --- /dev/null +++ b/src/jd/core/process/analyzer/classfile/reconstructor/AssignmentOperatorReconstructor.java @@ -0,0 +1,242 @@ +package jd.core.process.analyzer.classfile.reconstructor; + +import java.util.List; + +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.ArrayLoadInstruction; +import jd.core.model.instruction.bytecode.instruction.ArrayStoreInstruction; +import jd.core.model.instruction.bytecode.instruction.AssignmentInstruction; +import jd.core.model.instruction.bytecode.instruction.BinaryOperatorInstruction; +import jd.core.model.instruction.bytecode.instruction.DupLoad; +import jd.core.model.instruction.bytecode.instruction.GetField; +import jd.core.model.instruction.bytecode.instruction.GetStatic; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.LoadInstruction; +import jd.core.model.instruction.bytecode.instruction.PutField; +import jd.core.model.instruction.bytecode.instruction.PutStatic; +import jd.core.model.instruction.bytecode.instruction.StoreInstruction; +import jd.core.process.analyzer.classfile.visitor.CompareInstructionVisitor; + + +/* + * Recontruction des operateurs d'assignation depuis les motifs : + * 1) Operation sur les attributs de classes: + * PutStatic(BinaryOperator(GetStatic(), ...)) + * 2) Operation sur les attributs d'instance: + * PutField(objectref, BinaryOperator(GetField(objectref), ...)) + * 3) Operation sur les variables locales: + * Store(BinaryOperator(Load(), ...)) + * 4) Operation sur les variables locales: + * IStore(BinaryOperator(ILoad(), ...)) + * 5) Operation sur des tableaux: + * ArrayStore(arrayref, indexref, + * BinaryOperator(ArrayLoad(arrayref, indexref), ...)) + */ +public class AssignmentOperatorReconstructor +{ + public static void Reconstruct(List list) + { + int index = list.size(); + + while (index-- > 0) + { + Instruction i = list.get(index); + + switch (i.opcode) + { + case ByteCodeConstants.PUTSTATIC: + if (((PutStatic)i).valueref.opcode == + ByteCodeConstants.BINARYOP) + index = ReconstructPutStaticOperator(list, index, i); + break; + case ByteCodeConstants.PUTFIELD: + if (((PutField)i).valueref.opcode == + ByteCodeConstants.BINARYOP) + index = ReconstructPutFieldOperator(list, index, i); + break; + case ByteCodeConstants.ISTORE: + if (((StoreInstruction)i).valueref.opcode == + ByteCodeConstants.BINARYOP) + { + BinaryOperatorInstruction boi = (BinaryOperatorInstruction) + ((StoreInstruction)i).valueref; + if (boi.value1.opcode == ByteCodeConstants.ILOAD) + index = ReconstructStoreOperator(list, index, i, boi); + } + break; + case ByteCodeConstants.STORE: + if (((StoreInstruction)i).valueref.opcode == + ByteCodeConstants.BINARYOP) + { + BinaryOperatorInstruction boi = (BinaryOperatorInstruction) + ((StoreInstruction)i).valueref; + if (boi.value1.opcode == ByteCodeConstants.LOAD) + index = ReconstructStoreOperator(list, index, i, boi); + } + break; + case ByteCodeConstants.ARRAYSTORE: + if (((ArrayStoreInstruction)i).valueref.opcode == + ByteCodeConstants.BINARYOP) + index = ReconstructArrayOperator(list, index, i); + break; + } + } + } + + /* + * PutStatic(BinaryOperator(GetStatic(), ...)) + */ + private static int ReconstructPutStaticOperator( + List list, int index, Instruction i) + { + PutStatic putStatic = (PutStatic)i; + BinaryOperatorInstruction boi = + (BinaryOperatorInstruction)putStatic.valueref; + + if (boi.value1.opcode != ByteCodeConstants.GETSTATIC) + return index; + + GetStatic getStatic = (GetStatic)boi.value1; + + if ((putStatic.lineNumber != getStatic.lineNumber) || + (putStatic.index != getStatic.index)) + return index; + + String newOperator = boi.operator + "="; + + list.set(index, new AssignmentInstruction( + ByteCodeConstants.ASSIGNMENT, putStatic.offset, + getStatic.lineNumber, boi.getPriority(), newOperator, + getStatic, boi.value2)); + + return index; + } + + /* + * PutField(objectref, BinaryOperator(GetField(objectref), ...)) + */ + private static int ReconstructPutFieldOperator( + List list, int index, Instruction i) + { + PutField putField = (PutField)i; + BinaryOperatorInstruction boi = + (BinaryOperatorInstruction)putField.valueref; + + if (boi.value1.opcode != ByteCodeConstants.GETFIELD) + return index; + + GetField getField = (GetField)boi.value1; + CompareInstructionVisitor visitor = new CompareInstructionVisitor(); + + if ((putField.lineNumber != getField.lineNumber) || + (putField.index != getField.index) || + !visitor.visit(putField.objectref, getField.objectref)) + return index; + + if (putField.objectref.opcode == ByteCodeConstants.DUPLOAD) + { + // Remove DupStore & DupLoad + DupLoad dupLoad = (DupLoad)getField.objectref; + index = DeleteDupStoreInstruction(list, index, dupLoad); + getField.objectref = dupLoad.dupStore.objectref; + } + + String newOperator = boi.operator + "="; + + list.set(index, new AssignmentInstruction( + ByteCodeConstants.ASSIGNMENT, putField.offset, + getField.lineNumber, boi.getPriority(), newOperator, + getField, boi.value2)); + + return index; + } + + /* + * StoreInstruction(BinaryOperator(LoadInstruction(), ...)) + */ + private static int ReconstructStoreOperator( + List list, int index, + Instruction i, BinaryOperatorInstruction boi) + { + StoreInstruction si = (StoreInstruction)i; + LoadInstruction li = (LoadInstruction)boi.value1; + + if ((si.lineNumber != li.lineNumber) || (si.index != li.index)) + return index; + + String newOperator = boi.operator + "="; + + list.set(index, new AssignmentInstruction( + ByteCodeConstants.ASSIGNMENT, si.offset, + li.lineNumber, boi.getPriority(), newOperator, + li, boi.value2)); + + return index; + } + + /* + * ArrayStore(arrayref, indexref, + * BinaryOperator(ArrayLoad(arrayref, indexref), ...)) + */ + private static int ReconstructArrayOperator( + List list, int index, Instruction i) + { + ArrayStoreInstruction asi = (ArrayStoreInstruction)i; + BinaryOperatorInstruction boi = (BinaryOperatorInstruction)asi.valueref; + + if (boi.value1.opcode != ByteCodeConstants.ARRAYLOAD) + return index; + + ArrayLoadInstruction ali = (ArrayLoadInstruction)boi.value1; + CompareInstructionVisitor visitor = new CompareInstructionVisitor(); + + if ((asi.lineNumber != ali.lineNumber) || + !visitor.visit(asi.arrayref, ali.arrayref) || + !visitor.visit(asi.indexref, ali.indexref)) + return index; + + if (asi.arrayref.opcode == ByteCodeConstants.DUPLOAD) + { + // Remove DupStore & DupLoad + DupLoad dupLoad = (DupLoad)ali.arrayref; + index = DeleteDupStoreInstruction(list, index, dupLoad); + ali.arrayref = dupLoad.dupStore.objectref; + } + + if (asi.indexref.opcode == ByteCodeConstants.DUPLOAD) + { + // Remove DupStore & DupLoad + DupLoad dupLoad = (DupLoad)ali.indexref; + index = DeleteDupStoreInstruction(list, index, dupLoad); + ali.indexref = dupLoad.dupStore.objectref; + } + + String newOperator = boi.operator + "="; + + list.set(index, new AssignmentInstruction( + ByteCodeConstants.ASSIGNMENT, asi.offset, + ali.lineNumber, boi.getPriority(), newOperator, + ali, boi.value2)); + + return index; + } + + private static int DeleteDupStoreInstruction( + List list, int index, DupLoad dupLoad) + { + int indexTmp = index; + + while (indexTmp-- > 0) + { + Instruction i = list.get(indexTmp); + + if (dupLoad.dupStore == i) + { + list.remove(indexTmp); + return --index; + } + } + + return index; + } +} diff --git a/src/jd/core/process/analyzer/classfile/reconstructor/DotClass118AReconstructor.java b/src/jd/core/process/analyzer/classfile/reconstructor/DotClass118AReconstructor.java new file mode 100644 index 00000000..52dd7a5f --- /dev/null +++ b/src/jd/core/process/analyzer/classfile/reconstructor/DotClass118AReconstructor.java @@ -0,0 +1,303 @@ +package jd.core.process.analyzer.classfile.reconstructor; + +import java.util.ArrayList; +import java.util.List; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.ClassFileConstants; +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.Field; +import jd.core.model.classfile.Method; +import jd.core.model.classfile.constant.ConstantConstant; +import jd.core.model.classfile.constant.ConstantFieldref; +import jd.core.model.classfile.constant.ConstantMethodref; +import jd.core.model.classfile.constant.ConstantNameAndType; +import jd.core.model.classfile.constant.ConstantString; +import jd.core.model.classfile.constant.ConstantValue; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.ANewArray; +import jd.core.model.instruction.bytecode.instruction.DupStore; +import jd.core.model.instruction.bytecode.instruction.GetStatic; +import jd.core.model.instruction.bytecode.instruction.Goto; +import jd.core.model.instruction.bytecode.instruction.IConst; +import jd.core.model.instruction.bytecode.instruction.IfInstruction; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.Invokestatic; +import jd.core.model.instruction.bytecode.instruction.Invokevirtual; +import jd.core.model.instruction.bytecode.instruction.Ldc; +import jd.core.model.instruction.bytecode.instruction.NewArray; +import jd.core.model.instruction.bytecode.instruction.PutStatic; +import jd.core.model.instruction.bytecode.instruction.TernaryOpStore; +import jd.core.model.reference.ReferenceMap; +import jd.core.process.analyzer.classfile.visitor.ReplaceDupLoadVisitor; +import jd.core.util.SignatureUtil; +import jd.core.util.StringConstants; + + +/* + * Recontruction du mot cle '.class' depuis les instructions generees par le + * JDK 1.1.8 de SUN : + * ... + * ifnotnull( getstatic( current class, 'class$...', Class ) ) + * ternaryopstore( getstatic( class, 'class$...' ) ) + * goto + * dupstore( invokestatic( current class, 'class$', nom de la classe ) ) + * putstatic( current class, 'class$...', Class, dupload ) ) + * ??? ( dupload ) + * ... + */ +public class DotClass118AReconstructor +{ + public static void Reconstruct( + ReferenceMap referenceMap, ClassFile classFile, List list) + { + int i = list.size(); + + if (i < 6) + return; + + i -= 5; + ConstantPool constants = classFile.getConstantPool(); + + while (i-- > 0) + { + Instruction instruction = list.get(i); + + if (instruction.opcode != ByteCodeConstants.IFXNULL) + continue; + + IfInstruction ii = (IfInstruction)instruction; + + if (ii.value.opcode != ByteCodeConstants.GETSTATIC) + continue; + + GetStatic gs = (GetStatic)ii.value; + + int jumpOffset = ii.GetJumpOffset(); + + instruction = list.get(i+1); + + if (instruction.opcode != ByteCodeConstants.TERNARYOPSTORE) + continue; + + TernaryOpStore tos = (TernaryOpStore)instruction; + + if ((tos.objectref.opcode != ByteCodeConstants.GETSTATIC) || + (gs.index != ((GetStatic)tos.objectref).index)) + continue; + + instruction = list.get(i+2); + + if (instruction.opcode != ByteCodeConstants.GOTO) + continue; + + Goto g = (Goto)instruction; + + instruction = list.get(i+3); + + if (instruction.opcode != ByteCodeConstants.DUPSTORE) + continue; + + if ((g.offset >= jumpOffset) || (jumpOffset > instruction.offset)) + continue; + + DupStore ds = (DupStore)instruction; + + if (ds.objectref.opcode != ByteCodeConstants.INVOKESTATIC) + continue; + + Invokestatic is = (Invokestatic)ds.objectref; + + if (is.args.size() != 1) + continue; + + instruction = is.args.get(0); + + if (instruction.opcode != ByteCodeConstants.LDC) + continue; + + ConstantMethodref cmr = + constants.getConstantMethodref(is.index); + ConstantNameAndType cnatMethod = + constants.getConstantNameAndType(cmr.name_and_type_index); + String nameMethod = constants.getConstantUtf8(cnatMethod.name_index); + + if (! nameMethod.equals(StringConstants.CLASS_DOLLAR)) + continue; + + Ldc ldc = (Ldc)instruction; + ConstantValue cv = constants.getConstantValue(ldc.index); + + if (cv.tag != ConstantConstant.CONSTANT_String) + continue; + + instruction = list.get(i+4); + + if (instruction.opcode != ByteCodeConstants.PUTSTATIC) + continue; + + PutStatic ps = (PutStatic)instruction; + + if ((ps.valueref.opcode != ByteCodeConstants.DUPLOAD) || + (ds.offset != ps.valueref.offset)) + continue; + + ConstantFieldref cfr = constants.getConstantFieldref(gs.index); + ConstantNameAndType cnatField = constants.getConstantNameAndType( + cfr.name_and_type_index); + String signatureField = + constants.getConstantUtf8(cnatField.descriptor_index); + + if (! signatureField.equals(StringConstants.INTERNAL_CLASS_SIGNATURE)) + continue; + + String nameField = constants.getConstantUtf8(cnatField.name_index); + + if (nameField.startsWith(StringConstants.CLASS_DOLLAR)) + { + // motif 'x.class' classique trouv� ! + // Substitution par une constante de type 'ClassConstant' + ConstantString cs = (ConstantString)cv; + String signature = constants.getConstantUtf8(cs.string_index); + String internalName = signature.replace( + StringConstants.PACKAGE_SEPARATOR, + StringConstants.INTERNAL_PACKAGE_SEPARATOR); + + referenceMap.add(internalName); + + // Ajout du nom interne + int index = constants.addConstantUtf8(internalName); + // Ajout d'une nouvelle classe + index = constants.addConstantClass(index); + ldc = new Ldc( + ByteCodeConstants.LDC, ii.offset, + ii.lineNumber, index); + + // Remplacement de l'intruction GetStatic par l'instruction Ldc + ReplaceDupLoadVisitor visitor = new ReplaceDupLoadVisitor(ds, ldc); + + for (int j=i+5; j(0)); + + // Remplacement de l'intruction + ReplaceDupLoadVisitor visitor = new ReplaceDupLoadVisitor(ds, iv); + + for (int j=i+5; j 0) + { + Field field = fields[j]; + + if (field.name_index == cnatField.name_index) + { + field.access_flags |= ClassFileConstants.ACC_SYNTHETIC; + break; + } + } + + // Recherche de la methode statique et ajout de l'attribut SYNTHETIC + Method[] methods = classFile.getMethods(); + j = methods.length; + + while (j-- > 0) + { + Method method = methods[j]; + + if (method.name_index == cnatMethod.name_index) + { + method.access_flags |= ClassFileConstants.ACC_SYNTHETIC; + break; + } + } + } + } +} diff --git a/src/jd/core/process/analyzer/classfile/reconstructor/DotClass14Reconstructor.java b/src/jd/core/process/analyzer/classfile/reconstructor/DotClass14Reconstructor.java new file mode 100644 index 00000000..ebaa4528 --- /dev/null +++ b/src/jd/core/process/analyzer/classfile/reconstructor/DotClass14Reconstructor.java @@ -0,0 +1,368 @@ +package jd.core.process.analyzer.classfile.reconstructor; + +import java.util.ArrayList; +import java.util.List; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.ClassFileConstants; +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.Field; +import jd.core.model.classfile.Method; +import jd.core.model.classfile.constant.ConstantConstant; +import jd.core.model.classfile.constant.ConstantFieldref; +import jd.core.model.classfile.constant.ConstantMethodref; +import jd.core.model.classfile.constant.ConstantNameAndType; +import jd.core.model.classfile.constant.ConstantString; +import jd.core.model.classfile.constant.ConstantValue; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.ANewArray; +import jd.core.model.instruction.bytecode.instruction.DupStore; +import jd.core.model.instruction.bytecode.instruction.GetStatic; +import jd.core.model.instruction.bytecode.instruction.Goto; +import jd.core.model.instruction.bytecode.instruction.IConst; +import jd.core.model.instruction.bytecode.instruction.IfInstruction; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.Invokestatic; +import jd.core.model.instruction.bytecode.instruction.Invokevirtual; +import jd.core.model.instruction.bytecode.instruction.Ldc; +import jd.core.model.instruction.bytecode.instruction.NewArray; +import jd.core.model.instruction.bytecode.instruction.PutStatic; +import jd.core.model.instruction.bytecode.instruction.TernaryOpStore; +import jd.core.model.reference.ReferenceMap; +import jd.core.process.analyzer.classfile.visitor.ReplaceGetStaticVisitor; +import jd.core.util.SignatureUtil; +import jd.core.util.StringConstants; + + +/* + * Recontruction du mot cle '.class' depuis les instructions generees par le + * JDK 1.4 de SUN : + * ... + * ifnotnull( getstatic( current or outer class, 'class$...', Class ) ) + * dupstore( invokestatic( current or outer class, 'class$', nom de la classe ) ) + * putstatic( current class, 'class$...', Class, dupload ) + * ternaryOpStore( dupload ) + * goto + * ???( getstatic( class, 'class$...' ) ) + * ... + */ +public class DotClass14Reconstructor +{ + public static void Reconstruct( + ReferenceMap referenceMap, ClassFile classFile, List list) + { + int i = list.size(); + + if (i < 6) + return; + + i -= 5; + ConstantPool constants = classFile.getConstantPool(); + + while (i-- > 0) + { + Instruction instruction = list.get(i); + + if (instruction.opcode != ByteCodeConstants.IFXNULL) + continue; + + IfInstruction ii = (IfInstruction)instruction; + + if (ii.value.opcode != ByteCodeConstants.GETSTATIC) + continue; + + int jumpOffset = ii.GetJumpOffset(); + + instruction = list.get(i+1); + + if (instruction.opcode != ByteCodeConstants.DUPSTORE) + continue; + + DupStore ds = (DupStore)instruction; + + if (ds.objectref.opcode != ByteCodeConstants.INVOKESTATIC) + continue; + + Invokestatic is = (Invokestatic)ds.objectref; + + if (is.args.size() != 1) + continue; + + instruction = is.args.get(0); + + if (instruction.opcode != ByteCodeConstants.LDC) + continue; + + instruction = list.get(i+2); + + if (instruction.opcode != ByteCodeConstants.PUTSTATIC) + continue; + + PutStatic ps = (PutStatic)instruction; + + if ((ps.valueref.opcode != ByteCodeConstants.DUPLOAD) || + (ds.offset != ps.valueref.offset)) + continue; + + instruction = list.get(i+3); + + if (instruction.opcode != ByteCodeConstants.TERNARYOPSTORE) + continue; + + TernaryOpStore tos = (TernaryOpStore)instruction; + + if ((tos.objectref.opcode != ByteCodeConstants.DUPLOAD) || + (ds.offset != tos.objectref.offset)) + continue; + + instruction = list.get(i+4); + + if (instruction.opcode != ByteCodeConstants.GOTO) + continue; + + Goto g = (Goto)instruction; + instruction = list.get(i+5); + + if ((g.offset >= jumpOffset) || (jumpOffset > instruction.offset)) + continue; + + GetStatic gs = (GetStatic)ii.value; + + if (ps.index != gs.index) + continue; + + ConstantFieldref cfr = constants.getConstantFieldref(gs.index); + + if (searchMatchingClassFile(cfr.class_index, classFile) == null) + continue; + + ConstantNameAndType cnatField = constants.getConstantNameAndType( + cfr.name_and_type_index); + + String descriptorField = + constants.getConstantUtf8(cnatField.descriptor_index); + + if (! descriptorField.equals(StringConstants.INTERNAL_CLASS_SIGNATURE)) + continue; + + String nameField = constants.getConstantUtf8(cnatField.name_index); + + if (!nameField.startsWith(StringConstants.CLASS_DOLLAR) && + !nameField.startsWith(StringConstants.ARRAY_DOLLAR)) + continue; + + ConstantMethodref cmr = + constants.getConstantMethodref(is.index); + + ClassFile matchingClassFile = + searchMatchingClassFile(cmr.class_index, classFile); + if (matchingClassFile == null) + continue; + + ConstantNameAndType cnatMethod = + constants.getConstantNameAndType(cmr.name_and_type_index); + String nameMethod = + constants.getConstantUtf8(cnatMethod.name_index); + + if (! nameMethod.equals(StringConstants.CLASS_DOLLAR)) + continue; + + Ldc ldc = (Ldc)is.args.get(0); + ConstantValue cv = constants.getConstantValue(ldc.index); + + if (cv.tag != ConstantConstant.CONSTANT_String) + continue; + + // Trouve ! + ConstantString cs = (ConstantString)cv; + String signature = constants.getConstantUtf8(cs.string_index); + + if (SignatureUtil.GetArrayDimensionCount(signature) == 0) + { + String internalName = signature.replace( + StringConstants.PACKAGE_SEPARATOR, + StringConstants.INTERNAL_PACKAGE_SEPARATOR); + + referenceMap.add(internalName); + + // Ajout du nom interne + int index = constants.addConstantUtf8(internalName); + // Ajout d'une nouvelle classe + index = constants.addConstantClass(index); + ldc = new Ldc( + ByteCodeConstants.LDC, ii.offset, + ii.lineNumber, index); + + // Remplacement de l'intruction GetStatic par l'instruction Ldc + ReplaceGetStaticVisitor visitor = + new ReplaceGetStaticVisitor(gs.index, ldc); + + visitor.visit(instruction); + } + else + { + IConst iconst0 = new IConst( + ByteCodeConstants.ICONST, ii.offset, + ii.lineNumber, 0); + Instruction newArray; + + String signatureWithoutDimension = + SignatureUtil.CutArrayDimensionPrefix(signature); + + if (SignatureUtil.IsObjectSignature(signatureWithoutDimension)) + { + // 8: iconst_0 + // 9: anewarray 62 java/lang/String + // 12: invokevirtual 64 java/lang/Object:getClass ()Ljava/lang/Class; + String tmp = signatureWithoutDimension.replace( + StringConstants.PACKAGE_SEPARATOR, + StringConstants.INTERNAL_PACKAGE_SEPARATOR); + String internalName = tmp.substring(1, tmp.length()-1); + + // Ajout du nom de la classe pour generer la liste des imports + referenceMap.add(internalName); + // Ajout du nom interne + int index = constants.addConstantUtf8(internalName); + // Ajout d'une nouvelle classe + index = constants.addConstantClass(index); + + newArray = new ANewArray( + ByteCodeConstants.ANEWARRAY, ii.offset, + ii.lineNumber, index, iconst0); + } + else + { + // 8: iconst_0 + // 9: newarray byte + // 11: invokevirtual 62 java/lang/Object:getClass ()Ljava/lang/Class; + newArray = new NewArray( + ByteCodeConstants.NEWARRAY, ii.offset, ii.lineNumber, + SignatureUtil.GetTypeFromSignature(signatureWithoutDimension), + iconst0); + } + + // Ajout de la methode 'getClass' + int methodNameIndex = constants.addConstantUtf8("getClass"); + int methodDescriptorIndex = + constants.addConstantUtf8("()Ljava/lang/Class;"); + int nameAndTypeIndex = constants.addConstantNameAndType( + methodNameIndex, methodDescriptorIndex); + int cmrIndex = constants.addConstantMethodref( + constants.objectClassIndex, nameAndTypeIndex); + + Invokevirtual iv = new Invokevirtual( + ByteCodeConstants.INVOKEVIRTUAL, ii.offset, + ii.lineNumber, cmrIndex, newArray, + new ArrayList(0)); + + // Remplacement de l'intruction GetStatic + ReplaceGetStaticVisitor visitor = + new ReplaceGetStaticVisitor(gs.index, iv); + + visitor.visit(instruction); + } + + // Retrait de l'intruction Goto + list.remove(i+4); + // Retrait de l'intruction TernaryOpStore + list.remove(i+3); + // Retrait de l'intruction PutStatic + list.remove(i+2); + // Retrait de l'intruction DupStore + list.remove(i+1); + // Retrait de l'intruction IfNotNull + list.remove(i); + + if (matchingClassFile == classFile) + { + // Recherche de l'attribut statique et ajout de l'attribut SYNTHETIC + Field[] fields = classFile.getFields(); + int j = fields.length; + + while (j-- > 0) + { + Field field = fields[j]; + + if (field.name_index == cnatField.name_index) + { + field.access_flags |= ClassFileConstants.ACC_SYNTHETIC; + break; + } + } + + // Recherche de la methode statique et ajout de l'attribut SYNTHETIC + Method[] methods = classFile.getMethods(); + j = methods.length; + + while (j-- > 0) + { + Method method = methods[j]; + + if (method.name_index == cnatMethod.name_index) + { + method.access_flags |= ClassFileConstants.ACC_SYNTHETIC; + break; + } + } + } + else + { + // Recherche de l'attribut statique et ajout de l'attribut SYNTHETIC + ConstantPool matchingConstants = + matchingClassFile.getConstantPool(); + Field[] fields = matchingClassFile.getFields(); + int j = fields.length; + + + while (j-- > 0) + { + Field field = fields[j]; + + if (nameField.equals( + matchingConstants.getConstantUtf8(field.name_index))) + { + field.access_flags |= ClassFileConstants.ACC_SYNTHETIC; + break; + } + } + + // Recherche de la methode statique et ajout de l'attribut SYNTHETIC + Method[] methods = matchingClassFile.getMethods(); + j = methods.length; + + while (j-- > 0) + { + Method method = methods[j]; + + if (nameMethod.equals( + matchingConstants.getConstantUtf8(method.name_index))) + { + method.access_flags |= ClassFileConstants.ACC_SYNTHETIC; + break; + } + } + } + } + } + + private static ClassFile searchMatchingClassFile( + int classIndex, ClassFile classFile) + { + if (classIndex == classFile.getThisClassIndex()) + return classFile; + + String className = + classFile.getConstantPool().getConstantClassName(classIndex); + + for (;;) + { + classFile = classFile.getOuterClass(); + + if (classFile == null) + return null; + + if (classFile.getThisClassName().equals(className)) + return classFile; + } + } +} diff --git a/src/jd/core/process/analyzer/classfile/reconstructor/DupStoreThisReconstructor.java b/src/jd/core/process/analyzer/classfile/reconstructor/DupStoreThisReconstructor.java new file mode 100644 index 00000000..4df6f174 --- /dev/null +++ b/src/jd/core/process/analyzer/classfile/reconstructor/DupStoreThisReconstructor.java @@ -0,0 +1,79 @@ +package jd.core.process.analyzer.classfile.reconstructor; + +import java.util.List; + +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.ALoad; +import jd.core.model.instruction.bytecode.instruction.DupLoad; +import jd.core.model.instruction.bytecode.instruction.DupStore; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.MonitorEnter; +import jd.core.process.analyzer.classfile.visitor.ReplaceDupLoadVisitor; + + +/* + * Elimine la s�quence suivante: + * DupStore( ALoad(0) ) + * ... + * ???( DupLoad ) + * ... + * ???( DupLoad ) + */ +public class DupStoreThisReconstructor +{ + public static void Reconstruct(List list) + { + for (int dupStoreIndex=0; dupStoreIndex Les instructions d'initialisation et les champs ne sont pas classes dans le meme ordre. + * --> Un tableau local est utilise. + */ +public class InitDexEnumFieldsReconstructor +{ + public static void Reconstruct(ClassFile classFile) + { + Method method = classFile.getStaticMethod(); + if (method == null) + return; + + Field[] fields = classFile.getFields(); + if (fields == null) + return; + + List list = method.getFastNodes(); + if (list == null) + return; + + ConstantPool constants = classFile.getConstantPool(); + + // Search field initialisation from the end + + // Search PutStatic("ENUM$VALUES", ALoad(...)) + int indexInstruction = list.size(); + + if (indexInstruction > 0) + { + // Saute la derniere instruction 'return' + indexInstruction--; + + while (indexInstruction-- > 0) + { + Instruction instruction = list.get(indexInstruction); + if (instruction.opcode != ByteCodeConstants.PUTSTATIC) + break; + + PutStatic putStatic = (PutStatic)instruction; + if (putStatic.valueref.opcode != ByteCodeConstants.ALOAD) + break; + + ConstantFieldref cfr = constants.getConstantFieldref(putStatic.index); + if (cfr.class_index != classFile.getThisClassIndex()) + break; + + ConstantNameAndType cnat = + constants.getConstantNameAndType(cfr.name_and_type_index); + + String name = constants.getConstantUtf8(cnat.name_index); + if (! name.equals(StringConstants.ENUM_VALUES_ARRAY_NAME_ECLIPSE)) + break; + + int indexField = fields.length; + + while (indexField-- > 0) + { + Field field = fields[indexField]; + + if (((field.access_flags & (ClassFileConstants.ACC_STATIC|ClassFileConstants.ACC_SYNTHETIC|ClassFileConstants.ACC_FINAL|ClassFileConstants.ACC_PRIVATE)) == + (ClassFileConstants.ACC_STATIC|ClassFileConstants.ACC_SYNTHETIC|ClassFileConstants.ACC_FINAL|ClassFileConstants.ACC_PRIVATE)) && + (cnat.descriptor_index == field.descriptor_index) && + (cnat.name_index == field.name_index)) + { + // "ENUM$VALUES = ..." found. + ALoad aload = (ALoad)putStatic.valueref; + int localEnumArrayIndex = aload.index; + int index = indexInstruction; + + // Middle instructions of pattern : AAStore(...) + ArrayList values = new ArrayList(); + + while (index-- > 0) + { + instruction = list.get(index); + if (instruction.opcode != ByteCodeConstants.AASTORE) + break; + AAStore aastore = (AAStore)instruction; + if ((aastore.arrayref.opcode != ByteCodeConstants.ALOAD) || + (aastore.valueref.opcode != ByteCodeConstants.GETSTATIC) || + (((ALoad)aastore.arrayref).index != localEnumArrayIndex)) + break; + values.add(aastore.valueref); + } + + // FastDeclaration(AStore(...)) + if (instruction.opcode != FastConstants.DECLARE) + break; + FastDeclaration declaration = (FastDeclaration)instruction; + if (declaration.instruction.opcode != ByteCodeConstants.ASTORE) + break; + AStore astore = (AStore)declaration.instruction; + if (astore.index != localEnumArrayIndex) + break; + + int valuesLength = values.size(); + + if (valuesLength > 0) + { + // Pattern found. + + // Construct new pattern + InitArrayInstruction iai = + new InitArrayInstruction( + ByteCodeConstants.INITARRAY, + putStatic.offset, + declaration.lineNumber, + new ANewArray( + ByteCodeConstants.ANEWARRAY, + putStatic.offset, + declaration.lineNumber, + classFile.getThisClassIndex(), + new IConst( + ByteCodeConstants.ICONST, + putStatic.offset, + declaration.lineNumber, + valuesLength)), + values); + field.setValueAndMethod(iai, method); + + // Remove PutStatic + list.remove(indexInstruction); + // Remove AAStores + while (--indexInstruction > index) + list.remove(indexInstruction); + // Remove FastDeclaration + list.remove(indexInstruction); + } + + break; + } + } + } + } + } +} diff --git a/src/jd/core/process/analyzer/classfile/reconstructor/InitInstanceFieldsReconstructor.java b/src/jd/core/process/analyzer/classfile/reconstructor/InitInstanceFieldsReconstructor.java new file mode 100644 index 00000000..6a54306f --- /dev/null +++ b/src/jd/core/process/analyzer/classfile/reconstructor/InitInstanceFieldsReconstructor.java @@ -0,0 +1,326 @@ +package jd.core.process.analyzer.classfile.reconstructor; + +import java.util.ArrayList; +import java.util.List; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.ClassFileConstants; +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.Field; +import jd.core.model.classfile.Method; +import jd.core.model.classfile.constant.ConstantFieldref; +import jd.core.model.classfile.constant.ConstantMethodref; +import jd.core.model.classfile.constant.ConstantNameAndType; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.ALoad; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.Invokespecial; +import jd.core.model.instruction.bytecode.instruction.PutField; +import jd.core.model.instruction.fast.FastConstants; +import jd.core.process.analyzer.classfile.visitor.CompareInstructionVisitor; +import jd.core.process.analyzer.classfile.visitor.SearchInstructionByOpcodeVisitor; + + +public class InitInstanceFieldsReconstructor +{ + public static void Reconstruct(ClassFile classFile) + { + ArrayList putFieldList = new ArrayList(); + ConstantPool constants = classFile.getConstantPool(); + Method[] methods = classFile.getMethods(); + + if (methods == null) + return; + + int methodIndex = methods.length; + Method putFieldListMethod = null; + + // Recherche du dernier constructeur ne faisait pas appel a 'this(...)' + while (methodIndex > 0) + { + final Method method = methods[--methodIndex]; + + if (((method.access_flags & (ClassFileConstants.ACC_SYNTHETIC|ClassFileConstants.ACC_BRIDGE)) != 0) || + (method.getCode() == null) || + (method.getFastNodes() == null) || + (method.containsError() == true) || + (method.name_index != constants.instanceConstructorIndex)) + continue; + + List list = method.getFastNodes(); + if (list == null) + continue; + + int length = list.size(); + + if (length > 0) + { + int j = GetSuperCallIndex(classFile, constants, list); + + if (j < 0) + continue; + + j++; + + int lineNumberBefore = (j > 0) ? + list.get(j-1).lineNumber : Instruction.UNKNOWN_LINE_NUMBER; + Instruction instruction = null; + + // Store init values + while (j < length) + { + instruction = list.get(j++); + if (instruction.opcode != ByteCodeConstants.PUTFIELD) + break; + + PutField putField = (PutField)instruction; + ConstantFieldref cfr = constants.getConstantFieldref(putField.index); + + if ((cfr.class_index != classFile.getThisClassIndex()) || + (putField.objectref.opcode != ByteCodeConstants.ALOAD)) + break; + + ALoad aLaod = (ALoad)putField.objectref; + if (aLaod.index != 0) + break; + + Instruction valueInstruction = + SearchInstructionByOpcodeVisitor.visit( + putField.valueref, ByteCodeConstants.ALOAD); + if ((valueInstruction != null) && + (((ALoad)valueInstruction).index != 0)) + break; + if (SearchInstructionByOpcodeVisitor.visit( + putField.valueref, ByteCodeConstants.LOAD) != null) + break; + if (SearchInstructionByOpcodeVisitor.visit( + putField.valueref, ByteCodeConstants.ILOAD) != null) + break; + + putFieldList.add(putField); + putFieldListMethod = method; + } + + // Filter list of 'PUTFIELD' + if ((lineNumberBefore != Instruction.UNKNOWN_LINE_NUMBER) && + (instruction != null)) + { + int i = putFieldList.size(); + int lineNumberAfter = instruction.lineNumber; + + // Si l'instruction qui suit la serie de 'PUTFIELD' est une + // 'RETURN' ayant le meme numero de ligne que le dernier + // 'PUTFIELD', le constructeur est synthetique et ne sera + // pas filtre. + if ((instruction.opcode != ByteCodeConstants.RETURN) || + (j != length) || (i == 0) || + (lineNumberAfter != putFieldList.get(i-1).lineNumber)) + { + while (i-- > 0) + { + int lineNumber = putFieldList.get(i).lineNumber; + + if ((lineNumberBefore <= lineNumber) && + (lineNumber <= lineNumberAfter)) + { + // Remove 'PutField' instruction if it used in + // code block of constructor + putFieldList.remove(i); + } + } + } + } + } + + break; + } + + // Filter list + CompareInstructionVisitor visitor = new CompareInstructionVisitor(); + + while (methodIndex > 0) + { + final Method method = methods[--methodIndex]; + + if (((method.access_flags & + (ClassFileConstants.ACC_SYNTHETIC|ClassFileConstants.ACC_BRIDGE)) != 0)) + continue; + if (method.getCode() == null) + continue; + if (method.name_index != constants.instanceConstructorIndex) + continue; + + List list = method.getFastNodes(); + int length = list.size(); + + if (length > 0) + { + // Filter init values + int j = GetSuperCallIndex(classFile, constants, list); + + if (j < 0) + continue; + + int firstPutFieldIndex = j + 1; + int putFieldListLength = putFieldList.size(); + + // If 'putFieldList' is more loonger than 'list', + // remove extra 'putField'. + while (firstPutFieldIndex+putFieldListLength > length) + putFieldList.remove(--putFieldListLength); + + for (int i=0; i 0) && (fields != null)) + { + int fieldLength = fields.length; + int putFieldListIndex = putFieldListLength; + + while (putFieldListIndex-- > 0) + { + PutField putField = putFieldList.get(putFieldListIndex); + ConstantFieldref cfr = + constants.getConstantFieldref(putField.index); + ConstantNameAndType cnat = + constants.getConstantNameAndType(cfr.name_and_type_index); + int fieldIndex; + + for (fieldIndex=0; fieldIndex 0) + { + // Remove instructions from constructors + methodIndex = methods.length; + + while (methodIndex-- > 0) + { + final Method method = methods[methodIndex]; + + if (((method.access_flags & + (ClassFileConstants.ACC_SYNTHETIC|ClassFileConstants.ACC_BRIDGE)) != 0)) + continue; + if (method.getCode() == null) + continue; + if (method.name_index != constants.instanceConstructorIndex) + continue; + + List list = method.getFastNodes(); + int length = list.size(); + + if (length > 0) + { + // Remove instructions + putFieldListIndex = 0; + int putFieldIndex = putFieldList.get(putFieldListIndex).index; + + for (int index=0; index= putFieldListLength) + break; + putFieldIndex = + putFieldList.get(putFieldListIndex).index; + + } + } + } + } + } + } + + private static int GetSuperCallIndex( + ClassFile classFile, ConstantPool constants, List list) + { + int length = list.size(); + + for (int i=0; i list = method.getFastNodes(); + if (list == null) + return; + + ConstantPool constants = classFile.getConstantPool(); + + // Search field initialisation from the begining + int indexInstruction = 0; + int length = list.size(); + int indexField = 0; + + while (indexInstruction < length) + { + Instruction instruction = list.get(indexInstruction); + + if (instruction.opcode != ByteCodeConstants.PUTSTATIC) + break; + + PutStatic putStatic = (PutStatic)instruction; + ConstantFieldref cfr = constants.getConstantFieldref(putStatic.index); + + if (cfr.class_index != classFile.getThisClassIndex()) + break; + + ConstantNameAndType cnat = + constants.getConstantNameAndType(cfr.name_and_type_index); + + int lengthBeforeSubstitution = list.size(); + + while (indexField < fields.length) + { + Field field = fields[indexField++]; + + if (((field.access_flags & ClassFileConstants.ACC_STATIC) != 0) && + (cnat.descriptor_index == field.descriptor_index) && + (cnat.name_index == field.name_index)) + { + Instruction valueref = putStatic.valueref; + + if (SearchInstructionByOpcodeVisitor.visit( + valueref, ByteCodeConstants.ALOAD) != null) + break; + if (SearchInstructionByOpcodeVisitor.visit( + valueref, ByteCodeConstants.LOAD) != null) + break; + if (SearchInstructionByOpcodeVisitor.visit( + valueref, ByteCodeConstants.ILOAD) != null) + break; + + field.setValueAndMethod(valueref, method); + if (valueref.opcode == FastConstants.NEWANDINITARRAY) + valueref.opcode = FastConstants.INITARRAY; + list.remove(indexInstruction--); + break; + } + } + + // La substitution a-t-elle ete faite ? + if (lengthBeforeSubstitution == list.size()) + { + // Non -> On arrete. + break; + } + + indexInstruction++; + } + + // Search field initialisation from the end + indexInstruction = list.size(); + + if (indexInstruction > 0) + { + // Saute la derniere instruction 'return' + indexInstruction--; + indexField = fields.length; + + while (indexInstruction-- > 0) + { + Instruction instruction = list.get(indexInstruction); + + if (instruction.opcode != ByteCodeConstants.PUTSTATIC) + break; + + PutStatic putStatic = (PutStatic)instruction; + ConstantFieldref cfr = constants.getConstantFieldref(putStatic.index); + + if (cfr.class_index != classFile.getThisClassIndex()) + break; + + ConstantNameAndType cnat = + constants.getConstantNameAndType(cfr.name_and_type_index); + + int lengthBeforeSubstitution = list.size(); + + while (indexField-- > 0) + { + Field field = fields[indexField]; + + if (((field.access_flags & ClassFileConstants.ACC_STATIC) != 0) && + (cnat.descriptor_index == field.descriptor_index) && + (cnat.name_index == field.name_index)) + { + Instruction valueref = putStatic.valueref; + + if (SearchInstructionByOpcodeVisitor.visit( + valueref, ByteCodeConstants.ALOAD) != null) + break; + if (SearchInstructionByOpcodeVisitor.visit( + valueref, ByteCodeConstants.LOAD) != null) + break; + if (SearchInstructionByOpcodeVisitor.visit( + valueref, ByteCodeConstants.ILOAD) != null) + break; + + field.setValueAndMethod(valueref, method); + if (valueref.opcode == FastConstants.NEWANDINITARRAY) + valueref.opcode = FastConstants.INITARRAY; + list.remove(indexInstruction); + break; + } + } + + // La substitution a-t-elle ete faite ? + if (lengthBeforeSubstitution == list.size()) + { + // Non -> On arrete. + break; + } + } + } + } +} diff --git a/src/jd/core/process/analyzer/classfile/reconstructor/NewInstructionReconstructor.java b/src/jd/core/process/analyzer/classfile/reconstructor/NewInstructionReconstructor.java new file mode 100644 index 00000000..19eb13fc --- /dev/null +++ b/src/jd/core/process/analyzer/classfile/reconstructor/NewInstructionReconstructor.java @@ -0,0 +1,91 @@ +package jd.core.process.analyzer.classfile.reconstructor; + +import java.util.List; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.Method; +import jd.core.model.classfile.constant.ConstantMethodref; +import jd.core.model.classfile.constant.ConstantNameAndType; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.DupLoad; +import jd.core.model.instruction.bytecode.instruction.DupStore; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.InvokeNew; +import jd.core.model.instruction.bytecode.instruction.Invokespecial; +import jd.core.model.instruction.bytecode.instruction.New; +import jd.core.process.analyzer.util.ReconstructorUtil; + + +/* + * Recontruction de l'instruction 'new' depuis le motif : + * DupStore( New(java/lang/Long) ) + * ... + * Invokespecial(DupLoad, , [ IConst_1 ]) + * ... + * ??? DupLoad + */ +public class NewInstructionReconstructor extends NewInstructionReconstructorBase +{ + public static void Reconstruct( + ClassFile classFile, Method method, List list) + { + for (int dupStoreIndex=0; dupStoreIndex 0) + { + Field innerField = innerFields[i]; + int index = innerField.anonymousClassConstructorParameterIndex; + + if (index != UtilConstants.INVALID_INDEX) + { + innerField.anonymousClassConstructorParameterIndex = + UtilConstants.INVALID_INDEX; + + if (index < argsLength) + { + Instruction arg = invokeNew.args.get(index); + + if (arg.opcode == ByteCodeConstants.CHECKCAST) + arg = ((CheckCast)arg).objectref; + + switch (arg.opcode) + { + case ByteCodeConstants.LOAD: + case ByteCodeConstants.ALOAD: + case ByteCodeConstants.ILOAD: + LocalVariable lv = + localVariables + .getLocalVariableWithIndexAndOffset( + ((IndexInstruction)arg).index, + arg.offset); + + if (lv != null) + { + // Ajout du nom du parametre au ConstantPool + // de la class anonyme + String name = + constants.getConstantUtf8(lv.name_index); + innerField.outerMethodLocalVariableNameIndex = + innerConstants.addConstantUtf8(name); + // Ajout du flag 'final' sur la variable + // locale de la methode contenant + // l'instruction "new" + lv.finalFlag = true; + } + } + } + } + } + } + } + } +} diff --git a/src/jd/core/process/analyzer/classfile/reconstructor/OuterReferenceReconstructor.java b/src/jd/core/process/analyzer/classfile/reconstructor/OuterReferenceReconstructor.java new file mode 100644 index 00000000..99b1a1f3 --- /dev/null +++ b/src/jd/core/process/analyzer/classfile/reconstructor/OuterReferenceReconstructor.java @@ -0,0 +1,121 @@ +package jd.core.process.analyzer.classfile.reconstructor; + +import java.util.HashMap; +import java.util.List; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.process.analyzer.classfile.visitor.OuterGetFieldVisitor; +import jd.core.process.analyzer.classfile.visitor.OuterGetStaticVisitor; +import jd.core.process.analyzer.classfile.visitor.OuterInvokeMethodVisitor; +import jd.core.process.analyzer.classfile.visitor.OuterPutFieldVisitor; +import jd.core.process.analyzer.classfile.visitor.OuterPutStaticVisitor; +import jd.core.process.analyzer.classfile.visitor.ReplaceMultipleOuterReferenceVisitor; +import jd.core.process.analyzer.classfile.visitor.ReplaceOuterAccessorVisitor; +import jd.core.process.analyzer.classfile.visitor.ReplaceOuterReferenceVisitor; +import jd.core.util.SignatureUtil; + + +/* + * Recontruction des references externes dans le corps des methodes des classes + * internes. + */ +public class OuterReferenceReconstructor +{ + private ClassFile classFile; + + private ReplaceOuterReferenceVisitor outerReferenceVisitor; + private ReplaceMultipleOuterReferenceVisitor multipleOuterReference; + private ReplaceOuterAccessorVisitor outerAccessorVisitor; + + private OuterGetStaticVisitor outerGetStaticVisitor; + private OuterPutStaticVisitor outerPutStaticVisitor; + private OuterGetFieldVisitor outerGetFieldVisitor; + private OuterPutFieldVisitor outerPutFieldVisitor; + private OuterInvokeMethodVisitor outerMethodVisitor; + + + public OuterReferenceReconstructor( + HashMap innerClassesMap, ClassFile classFile) + { + this.classFile = classFile; + + ConstantPool constants = classFile.getConstantPool(); + + // Initialisation des visiteurs traitant les references des classes externes + this.outerReferenceVisitor = new ReplaceOuterReferenceVisitor( + ByteCodeConstants.ALOAD, 1, + CreateOuterThisInstructionIndex(classFile)); + this.multipleOuterReference = + new ReplaceMultipleOuterReferenceVisitor(classFile); + this.outerAccessorVisitor = + new ReplaceOuterAccessorVisitor(classFile); + // Initialisation des visiteurs traitant l'acces des champs externes + this.outerGetFieldVisitor = + new OuterGetFieldVisitor(innerClassesMap, constants); + this.outerPutFieldVisitor = + new OuterPutFieldVisitor(innerClassesMap, constants); + // Initialisation du visiteur traitant l'acces des champs statics externes + this.outerGetStaticVisitor = + new OuterGetStaticVisitor(innerClassesMap, constants); + this.outerPutStaticVisitor = + new OuterPutStaticVisitor(innerClassesMap, constants); + // Initialisation du visiteur traitant l'acces des methodes externes + this.outerMethodVisitor = + new OuterInvokeMethodVisitor(innerClassesMap, constants); + } + + public void reconstruct( + Method method, List list) + { + // Inner no static class file + if (classFile.getOuterThisField() != null) + { + // Replace outer reference parameter of constructors + ConstantPool constants = classFile.getConstantPool(); + if (method.name_index == constants.instanceConstructorIndex) + this.outerReferenceVisitor.visit(list); + // Replace multiple outer references + this.multipleOuterReference.visit(list); + // Replace static call to "OuterClass access$0(InnerClass)" methods. + this.outerAccessorVisitor.visit(list); + } + + // Replace outer field accessors + this.outerGetFieldVisitor.visit(list); + this.outerPutFieldVisitor.visit(list); + // Replace outer static field accessors + this.outerGetStaticVisitor.visit(list); + this.outerPutStaticVisitor.visit(list); + // Replace outer methods accessors + this.outerMethodVisitor.visit(list); + } + + // Creation d'une nouvelle constante de type 'Fieldref', dans le + // pool, permettant l'affichage de 'OuterClass.this.' + private static int CreateOuterThisInstructionIndex(ClassFile classFile) + { + if (classFile.getOuterClass() == null) + return 0; + + String internalOuterClassName = + classFile.getOuterClass().getInternalClassName(); + String outerClassName = + SignatureUtil.GetInnerName(internalOuterClassName); + + ConstantPool constants = classFile.getConstantPool(); + + int signatureIndex = constants.addConstantUtf8(outerClassName); + int classIndex = constants.addConstantClass(signatureIndex); + int thisIndex = constants.thisLocalVariableNameIndex; + int descriptorIndex = + constants.addConstantUtf8(internalOuterClassName); + int nameAndTypeIndex = constants.addConstantNameAndType( + thisIndex, descriptorIndex); + + return constants.addConstantFieldref(classIndex, nameAndTypeIndex); + } +} diff --git a/src/jd/core/process/analyzer/classfile/reconstructor/PostIncReconstructor.java b/src/jd/core/process/analyzer/classfile/reconstructor/PostIncReconstructor.java new file mode 100644 index 00000000..72ce2041 --- /dev/null +++ b/src/jd/core/process/analyzer/classfile/reconstructor/PostIncReconstructor.java @@ -0,0 +1,145 @@ +package jd.core.process.analyzer.classfile.reconstructor; + +import java.util.List; + +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.BinaryOperatorInstruction; +import jd.core.model.instruction.bytecode.instruction.ConstInstruction; +import jd.core.model.instruction.bytecode.instruction.ConvertInstruction; +import jd.core.model.instruction.bytecode.instruction.DupStore; +import jd.core.model.instruction.bytecode.instruction.IncInstruction; +import jd.core.model.instruction.bytecode.instruction.IndexInstruction; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.PutField; +import jd.core.model.instruction.bytecode.instruction.PutStatic; +import jd.core.model.instruction.bytecode.instruction.StoreInstruction; +import jd.core.process.analyzer.util.ReconstructorUtil; + + +/* + * Recontruction des post-incrementations depuis le motif : + * DupStore( i ) + * ... + * {?Store | PutField | PutStatic}( DupLoad +/- 1 ) + * ... + * ???( DupLoad ) + */ +public class PostIncReconstructor +{ + public static void Reconstruct(List list) + { + int length = list.size(); + + for (int dupStoreIndex=0; dupStoreIndex list) + { + int length = list.size(); + + for (int dupStoreIndex=0; dupStoreIndex, [ IConst_1 ]) + */ +public class SimpleNewInstructionReconstructor + extends NewInstructionReconstructorBase +{ + public static void Reconstruct( + ClassFile classFile, Method method, List list) + { + for (int invokespecialIndex=0; + invokespecialIndex 0) + { + // AStore est associ� � une variable correctment typ�e + if (lv.signature_index != this.constants.objectSignatureIndex) + { + String signature = + this.constants.getConstantUtf8(lv.signature_index); + storeInstruction.valueref = newInstruction( + signature, storeInstruction.valueref); + } + } + } + else + { + visit(storeInstruction.valueref); + } + } + break; + case ByteCodeConstants.DUPSTORE: + visit(((DupStore)instruction).objectref); + break; + case ByteCodeConstants.CONVERT: + case ByteCodeConstants.IMPLICITCONVERT: + visit(((ConvertInstruction)instruction).value); + break; + case ByteCodeConstants.IFCMP: + { + IfCmp ifCmp = (IfCmp)instruction; + visit(ifCmp.value1); + visit(ifCmp.value2); + } + break; + case ByteCodeConstants.IF: + case ByteCodeConstants.IFXNULL: + visit(((IfInstruction)instruction).value); + break; + case ByteCodeConstants.COMPLEXIF: + { + List branchList = + ((ComplexConditionalBranchInstruction)instruction).instructions; + for (int i=branchList.size()-1; i>=0; --i) + { + visit(branchList.get(i)); + } + } + break; + case ByteCodeConstants.INSTANCEOF: + visit(((InstanceOf)instruction).objectref); + break; + case ByteCodeConstants.INVOKEINTERFACE: + case ByteCodeConstants.INVOKESPECIAL: + case ByteCodeConstants.INVOKEVIRTUAL: + { + InvokeNoStaticInstruction insi = + (InvokeNoStaticInstruction)instruction; + if (match(insi.objectref)) + { + ConstantMethodref cmr = this.constants.getConstantMethodref(insi.index); + ConstantClass cc = this.constants.getConstantClass(cmr.class_index); + + if (this.constants.objectClassNameIndex != cc.name_index) + { + Instruction i = insi.objectref; + insi.objectref = new CheckCast( + ByteCodeConstants.CHECKCAST, i.offset, + i.lineNumber, cmr.class_index, i); + } + } + else + { + visit(insi.objectref); + } + } + case ByteCodeConstants.INVOKESTATIC: + { + List list = ((InvokeInstruction)instruction).args; + List types = ((InvokeInstruction)instruction) + .getListOfParameterSignatures(this.constants); + + for (int i=list.size()-1; i>=0; --i) + { + Instruction arg = list.get(i); + if (match(arg)) + { + String signature = types.get(i); + + if (! signature.equals(StringConstants.INTERNAL_OBJECT_SIGNATURE)) + { + list.set(i, newInstruction(signature, arg)); + } + } + else + { + visit(arg); + } + } + } + break; + case ByteCodeConstants.LOOKUPSWITCH: + visit(((LookupSwitch)instruction).key); + break; + case ByteCodeConstants.MONITORENTER: + visit(((MonitorEnter)instruction).objectref); + break; + case ByteCodeConstants.MONITOREXIT: + visit(((MonitorExit)instruction).objectref); + break; + case ByteCodeConstants.MULTIANEWARRAY: + { + Instruction[] dimensions = ((MultiANewArray)instruction).dimensions; + for (int i=dimensions.length-1; i>=0; --i) + visit(dimensions[i]); + } + break; + case ByteCodeConstants.NEWARRAY: + visit(((NewArray)instruction).dimension); + break; + case ByteCodeConstants.ANEWARRAY: + visit(((ANewArray)instruction).dimension); + break; + case ByteCodeConstants.POP: + visit(((Pop)instruction).objectref); + break; + case ByteCodeConstants.GETFIELD: + { + GetField getField = (GetField)instruction; + if (match(getField.objectref)) + { + ConstantFieldref cfr = + this.constants.getConstantFieldref(getField.index); + ConstantClass cc = this.constants.getConstantClass(cfr.class_index); + + if (this.constants.objectClassNameIndex != cc.name_index) + { + Instruction i = getField.objectref; + getField.objectref = new CheckCast( + ByteCodeConstants.CHECKCAST, i.offset, + i.lineNumber, cfr.class_index, i); + } + } + else + { + visit(getField.objectref); + } + } + break; + case ByteCodeConstants.PUTFIELD: + { + PutField putField = (PutField)instruction; + if (match(putField.objectref)) + { + ConstantFieldref cfr = + this.constants.getConstantFieldref(putField.index); + ConstantClass cc = this.constants.getConstantClass(cfr.class_index); + + if (this.constants.objectClassNameIndex != cc.name_index) + { + Instruction i = putField.objectref; + putField.objectref = new CheckCast( + ByteCodeConstants.CHECKCAST, i.offset, + i.lineNumber, cfr.class_index, i); + } + } + else + { + visit(putField.objectref); + } + if (match(putField.valueref)) + { + ConstantFieldref cfr = constants.getConstantFieldref(putField.index); + ConstantNameAndType cnat = + constants.getConstantNameAndType(cfr.name_and_type_index); + + if (cnat.descriptor_index != this.constants.objectSignatureIndex) + { + String signature = + this.constants.getConstantUtf8(cnat.descriptor_index); + putField.valueref = newInstruction( + signature, putField.valueref); + } + } + else + { + visit(putField.valueref); + } + } + break; + case ByteCodeConstants.PUTSTATIC: + { + PutStatic putStatic = (PutStatic)instruction; + if (match(putStatic.valueref)) + { + ConstantFieldref cfr = constants.getConstantFieldref(putStatic.index); + ConstantNameAndType cnat = + constants.getConstantNameAndType(cfr.name_and_type_index); + + if (cnat.descriptor_index != this.constants.objectSignatureIndex) + { + String signature = + this.constants.getConstantUtf8(cnat.descriptor_index); + putStatic.valueref = newInstruction( + signature, putStatic.valueref); + } + } + else + { + visit(putStatic.valueref); + } + } + break; + case ByteCodeConstants.XRETURN: + visit(((ReturnInstruction)instruction).valueref); + break; + case ByteCodeConstants.TABLESWITCH: + visit(((TableSwitch)instruction).key); + break; + case ByteCodeConstants.TERNARYOPSTORE: + visit(((TernaryOpStore)instruction).objectref); + break; + case ByteCodeConstants.TERNARYOP: + { + TernaryOperator to = (TernaryOperator)instruction; + visit(to.value1); + visit(to.value2); + } + break; + case ByteCodeConstants.ACONST_NULL: + case ByteCodeConstants.ARRAYLOAD: + case ByteCodeConstants.LOAD: + case ByteCodeConstants.ALOAD: + case ByteCodeConstants.ILOAD: + case ByteCodeConstants.BIPUSH: + case ByteCodeConstants.ICONST: + case ByteCodeConstants.LCONST: + case ByteCodeConstants.FCONST: + case ByteCodeConstants.DCONST: + case ByteCodeConstants.DUPLOAD: + case ByteCodeConstants.GETSTATIC: + case ByteCodeConstants.OUTERTHIS: + case ByteCodeConstants.GOTO: + case ByteCodeConstants.INVOKENEW: + case ByteCodeConstants.JSR: + case ByteCodeConstants.LDC: + case ByteCodeConstants.LDC2_W: + case ByteCodeConstants.NEW: + case ByteCodeConstants.NOP: + case ByteCodeConstants.SIPUSH: + case ByteCodeConstants.RET: + case ByteCodeConstants.RETURN: + case ByteCodeConstants.EXCEPTIONLOAD: + case ByteCodeConstants.RETURNADDRESSLOAD: + case ByteCodeConstants.IINC: + case ByteCodeConstants.PREINC: + case ByteCodeConstants.POSTINC: + break; + default: + System.err.println( + "Can not add cast in " + + instruction.getClass().getName() + + ", opcode=" + instruction.opcode); + } + } + + private boolean match(Instruction i) + { + if (i.opcode == ByteCodeConstants.ALOAD) + { + LoadInstruction li = (LoadInstruction)i; + if (li.index == this.localVariable.index) + { + LocalVariable lv = + this.localVariables.getLocalVariableWithIndexAndOffset( + li.index, li.offset); + return lv == this.localVariable; + } + } + + return false; + } + + private Instruction newInstruction(String signature, Instruction i) + { + if (SignatureUtil.IsPrimitiveSignature(signature)) + { + return new ConvertInstruction( + ByteCodeConstants.CONVERT, i.offset, + i.lineNumber, i, signature); + } + else + { + int nameIndex; + + if (signature.charAt(0) == 'L') + { + String name = SignatureUtil.GetInnerName(signature); + nameIndex = this.constants.addConstantUtf8(name); + } + else + { + nameIndex = this.constants.addConstantUtf8(signature); + } + + int classIndex = + this.constants.addConstantClass(nameIndex); + return new CheckCast( + ByteCodeConstants.CHECKCAST, i.offset, + i.lineNumber, classIndex, i); + } + } +} diff --git a/src/jd/core/process/analyzer/classfile/visitor/CheckCastAndConvertInstructionVisitor.java b/src/jd/core/process/analyzer/classfile/visitor/CheckCastAndConvertInstructionVisitor.java new file mode 100644 index 00000000..c8bdf4d3 --- /dev/null +++ b/src/jd/core/process/analyzer/classfile/visitor/CheckCastAndConvertInstructionVisitor.java @@ -0,0 +1,310 @@ +package jd.core.process.analyzer.classfile.visitor; + +import java.util.List; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.ANewArray; +import jd.core.model.instruction.bytecode.instruction.AThrow; +import jd.core.model.instruction.bytecode.instruction.ArrayLength; +import jd.core.model.instruction.bytecode.instruction.ArrayStoreInstruction; +import jd.core.model.instruction.bytecode.instruction.AssertInstruction; +import jd.core.model.instruction.bytecode.instruction.BinaryOperatorInstruction; +import jd.core.model.instruction.bytecode.instruction.CheckCast; +import jd.core.model.instruction.bytecode.instruction.ComplexConditionalBranchInstruction; +import jd.core.model.instruction.bytecode.instruction.ConvertInstruction; +import jd.core.model.instruction.bytecode.instruction.DupStore; +import jd.core.model.instruction.bytecode.instruction.GetField; +import jd.core.model.instruction.bytecode.instruction.IConst; +import jd.core.model.instruction.bytecode.instruction.IfCmp; +import jd.core.model.instruction.bytecode.instruction.IfInstruction; +import jd.core.model.instruction.bytecode.instruction.IncInstruction; +import jd.core.model.instruction.bytecode.instruction.InitArrayInstruction; +import jd.core.model.instruction.bytecode.instruction.InstanceOf; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.InvokeInstruction; +import jd.core.model.instruction.bytecode.instruction.InvokeNoStaticInstruction; +import jd.core.model.instruction.bytecode.instruction.LookupSwitch; +import jd.core.model.instruction.bytecode.instruction.MonitorEnter; +import jd.core.model.instruction.bytecode.instruction.MonitorExit; +import jd.core.model.instruction.bytecode.instruction.MultiANewArray; +import jd.core.model.instruction.bytecode.instruction.NewArray; +import jd.core.model.instruction.bytecode.instruction.Pop; +import jd.core.model.instruction.bytecode.instruction.PutField; +import jd.core.model.instruction.bytecode.instruction.PutStatic; +import jd.core.model.instruction.bytecode.instruction.ReturnInstruction; +import jd.core.model.instruction.bytecode.instruction.StoreInstruction; +import jd.core.model.instruction.bytecode.instruction.TableSwitch; +import jd.core.model.instruction.bytecode.instruction.TernaryOpStore; +import jd.core.model.instruction.bytecode.instruction.UnaryOperatorInstruction; +import jd.core.util.SignatureUtil; + + +/* + * Elimine les doubles casts et ajoute des casts devant les constantes + * numeriques si necessaire. + */ +public class CheckCastAndConvertInstructionVisitor +{ + private static void visit(ConstantPool constants, Instruction instruction) + { + switch (instruction.opcode) + { + case ByteCodeConstants.ARRAYLENGTH: + visit(constants, ((ArrayLength)instruction).arrayref); + break; + case ByteCodeConstants.AASTORE: + case ByteCodeConstants.ARRAYSTORE: + visit(constants, ((ArrayStoreInstruction)instruction).arrayref); + break; + case ByteCodeConstants.ASSERT: + { + AssertInstruction ai = (AssertInstruction)instruction; + visit(constants, ai.test); + if (ai.msg != null) + visit(constants, ai.msg); + } + break; + case ByteCodeConstants.ATHROW: + visit(constants, ((AThrow)instruction).value); + break; + case ByteCodeConstants.UNARYOP: + visit(constants, ((UnaryOperatorInstruction)instruction).value); + break; + case ByteCodeConstants.BINARYOP: + case ByteCodeConstants.ASSIGNMENT: + { + BinaryOperatorInstruction boi = + (BinaryOperatorInstruction)instruction; + visit(constants, boi.value1); + visit(constants, boi.value2); + } + break; + case ByteCodeConstants.CHECKCAST: + { + CheckCast cc = (CheckCast)instruction; + if (cc.objectref.opcode == ByteCodeConstants.CHECKCAST) + { + cc.objectref = ((CheckCast)cc.objectref).objectref; + } + visit(constants, cc.objectref); + } + break; + case ByteCodeConstants.STORE: + case ByteCodeConstants.ASTORE: + case ByteCodeConstants.ISTORE: + visit(constants, ((StoreInstruction)instruction).valueref); + break; + case ByteCodeConstants.DUPSTORE: + visit(constants, ((DupStore)instruction).objectref); + break; + case ByteCodeConstants.CONVERT: + case ByteCodeConstants.IMPLICITCONVERT: + visit(constants, ((ConvertInstruction)instruction).value); + break; + case ByteCodeConstants.IFCMP: + { + IfCmp ifCmp = (IfCmp)instruction; + visit(constants, ifCmp.value1); + visit(constants, ifCmp.value2); + } + break; + case ByteCodeConstants.IF: + case ByteCodeConstants.IFXNULL: + visit(constants, ((IfInstruction)instruction).value); + break; + case ByteCodeConstants.COMPLEXIF: + { + List branchList = + ((ComplexConditionalBranchInstruction)instruction).instructions; + for (int i=branchList.size()-1; i>=0; --i) + { + visit(constants, branchList.get(i)); + } + } + break; + case ByteCodeConstants.INSTANCEOF: + visit(constants, ((InstanceOf)instruction).objectref); + break; + case ByteCodeConstants.INVOKEINTERFACE: + case ByteCodeConstants.INVOKESPECIAL: + case ByteCodeConstants.INVOKEVIRTUAL: + { + visit(constants, ((InvokeNoStaticInstruction)instruction).objectref); + } + case ByteCodeConstants.INVOKESTATIC: + case ByteCodeConstants.INVOKENEW: + { + List parameterSignatures = + ((InvokeInstruction)instruction). + getListOfParameterSignatures(constants); + + if (parameterSignatures != null) + { + List args = + ((InvokeInstruction)instruction).args; + int i = parameterSignatures.size(); + int j = args.size(); + + while ((i-- > 0) && (j-- > 0)) + { + Instruction arg = args.get(j); + + switch (arg.opcode) + { + case ByteCodeConstants.SIPUSH: + case ByteCodeConstants.BIPUSH: + case ByteCodeConstants.ICONST: + { + String argSignature = ((IConst)arg).getSignature(); + String parameterSignature = parameterSignatures.get(i); + + if (!parameterSignature.equals(argSignature)) + { + // Types differents + int argBitFields = + SignatureUtil.CreateArgOrReturnBitFields(argSignature); + int paramBitFields = + SignatureUtil.CreateTypesBitField(parameterSignature); + + if ((argBitFields|paramBitFields) == 0) + { + // Ajout d'une instruction cast si les types + // sont differents + args.set(j, new ConvertInstruction( + ByteCodeConstants.CONVERT, + arg.offset-1, arg.lineNumber, + arg, parameterSignature)); + } + } + else + { + switch (parameterSignature.charAt(0)) + { + case 'B': + case 'S': + // Ajout d'une instruction cast pour les + // parametres numeriques de type byte ou short + args.set(j, new ConvertInstruction( + ByteCodeConstants.CONVERT, + arg.offset-1, arg.lineNumber, + arg, parameterSignature)); + break; + default: + visit(constants, arg); + } + } + } + break; + default: + visit(constants, arg); + } + } + } + } + break; + case ByteCodeConstants.LOOKUPSWITCH: + visit(constants, ((LookupSwitch)instruction).key); + break; + case ByteCodeConstants.MONITORENTER: + visit(constants, ((MonitorEnter)instruction).objectref); + break; + case ByteCodeConstants.MONITOREXIT: + visit(constants, ((MonitorExit)instruction).objectref); + break; + case ByteCodeConstants.MULTIANEWARRAY: + { + Instruction[] dimensions = ((MultiANewArray)instruction).dimensions; + for (int i=dimensions.length-1; i>=0; --i) + { + visit(constants, dimensions[i]); + } + } + break; + case ByteCodeConstants.NEWARRAY: + visit(constants, ((NewArray)instruction).dimension); + break; + case ByteCodeConstants.ANEWARRAY: + visit(constants, ((ANewArray)instruction).dimension); + break; + case ByteCodeConstants.POP: + visit(constants, ((Pop)instruction).objectref); + break; + case ByteCodeConstants.PUTFIELD: + { + PutField putField = (PutField)instruction; + visit(constants, putField.objectref); + visit(constants, putField.valueref); + } + break; + case ByteCodeConstants.PUTSTATIC: + visit(constants, ((PutStatic)instruction).valueref); + break; + case ByteCodeConstants.XRETURN: + visit(constants, ((ReturnInstruction)instruction).valueref); + break; + case ByteCodeConstants.TABLESWITCH: + visit(constants, ((TableSwitch)instruction).key); + break; + case ByteCodeConstants.TERNARYOPSTORE: + visit(constants, ((TernaryOpStore)instruction).objectref); + break; + case ByteCodeConstants.PREINC: + case ByteCodeConstants.POSTINC: + visit(constants, ((IncInstruction)instruction).value); + break; + case ByteCodeConstants.GETFIELD: + visit(constants, ((GetField)instruction).objectref); + break; + case ByteCodeConstants.INITARRAY: + case ByteCodeConstants.NEWANDINITARRAY: + { + InitArrayInstruction iai = (InitArrayInstruction)instruction; + visit(constants, iai.newArray); + if (iai.values != null) + visit(constants, iai.values); + } + break; + case ByteCodeConstants.ACONST_NULL: + case ByteCodeConstants.ARRAYLOAD: + case ByteCodeConstants.LOAD: + case ByteCodeConstants.ALOAD: + case ByteCodeConstants.ILOAD: + case ByteCodeConstants.BIPUSH: + case ByteCodeConstants.ICONST: + case ByteCodeConstants.LCONST: + case ByteCodeConstants.FCONST: + case ByteCodeConstants.DCONST: + case ByteCodeConstants.DUPLOAD: + case ByteCodeConstants.GETSTATIC: + case ByteCodeConstants.OUTERTHIS: + case ByteCodeConstants.GOTO: + case ByteCodeConstants.IINC: + case ByteCodeConstants.JSR: + case ByteCodeConstants.LDC: + case ByteCodeConstants.LDC2_W: + case ByteCodeConstants.NEW: + case ByteCodeConstants.NOP: + case ByteCodeConstants.SIPUSH: + case ByteCodeConstants.RET: + case ByteCodeConstants.RETURN: + case ByteCodeConstants.EXCEPTIONLOAD: + case ByteCodeConstants.RETURNADDRESSLOAD: + break; + default: + System.err.println( + "Can not check cast and convert instruction in " + + instruction.getClass().getName() + + ", opcode=" + instruction.opcode); + } + } + + public static void visit( + ConstantPool constants, List instructions) + { + for (int i=instructions.size()-1; i>=0; --i) + { + visit(constants, instructions.get(i)); + } + } +} diff --git a/src/jd/core/process/analyzer/classfile/visitor/CompareInstructionVisitor.java b/src/jd/core/process/analyzer/classfile/visitor/CompareInstructionVisitor.java new file mode 100644 index 00000000..04860324 --- /dev/null +++ b/src/jd/core/process/analyzer/classfile/visitor/CompareInstructionVisitor.java @@ -0,0 +1,448 @@ +package jd.core.process.analyzer.classfile.visitor; + +import java.util.List; + +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.ANewArray; +import jd.core.model.instruction.bytecode.instruction.AThrow; +import jd.core.model.instruction.bytecode.instruction.ArrayLength; +import jd.core.model.instruction.bytecode.instruction.ArrayLoadInstruction; +import jd.core.model.instruction.bytecode.instruction.ArrayStoreInstruction; +import jd.core.model.instruction.bytecode.instruction.AssertInstruction; +import jd.core.model.instruction.bytecode.instruction.AssignmentInstruction; +import jd.core.model.instruction.bytecode.instruction.BinaryOperatorInstruction; +import jd.core.model.instruction.bytecode.instruction.CheckCast; +import jd.core.model.instruction.bytecode.instruction.ComplexConditionalBranchInstruction; +import jd.core.model.instruction.bytecode.instruction.ConstInstruction; +import jd.core.model.instruction.bytecode.instruction.ConvertInstruction; +import jd.core.model.instruction.bytecode.instruction.DupLoad; +import jd.core.model.instruction.bytecode.instruction.DupStore; +import jd.core.model.instruction.bytecode.instruction.GetField; +import jd.core.model.instruction.bytecode.instruction.IConst; +import jd.core.model.instruction.bytecode.instruction.IfCmp; +import jd.core.model.instruction.bytecode.instruction.IfInstruction; +import jd.core.model.instruction.bytecode.instruction.IncInstruction; +import jd.core.model.instruction.bytecode.instruction.InitArrayInstruction; +import jd.core.model.instruction.bytecode.instruction.InstanceOf; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.InvokeInstruction; +import jd.core.model.instruction.bytecode.instruction.InvokeNew; +import jd.core.model.instruction.bytecode.instruction.InvokeNoStaticInstruction; +import jd.core.model.instruction.bytecode.instruction.LoadInstruction; +import jd.core.model.instruction.bytecode.instruction.MultiANewArray; +import jd.core.model.instruction.bytecode.instruction.NewArray; +import jd.core.model.instruction.bytecode.instruction.PutField; +import jd.core.model.instruction.bytecode.instruction.StoreInstruction; +import jd.core.model.instruction.bytecode.instruction.TernaryOpStore; +import jd.core.model.instruction.bytecode.instruction.TernaryOperator; +import jd.core.model.instruction.bytecode.instruction.UnaryOperatorInstruction; + + + +public class CompareInstructionVisitor +{ + public boolean visit(Instruction i1, Instruction i2) + { + if (i1.opcode != i2.opcode) + return false; + + switch (i1.opcode) + { + case ByteCodeConstants.ARRAYLENGTH: + return visit( + ((ArrayLength)i1).arrayref, ((ArrayLength)i2).arrayref); + case ByteCodeConstants.AASTORE: + case ByteCodeConstants.ARRAYSTORE: + { + if (((ArrayStoreInstruction)i1).signature.compareTo( + ((ArrayStoreInstruction)i2).signature) != 0) + return false; + + if (! visit( + ((ArrayStoreInstruction)i1).arrayref, + ((ArrayStoreInstruction)i2).arrayref)) + return false; + + if (! visit( + ((ArrayStoreInstruction)i1).indexref, + ((ArrayStoreInstruction)i2).indexref)) + return false; + + return visit( + ((ArrayStoreInstruction)i1).valueref, + ((ArrayStoreInstruction)i2).valueref); + } + case ByteCodeConstants.ASSERT: + { + if (! visit( + ((AssertInstruction)i1).test, + ((AssertInstruction)i2).test)) + return false; + + Instruction msg1 = ((AssertInstruction)i1).msg; + Instruction msg2 = ((AssertInstruction)i2).msg; + + if (msg1 == msg2) + return true; + if ((msg1 == null) || (msg2 == null)) + return false; + return visit(msg1, msg2); + } + case ByteCodeConstants.ATHROW: + return visit(((AThrow)i1).value, ((AThrow)i2).value); + case ByteCodeConstants.UNARYOP: + { + if (((UnaryOperatorInstruction)i1).getPriority() != + ((UnaryOperatorInstruction)i2).getPriority()) + return false; + + if (((UnaryOperatorInstruction)i1).signature.compareTo( + ((UnaryOperatorInstruction)i2).signature) != 0) + return false; + + if (((UnaryOperatorInstruction)i1).operator.compareTo( + ((UnaryOperatorInstruction)i2).operator) != 0) + return false; + + return visit( + ((UnaryOperatorInstruction)i1).value, + ((UnaryOperatorInstruction)i2).value); + } + case ByteCodeConstants.BINARYOP: + { + if (((BinaryOperatorInstruction)i1).getPriority() != + ((BinaryOperatorInstruction)i2).getPriority()) + return false; + + if (((BinaryOperatorInstruction)i1).signature.compareTo( + ((BinaryOperatorInstruction)i2).signature) != 0) + return false; + + if (((BinaryOperatorInstruction)i1).operator.compareTo( + ((BinaryOperatorInstruction)i2).operator) != 0) + return false; + + if (! visit( + ((BinaryOperatorInstruction)i1).value1, + ((BinaryOperatorInstruction)i2).value1)) + return false; + + return visit( + ((BinaryOperatorInstruction)i1).value2, + ((BinaryOperatorInstruction)i2).value2); + } + case ByteCodeConstants.CHECKCAST: + { + if (((CheckCast)i1).index != ((CheckCast)i2).index) + return false; + + return visit( + ((CheckCast)i1).objectref, ((CheckCast)i2).objectref); + } + case ByteCodeConstants.STORE: + case ByteCodeConstants.ASTORE: + case ByteCodeConstants.ISTORE: + { + String rs1 = ((StoreInstruction)i1).getReturnedSignature(null, null); + String rs2 = ((StoreInstruction)i2).getReturnedSignature(null, null); + if ((rs1 == null) ? (rs2 != null) : (rs1.compareTo(rs2) != 0)) + return false; + + return visit( + ((StoreInstruction)i1).valueref, + ((StoreInstruction)i2).valueref); + } + case ByteCodeConstants.DUPSTORE: + return visit( + ((DupStore)i1).objectref, ((DupStore)i2).objectref); + case ByteCodeConstants.CONVERT: + case ByteCodeConstants.IMPLICITCONVERT: + { + if (((ConvertInstruction)i1).signature.compareTo( + ((ConvertInstruction)i2).signature) != 0) + return false; + + return visit( + ((ConvertInstruction)i1).value, + ((ConvertInstruction)i2).value); + } + case ByteCodeConstants.IFCMP: + { + if (((IfCmp)i1).cmp != ((IfCmp)i2).cmp) + return false; + + // Ce test perturbe le retrait des instructions 'finally' dans + // les blocs 'try' et 'catch'. + // if (((IfCmp)i1).branch != ((IfCmp)i2).branch) + // return false; + + if (! visit(((IfCmp)i1).value1, ((IfCmp)i2).value1)) + return false; + + return visit(((IfCmp)i1).value2, ((IfCmp)i2).value2); + } + case ByteCodeConstants.IF: + case ByteCodeConstants.IFXNULL: + { + if (((IfInstruction)i1).cmp != ((IfInstruction)i2).cmp) + return false; + + return visit( + ((IfInstruction)i1).value, ((IfInstruction)i2).value); + } + case ByteCodeConstants.COMPLEXIF: + { + if (((ComplexConditionalBranchInstruction)i1).cmp != ((ComplexConditionalBranchInstruction)i2).cmp) + return false; + + if (((ComplexConditionalBranchInstruction)i1).branch != ((ComplexConditionalBranchInstruction)i2).branch) + return false; + + return visit( + ((ComplexConditionalBranchInstruction)i1).instructions, + ((ComplexConditionalBranchInstruction)i2).instructions); + } + case ByteCodeConstants.INSTANCEOF: + { + if (((InstanceOf)i1).index != ((InstanceOf)i2).index) + return false; + + return visit( + ((InstanceOf)i1).objectref, ((InstanceOf)i2).objectref); + } + case ByteCodeConstants.INVOKEINTERFACE: + case ByteCodeConstants.INVOKESPECIAL: + case ByteCodeConstants.INVOKEVIRTUAL: + { + if (! visit( + ((InvokeNoStaticInstruction)i1).objectref, + ((InvokeNoStaticInstruction)i2).objectref)) + return false; + } + case ByteCodeConstants.INVOKESTATIC: + return visit( + ((InvokeInstruction)i1).args, ((InvokeInstruction)i2).args); + case ByteCodeConstants.INVOKENEW: + { + if (((InvokeNew)i1).index != ((InvokeNew)i2).index) + return false; + + return visit( + ((InvokeNew)i1).args, ((InvokeNew)i2).args); + } + case ByteCodeConstants.MULTIANEWARRAY: + { + if (((MultiANewArray)i1).index != ((MultiANewArray)i2).index) + return false; + + Instruction[] dimensions1 = ((MultiANewArray)i1).dimensions; + Instruction[] dimensions2 = ((MultiANewArray)i2).dimensions; + + if (dimensions1.length != dimensions2.length) + return false; + + for (int i=dimensions1.length-1; i>=0; --i) + { + if (! visit(dimensions1[i], dimensions2[i])) + return false; + } + + return true; + } + case ByteCodeConstants.NEWARRAY: + { + if (((NewArray)i1).type != ((NewArray)i2).type) + return false; + + return visit( + ((NewArray)i1).dimension, ((NewArray)i2).dimension); + } + case ByteCodeConstants.ANEWARRAY: + { + if (((ANewArray)i1).index != ((ANewArray)i2).index) + return false; + + return visit( + ((ANewArray)i1).dimension, ((ANewArray)i2).dimension); + } + case ByteCodeConstants.PUTFIELD: + { + if (! visit( + ((PutField)i1).objectref, + ((PutField)i2).objectref)) + return false; + + return visit( + ((PutField)i1).valueref, ((PutField)i2).valueref); + } + case ByteCodeConstants.TERNARYOPSTORE: + { + if (((TernaryOpStore)i1).ternaryOp2ndValueOffset-i1.offset != + ((TernaryOpStore)i2).ternaryOp2ndValueOffset-i2.offset) + return false; + + return visit( + ((TernaryOpStore)i1).objectref, + ((TernaryOpStore)i2).objectref); + } + case ByteCodeConstants.TERNARYOP: + { + if (! visit( + ((TernaryOperator)i1).test, + ((TernaryOperator)i2).test)) + return false; + + if (! visit( + ((TernaryOperator)i1).value1, + ((TernaryOperator)i2).value1)) + return false; + + return visit( + ((TernaryOperator)i1).value2, + ((TernaryOperator)i2).value2); + } + case ByteCodeConstants.ASSIGNMENT: + { + if (((AssignmentInstruction)i1).getPriority() != + ((AssignmentInstruction)i2).getPriority()) + return false; + + if (((AssignmentInstruction)i1).operator.compareTo( + ((AssignmentInstruction)i2).operator) != 0) + return false; + + if (! visit( + ((AssignmentInstruction)i1).value1, + ((AssignmentInstruction)i2).value1)) + return false; + + return visit( + ((AssignmentInstruction)i1).value2, + ((AssignmentInstruction)i2).value2); + } + case ByteCodeConstants.ARRAYLOAD: + { + String s1 = ((ArrayLoadInstruction)i1).getReturnedSignature(null, null); + String s2 = ((ArrayLoadInstruction)i2).getReturnedSignature(null, null); + + if (s1 == null) + { + if (s2 != null) + return false; + } + else + { + if (s1.compareTo(s2) != 0) + return false; + } + + if (! visit( + ((ArrayLoadInstruction)i1).arrayref, + ((ArrayLoadInstruction)i2).arrayref)) + return false; + + return visit( + ((ArrayLoadInstruction)i1).indexref, + ((ArrayLoadInstruction)i2).indexref); + } + case ByteCodeConstants.PREINC: + case ByteCodeConstants.POSTINC: + { + if (((IncInstruction)i1).count != ((IncInstruction)i2).count) + return false; + + return visit( + ((IncInstruction)i1).value, + ((IncInstruction)i2).value); + } + case ByteCodeConstants.GETFIELD: + { + if (((GetField)i1).index != ((GetField)i2).index) + return false; + + return visit( + ((GetField)i1).objectref, ((GetField)i2).objectref); + } + case ByteCodeConstants.INITARRAY: + case ByteCodeConstants.NEWANDINITARRAY: + { + if (! visit( + ((InitArrayInstruction)i1).newArray, + ((InitArrayInstruction)i2).newArray)) + return false; + + return visit(((InitArrayInstruction)i1).values, + ((InitArrayInstruction)i2).values); + } + case ByteCodeConstants.ALOAD: + case ByteCodeConstants.ILOAD: + { + String rs1 = ((LoadInstruction)i1).getReturnedSignature(null, null); + String rs2 = ((LoadInstruction)i2).getReturnedSignature(null, null); + return (rs1 == null) ? (rs2 == null) : (rs1.compareTo(rs2) == 0); + } + case ByteCodeConstants.ICONST: + case ByteCodeConstants.BIPUSH: + case ByteCodeConstants.SIPUSH: + { + if (((IConst)i1).value != ((IConst)i2).value) + return false; + + return + ((IConst)i1).signature.compareTo( + ((IConst)i2).signature) == 0; + } + case ByteCodeConstants.DCONST: + case ByteCodeConstants.LCONST: + case ByteCodeConstants.FCONST: + return ((ConstInstruction)i1).value == ((ConstInstruction)i2).value; + case ByteCodeConstants.DUPLOAD: + return ((DupLoad)i1).dupStore == ((DupLoad)i2).dupStore; + case ByteCodeConstants.TABLESWITCH: + case ByteCodeConstants.XRETURN: + case ByteCodeConstants.PUTSTATIC: + case ByteCodeConstants.LOOKUPSWITCH: + case ByteCodeConstants.MONITORENTER: + case ByteCodeConstants.MONITOREXIT: + case ByteCodeConstants.POP: + case ByteCodeConstants.ACONST_NULL: + case ByteCodeConstants.LOAD: + case ByteCodeConstants.GETSTATIC: + case ByteCodeConstants.OUTERTHIS: + case ByteCodeConstants.GOTO: + case ByteCodeConstants.IINC: + case ByteCodeConstants.JSR: + case ByteCodeConstants.LDC: + case ByteCodeConstants.LDC2_W: + case ByteCodeConstants.NEW: + case ByteCodeConstants.NOP: + case ByteCodeConstants.RET: + case ByteCodeConstants.RETURN: + case ByteCodeConstants.EXCEPTIONLOAD: + case ByteCodeConstants.RETURNADDRESSLOAD: + return true; + default: + System.err.println( + "Can not compare instruction " + + i1.getClass().getName() + " and " + i2.getClass().getName()); + return false; + } + } + + protected boolean visit( + List l1, List l2) + { + int i = l1.size(); + + if (i != l2.size()) + return false; + + while (i-- > 0) + { + if (! visit(l1.get(i), l2.get(i))) + return false; + } + + return true; + } +} diff --git a/src/jd/core/process/analyzer/classfile/visitor/OuterGetFieldVisitor.java b/src/jd/core/process/analyzer/classfile/visitor/OuterGetFieldVisitor.java new file mode 100644 index 00000000..ff0719e0 --- /dev/null +++ b/src/jd/core/process/analyzer/classfile/visitor/OuterGetFieldVisitor.java @@ -0,0 +1,86 @@ +package jd.core.process.analyzer.classfile.visitor; + +import java.util.HashMap; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.accessor.Accessor; +import jd.core.model.classfile.accessor.AccessorConstants; +import jd.core.model.classfile.accessor.GetFieldAccessor; +import jd.core.model.classfile.constant.ConstantMethodref; +import jd.core.model.classfile.constant.ConstantNameAndType; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.GetField; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.Invokestatic; + +/* + * Replace 'TestInnerClass.access$0(this.this$0)' + * par 'this.this$0.text' + */ +public class OuterGetFieldVisitor extends OuterGetStaticVisitor +{ + public OuterGetFieldVisitor( + HashMap innerClassesMap, ConstantPool constants) + { + super(innerClassesMap, constants); + } + + protected Accessor match(Instruction i) + { + if (i.opcode != ByteCodeConstants.INVOKESTATIC) + return null; + + Invokestatic is = (Invokestatic)i; + ConstantMethodref cmr = + constants.getConstantMethodref(is.index); + ConstantNameAndType cnat = + constants.getConstantNameAndType(cmr.name_and_type_index); + String descriptor = + constants.getConstantUtf8(cnat.descriptor_index); + + // Two parameters ? + if (cmr.getNbrOfParameters() != 1) + return null; + + String className = constants.getConstantClassName(cmr.class_index); + ClassFile classFile = this.innerClassesMap.get(className); + if (classFile == null) + return null; + + String name = + constants.getConstantUtf8(cnat.name_index); + + Accessor accessor = classFile.getAccessor(name, descriptor); + + if ((accessor == null) || + (accessor.tag != AccessorConstants.ACCESSOR_GETFIELD)) + return null; + + return accessor; + } + + protected Instruction newInstruction(Instruction i, Accessor a) + { + GetFieldAccessor gfa = (GetFieldAccessor)a; + Invokestatic is = (Invokestatic)i; + + int nameIndex = this.constants.addConstantUtf8(gfa.fieldName); + int descriptorIndex = + this.constants.addConstantUtf8(gfa.fieldDescriptor); + int cnatIndex = + this.constants.addConstantNameAndType(nameIndex, descriptorIndex); + + int classNameIndex = this.constants.addConstantUtf8(gfa.className); + int classIndex = this.constants.addConstantClass(classNameIndex); + + int cfrIndex = + this.constants.addConstantFieldref(classIndex, cnatIndex); + + Instruction objectref = is.args.remove(0); + + return new GetField( + ByteCodeConstants.GETFIELD, i.offset, i.lineNumber, + cfrIndex, objectref); + } +} diff --git a/src/jd/core/process/analyzer/classfile/visitor/OuterGetStaticVisitor.java b/src/jd/core/process/analyzer/classfile/visitor/OuterGetStaticVisitor.java new file mode 100644 index 00000000..38a40ed8 --- /dev/null +++ b/src/jd/core/process/analyzer/classfile/visitor/OuterGetStaticVisitor.java @@ -0,0 +1,582 @@ +package jd.core.process.analyzer.classfile.visitor; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.accessor.Accessor; +import jd.core.model.classfile.accessor.AccessorConstants; +import jd.core.model.classfile.accessor.GetStaticAccessor; +import jd.core.model.classfile.constant.ConstantMethodref; +import jd.core.model.classfile.constant.ConstantNameAndType; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.ANewArray; +import jd.core.model.instruction.bytecode.instruction.AThrow; +import jd.core.model.instruction.bytecode.instruction.ArrayLength; +import jd.core.model.instruction.bytecode.instruction.ArrayLoadInstruction; +import jd.core.model.instruction.bytecode.instruction.ArrayStoreInstruction; +import jd.core.model.instruction.bytecode.instruction.AssertInstruction; +import jd.core.model.instruction.bytecode.instruction.AssignmentInstruction; +import jd.core.model.instruction.bytecode.instruction.BinaryOperatorInstruction; +import jd.core.model.instruction.bytecode.instruction.CheckCast; +import jd.core.model.instruction.bytecode.instruction.ComplexConditionalBranchInstruction; +import jd.core.model.instruction.bytecode.instruction.ConvertInstruction; +import jd.core.model.instruction.bytecode.instruction.DupStore; +import jd.core.model.instruction.bytecode.instruction.GetField; +import jd.core.model.instruction.bytecode.instruction.GetStatic; +import jd.core.model.instruction.bytecode.instruction.IfCmp; +import jd.core.model.instruction.bytecode.instruction.IfInstruction; +import jd.core.model.instruction.bytecode.instruction.IncInstruction; +import jd.core.model.instruction.bytecode.instruction.InitArrayInstruction; +import jd.core.model.instruction.bytecode.instruction.InstanceOf; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.InvokeInstruction; +import jd.core.model.instruction.bytecode.instruction.InvokeNoStaticInstruction; +import jd.core.model.instruction.bytecode.instruction.Invokestatic; +import jd.core.model.instruction.bytecode.instruction.LookupSwitch; +import jd.core.model.instruction.bytecode.instruction.MonitorEnter; +import jd.core.model.instruction.bytecode.instruction.MonitorExit; +import jd.core.model.instruction.bytecode.instruction.MultiANewArray; +import jd.core.model.instruction.bytecode.instruction.NewArray; +import jd.core.model.instruction.bytecode.instruction.Pop; +import jd.core.model.instruction.bytecode.instruction.PutField; +import jd.core.model.instruction.bytecode.instruction.PutStatic; +import jd.core.model.instruction.bytecode.instruction.ReturnInstruction; +import jd.core.model.instruction.bytecode.instruction.StoreInstruction; +import jd.core.model.instruction.bytecode.instruction.TableSwitch; +import jd.core.model.instruction.bytecode.instruction.TernaryOpStore; +import jd.core.model.instruction.bytecode.instruction.TernaryOperator; +import jd.core.model.instruction.bytecode.instruction.UnaryOperatorInstruction; + +/* + * Replace 'EntitlementFunctionLibrary.access$000()' + * par 'EntitlementFunctionLibrary.kernelId' + */ +public class OuterGetStaticVisitor +{ + protected Map innerClassesMap; + protected ConstantPool constants; + + public OuterGetStaticVisitor( + HashMap innerClassesMap, ConstantPool constants) + { + this.innerClassesMap = innerClassesMap; + this.constants = constants; + } + + public void visit(Instruction instruction) + { + switch (instruction.opcode) + { + case ByteCodeConstants.ARRAYLENGTH: + { + ArrayLength al = (ArrayLength)instruction; + Accessor a = match(al.arrayref); + if (a != null) + al.arrayref = newInstruction(al.arrayref, a); + else + visit(al.arrayref); + } + break; + case ByteCodeConstants.AASTORE: + case ByteCodeConstants.ARRAYSTORE: + { + ArrayStoreInstruction asi = (ArrayStoreInstruction)instruction; + Accessor a = match(asi.arrayref); + if (a != null) + asi.arrayref = newInstruction(asi.arrayref, a); + else + visit(asi.arrayref); + a = match(asi.indexref); + if (a != null) + asi.indexref = newInstruction(asi.indexref, a); + else + visit(asi.indexref); + a = match(asi.valueref); + if (a != null) + asi.valueref = newInstruction(asi.valueref, a); + else + visit(asi.valueref); + } + break; + case ByteCodeConstants.ASSERT: + { + AssertInstruction ai = (AssertInstruction)instruction; + Accessor a = match(ai.test); + if (a != null) + ai.test = newInstruction(ai.test, a); + else + visit(ai.test); + if (ai.msg != null) + { + a = match(ai.msg); + if (a != null) + ai.msg = newInstruction(ai.msg, a); + else + visit(ai.msg); + } + } + break; + case ByteCodeConstants.ATHROW: + { + AThrow aThrow = (AThrow)instruction; + Accessor a = match(aThrow.value); + if (a != null) + aThrow.value = newInstruction(aThrow.value, a); + else + visit(aThrow.value); + } + break; + case ByteCodeConstants.UNARYOP: + { + UnaryOperatorInstruction uoi = (UnaryOperatorInstruction)instruction; + Accessor a = match(uoi.value); + if (a != null) + uoi.value = newInstruction(uoi.value, a); + else + visit(uoi.value); + } + break; + case ByteCodeConstants.BINARYOP: + { + BinaryOperatorInstruction boi = (BinaryOperatorInstruction)instruction; + Accessor a = match(boi.value1); + if (a != null) + boi.value1 = newInstruction(boi.value1, a); + else + visit(boi.value1); + a = match(boi.value2); + if (a != null) + boi.value2 = newInstruction(boi.value2, a); + else + visit(boi.value2); + } + break; + case ByteCodeConstants.CHECKCAST: + { + CheckCast checkCast = (CheckCast)instruction; + Accessor a = match(checkCast.objectref); + if (a != null) + checkCast.objectref = newInstruction(checkCast.objectref, a); + else + visit(checkCast.objectref); + } + break; + case ByteCodeConstants.STORE: + case ByteCodeConstants.ASTORE: + case ByteCodeConstants.ISTORE: + { + StoreInstruction storeInstruction = (StoreInstruction)instruction; + Accessor a = match(storeInstruction.valueref); + if (a != null) + storeInstruction.valueref = newInstruction(storeInstruction.valueref, a); + else + visit(storeInstruction.valueref); + } + break; + case ByteCodeConstants.DUPSTORE: + { + DupStore dupStore = (DupStore)instruction; + Accessor a = match(dupStore.objectref); + if (a != null) + dupStore.objectref = newInstruction(dupStore.objectref, a); + else + visit(dupStore.objectref); + } + break; + case ByteCodeConstants.CONVERT: + case ByteCodeConstants.IMPLICITCONVERT: + { + ConvertInstruction ci = (ConvertInstruction)instruction; + Accessor a = match(ci.value); + if (a != null) + ci.value = newInstruction(ci.value, a); + else + visit(ci.value); + } + break; + case ByteCodeConstants.IFCMP: + { + IfCmp ifCmp = (IfCmp)instruction; + Accessor a = match(ifCmp.value1); + if (a != null) + ifCmp.value1 = newInstruction(ifCmp.value1, a); + else + visit(ifCmp.value1); + a = match(ifCmp.value2); + if (a != null) + ifCmp.value2 = newInstruction(ifCmp.value2, a); + else + visit(ifCmp.value2); + } + break; + case ByteCodeConstants.IF: + case ByteCodeConstants.IFXNULL: + { + IfInstruction iff = (IfInstruction)instruction; + Accessor a = match(iff.value); + if (a != null) + iff.value = newInstruction(iff.value, a); + else + visit(iff.value); + } + break; + case ByteCodeConstants.COMPLEXIF: + { + List branchList = + ((ComplexConditionalBranchInstruction)instruction).instructions; + for (int i=branchList.size()-1; i>=0; --i) + visit(branchList.get(i)); + } + break; + case ByteCodeConstants.INSTANCEOF: + { + InstanceOf instanceOf = (InstanceOf)instruction; + Accessor a = match(instanceOf.objectref); + if (a != null) + instanceOf.objectref = newInstruction(instanceOf.objectref, a); + else + visit(instanceOf.objectref); + } + break; + case ByteCodeConstants.INVOKEINTERFACE: + case ByteCodeConstants.INVOKESPECIAL: + case ByteCodeConstants.INVOKEVIRTUAL: + { + InvokeNoStaticInstruction insi = + (InvokeNoStaticInstruction)instruction; + Accessor a = match(insi.objectref); + if (a != null) + insi.objectref = newInstruction(insi.objectref, a); + else + visit(insi.objectref); + } + case ByteCodeConstants.INVOKESTATIC: + case ByteCodeConstants.INVOKENEW: + { + List list = ((InvokeInstruction)instruction).args; + for (int i=list.size()-1; i>=0; --i) + { + Accessor a = match(list.get(i)); + if (a != null) + list.set(i, newInstruction(list.get(i), a)); + else + visit(list.get(i)); + } + } + break; + case ByteCodeConstants.LOOKUPSWITCH: + { + LookupSwitch ls = (LookupSwitch)instruction; + Accessor a = match(ls.key); + if (a != null) + ls.key = newInstruction(ls.key, a); + else + visit(ls.key); + } + break; + case ByteCodeConstants.MONITORENTER: + { + MonitorEnter monitorEnter = (MonitorEnter)instruction; + Accessor a = match(monitorEnter.objectref); + if (a != null) + monitorEnter.objectref = newInstruction(monitorEnter.objectref, a); + else + visit(monitorEnter.objectref); + } + break; + case ByteCodeConstants.MONITOREXIT: + { + MonitorExit monitorExit = (MonitorExit)instruction; + Accessor a = match(monitorExit.objectref); + if (a != null) + monitorExit.objectref = newInstruction(monitorExit.objectref, a); + else + visit(monitorExit.objectref); + } + break; + case ByteCodeConstants.MULTIANEWARRAY: + { + Instruction[] dimensions = ((MultiANewArray)instruction).dimensions; + for (int i=dimensions.length-1; i>=0; --i) + { + Accessor a = match(dimensions[i]); + if (a != null) + dimensions[i] = newInstruction(dimensions[i], a); + else + visit(dimensions[i]); + } + } + break; + case ByteCodeConstants.NEWARRAY: + { + NewArray newArray = (NewArray)instruction; + Accessor a = match(newArray.dimension); + if (a != null) + newArray.dimension = newInstruction(newArray.dimension, a); + else + visit(newArray.dimension); + } + break; + case ByteCodeConstants.ANEWARRAY: + { + ANewArray aNewArray = (ANewArray)instruction; + Accessor a = match(aNewArray.dimension); + if (a != null) + aNewArray.dimension = newInstruction(aNewArray.dimension, a); + else + visit(aNewArray.dimension); + } + break; + case ByteCodeConstants.POP: + { + Pop pop = (Pop)instruction; + Accessor a = match(pop.objectref); + if (a != null) + pop.objectref = newInstruction(pop.objectref, a); + else + visit(pop.objectref); + } + break; + case ByteCodeConstants.PUTFIELD: + { + PutField putField = (PutField)instruction; + Accessor a = match(putField.objectref); + if (a != null) + putField.objectref = newInstruction(putField.objectref, a); + else + visit(putField.objectref); + a = match(putField.valueref); + if (a != null) + putField.valueref = newInstruction(putField.valueref, a); + else + visit(putField.valueref); + } + break; + case ByteCodeConstants.PUTSTATIC: + { + PutStatic putStatic = (PutStatic)instruction; + Accessor a = match(putStatic.valueref); + if (a != null) + putStatic.valueref = newInstruction(putStatic.valueref, a); + else + visit(putStatic.valueref); + } + break; + case ByteCodeConstants.XRETURN: + { + ReturnInstruction ri = (ReturnInstruction)instruction; + Accessor a = match(ri.valueref); + if (a != null) + ri.valueref = newInstruction(ri.valueref, a); + else + visit(ri.valueref); + } + break; + case ByteCodeConstants.TABLESWITCH: + { + TableSwitch ts = (TableSwitch)instruction; + Accessor a = match(ts.key); + if (a != null) + ts.key = newInstruction(ts.key, a); + else + visit(ts.key); + } + break; + case ByteCodeConstants.TERNARYOPSTORE: + { + TernaryOpStore tos = (TernaryOpStore)instruction; + Accessor a = match(tos.objectref); + if (a != null) + tos.objectref = newInstruction(tos.objectref, a); + else + visit(tos.objectref); + } + break; + case ByteCodeConstants.TERNARYOP: + { + TernaryOperator to = (TernaryOperator)instruction; + Accessor a = match(to.test); + if (a != null) + to.test = newInstruction(to.test, a); + else + visit(to.test); + a = match(to.value1); + if (a != null) + to.value1 = newInstruction(to.value1, a); + else + visit(to.value1); + a = match(to.value2); + if (a != null) + to.value2 = newInstruction(to.value2, a); + else + visit(to.value2); + } + break; + case ByteCodeConstants.ASSIGNMENT: + { + AssignmentInstruction ai = (AssignmentInstruction)instruction; + Accessor a = match(ai.value1); + if (a != null) + ai.value1 = newInstruction(ai.value1, a); + else + visit(ai.value1); + a = match(ai.value2); + if (a != null) + ai.value2 = newInstruction(ai.value2, a); + else + visit(ai.value2); + } + break; + case ByteCodeConstants.ARRAYLOAD: + { + ArrayLoadInstruction ali = (ArrayLoadInstruction)instruction; + Accessor a = match(ali.arrayref); + if (a != null) + ali.arrayref = newInstruction(ali.arrayref, a); + else + visit(ali.arrayref); + a = match(ali.indexref); + if (a != null) + ali.indexref = newInstruction(ali.indexref, a); + else + visit(ali.indexref); + } + break; + case ByteCodeConstants.PREINC: + case ByteCodeConstants.POSTINC: + { + IncInstruction ii = (IncInstruction)instruction; + Accessor a = match(ii.value); + if (a != null) + ii.value = newInstruction(ii.value, a); + else + visit(ii.value); + } + break; + case ByteCodeConstants.GETFIELD: + { + GetField gf = (GetField)instruction; + Accessor a = match(gf.objectref); + if (a != null) + gf.objectref = newInstruction(gf.objectref, a); + else + visit(gf.objectref); + } + break; + case ByteCodeConstants.INITARRAY: + case ByteCodeConstants.NEWANDINITARRAY: + { + InitArrayInstruction iai = (InitArrayInstruction)instruction; + Accessor a = match(iai.newArray); + if (a != null) + iai.newArray = newInstruction(iai.newArray, a); + else + visit(iai.newArray); + if (iai.values != null) + visit(iai.values); + } + break; + case ByteCodeConstants.ACONST_NULL: + case ByteCodeConstants.LOAD: + case ByteCodeConstants.ALOAD: + case ByteCodeConstants.ILOAD: + case ByteCodeConstants.BIPUSH: + case ByteCodeConstants.ICONST: + case ByteCodeConstants.LCONST: + case ByteCodeConstants.FCONST: + case ByteCodeConstants.DCONST: + case ByteCodeConstants.DUPLOAD: + case ByteCodeConstants.GETSTATIC: + case ByteCodeConstants.OUTERTHIS: + case ByteCodeConstants.GOTO: + case ByteCodeConstants.IINC: + case ByteCodeConstants.JSR: + case ByteCodeConstants.LDC: + case ByteCodeConstants.LDC2_W: + case ByteCodeConstants.NEW: + case ByteCodeConstants.NOP: + case ByteCodeConstants.SIPUSH: + case ByteCodeConstants.RET: + case ByteCodeConstants.RETURN: + case ByteCodeConstants.EXCEPTIONLOAD: + case ByteCodeConstants.RETURNADDRESSLOAD: + break; + default: + System.err.println( + "Can not replace accessor in " + + instruction.getClass().getName() + + ", opcode=" + instruction.opcode); + } + } + + public void visit(List instructions) + { + for (int index=instructions.size()-1; index>=0; --index) + { + Instruction i = instructions.get(index); + Accessor a = match(i); + + if (a != null) + instructions.set(index, newInstruction(i, a)); + else + visit(i); + } + } + + protected Accessor match(Instruction i) + { + if (i.opcode != ByteCodeConstants.INVOKESTATIC) + return null; + + Invokestatic is = (Invokestatic)i; + ConstantMethodref cmr = + constants.getConstantMethodref(is.index); + ConstantNameAndType cnat = + constants.getConstantNameAndType(cmr.name_and_type_index); + String descriptor = + constants.getConstantUtf8(cnat.descriptor_index); + + // Zero parameter ? + if (descriptor.charAt(1) != ')') + return null; + + String className = constants.getConstantClassName(cmr.class_index); + ClassFile classFile = this.innerClassesMap.get(className); + if (classFile == null) + return null; + + String name = + constants.getConstantUtf8(cnat.name_index); + + Accessor accessor = classFile.getAccessor(name, descriptor); + + if ((accessor == null) || + (accessor.tag != AccessorConstants.ACCESSOR_GETSTATIC)) + return null; + + return (GetStaticAccessor)accessor; + } + + protected Instruction newInstruction(Instruction i, Accessor a) + { + GetStaticAccessor gsa = (GetStaticAccessor)a; + + int nameIndex = this.constants.addConstantUtf8(gsa.fieldName); + int descriptorIndex = + this.constants.addConstantUtf8(gsa.fieldDescriptor); + int cnatIndex = + this.constants.addConstantNameAndType(nameIndex, descriptorIndex); + + int classNameIndex = this.constants.addConstantUtf8(gsa.className); + int classIndex = this.constants.addConstantClass(classNameIndex); + + int cfrIndex = + constants.addConstantFieldref(classIndex, cnatIndex); + + return new GetStatic( + ByteCodeConstants.GETSTATIC, i.offset, i.lineNumber, cfrIndex); + } +} diff --git a/src/jd/core/process/analyzer/classfile/visitor/OuterInvokeMethodVisitor.java b/src/jd/core/process/analyzer/classfile/visitor/OuterInvokeMethodVisitor.java new file mode 100644 index 00000000..b8cffdb5 --- /dev/null +++ b/src/jd/core/process/analyzer/classfile/visitor/OuterInvokeMethodVisitor.java @@ -0,0 +1,116 @@ +package jd.core.process.analyzer.classfile.visitor; + +import java.util.HashMap; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.accessor.Accessor; +import jd.core.model.classfile.accessor.AccessorConstants; +import jd.core.model.classfile.accessor.InvokeMethodAccessor; +import jd.core.model.classfile.constant.ConstantMethodref; +import jd.core.model.classfile.constant.ConstantNameAndType; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.Invokeinterface; +import jd.core.model.instruction.bytecode.instruction.Invokespecial; +import jd.core.model.instruction.bytecode.instruction.Invokestatic; +import jd.core.model.instruction.bytecode.instruction.Invokevirtual; + +/* + * Replace 'EntitlementFunctionLibrary.access$000()' + * par 'EntitlementFunctionLibrary.kernelId' + */ +public class OuterInvokeMethodVisitor extends OuterGetStaticVisitor +{ + public OuterInvokeMethodVisitor( + HashMap innerClassesMap, ConstantPool constants) + { + super(innerClassesMap, constants); + } + + protected Accessor match(Instruction i) + { + if (i.opcode != ByteCodeConstants.INVOKESTATIC) + return null; + + Invokestatic is = (Invokestatic)i; + ConstantMethodref cmr = + constants.getConstantMethodref(is.index); + ConstantNameAndType cnat = + constants.getConstantNameAndType(cmr.name_and_type_index); + String descriptor = + constants.getConstantUtf8(cnat.descriptor_index); + + // Zero parameter ? + if (descriptor.charAt(1) == ')') + return null; + + String className = constants.getConstantClassName(cmr.class_index); + ClassFile classFile = this.innerClassesMap.get(className); + if (classFile == null) + return null; + + String name = + constants.getConstantUtf8(cnat.name_index); + + Accessor accessor = classFile.getAccessor(name, descriptor); + + if ((accessor == null) || + (accessor.tag != AccessorConstants.ACCESSOR_INVOKEMETHOD)) + return null; + + return accessor; + } + + protected Instruction newInstruction(Instruction i, Accessor a) + { + InvokeMethodAccessor ima = (InvokeMethodAccessor)a; + Invokestatic is = (Invokestatic)i; + + int nameIndex = this.constants.addConstantUtf8(ima.methodName); + int descriptorIndex = + this.constants.addConstantUtf8(ima.methodDescriptor); + int cnatIndex = + this.constants.addConstantNameAndType(nameIndex, descriptorIndex); + + int classNameIndex = this.constants.addConstantUtf8(ima.className); + int classIndex = this.constants.addConstantClass(classNameIndex); + + int cmrIndex = constants.addConstantMethodref( + classIndex, cnatIndex, + ima.listOfParameterSignatures, ima.returnedSignature); + + switch (ima.methodOpcode) + { + case ByteCodeConstants.INVOKESPECIAL: + { + Instruction objectref = is.args.remove(0); + return new Invokespecial( + ByteCodeConstants.INVOKESPECIAL, i.offset, i.lineNumber, + cmrIndex, objectref, is.args); + } + case ByteCodeConstants.INVOKEVIRTUAL: + { + Instruction objectref = is.args.remove(0); + return new Invokevirtual( + ByteCodeConstants.INVOKEVIRTUAL, i.offset, i.lineNumber, + cmrIndex, objectref, is.args); + } + case ByteCodeConstants.INVOKEINTERFACE: + { + Instruction objectref = is.args.remove(0); + return new Invokeinterface( + ByteCodeConstants.INVOKEINTERFACE, i.offset, i.lineNumber, + cmrIndex, objectref, is.args); + } + case ByteCodeConstants.INVOKESTATIC: + { + return new Invokestatic( + ByteCodeConstants.INVOKESTATIC, i.offset, i.lineNumber, + cmrIndex, is.args); + } + default: + return i; + } + } +} diff --git a/src/jd/core/process/analyzer/classfile/visitor/OuterPutFieldVisitor.java b/src/jd/core/process/analyzer/classfile/visitor/OuterPutFieldVisitor.java new file mode 100644 index 00000000..bde8c8b5 --- /dev/null +++ b/src/jd/core/process/analyzer/classfile/visitor/OuterPutFieldVisitor.java @@ -0,0 +1,87 @@ +package jd.core.process.analyzer.classfile.visitor; + +import java.util.HashMap; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.accessor.Accessor; +import jd.core.model.classfile.accessor.AccessorConstants; +import jd.core.model.classfile.accessor.PutFieldAccessor; +import jd.core.model.classfile.constant.ConstantMethodref; +import jd.core.model.classfile.constant.ConstantNameAndType; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.Invokestatic; +import jd.core.model.instruction.bytecode.instruction.PutField; + +/* + * Replace 'TestInnerClass.access$0(this.this$0, 1)' + * par 'this.this$0.text = 1' + */ +public class OuterPutFieldVisitor extends OuterGetStaticVisitor +{ + public OuterPutFieldVisitor( + HashMap innerClassesMap, ConstantPool constants) + { + super(innerClassesMap, constants); + } + + protected Accessor match(Instruction i) + { + if (i.opcode != ByteCodeConstants.INVOKESTATIC) + return null; + + Invokestatic is = (Invokestatic)i; + ConstantMethodref cmr = + constants.getConstantMethodref(is.index); + ConstantNameAndType cnat = + constants.getConstantNameAndType(cmr.name_and_type_index); + String descriptor = + constants.getConstantUtf8(cnat.descriptor_index); + + // Two parameters ? + if (cmr.getNbrOfParameters() != 2) + return null; + + String className = constants.getConstantClassName(cmr.class_index); + ClassFile classFile = this.innerClassesMap.get(className); + if (classFile == null) + return null; + + String name = + constants.getConstantUtf8(cnat.name_index); + + Accessor accessor = classFile.getAccessor(name, descriptor); + + if ((accessor == null) || + (accessor.tag != AccessorConstants.ACCESSOR_PUTFIELD)) + return null; + + return (PutFieldAccessor)accessor; + } + + protected Instruction newInstruction(Instruction i, Accessor a) + { + PutFieldAccessor pfa = (PutFieldAccessor)a; + Invokestatic is = (Invokestatic)i; + + int nameIndex = this.constants.addConstantUtf8(pfa.fieldName); + int descriptorIndex = + this.constants.addConstantUtf8(pfa.fieldDescriptor); + int cnatIndex = + this.constants.addConstantNameAndType(nameIndex, descriptorIndex); + + int classNameIndex = this.constants.addConstantUtf8(pfa.className); + int classIndex = this.constants.addConstantClass(classNameIndex); + + int cfrIndex = + this.constants.addConstantFieldref(classIndex, cnatIndex); + + Instruction valueref = is.args.remove(1); + Instruction objectref = is.args.remove(0); + + return new PutField( + ByteCodeConstants.PUTFIELD, i.offset, i.lineNumber, cfrIndex, + objectref, valueref); + } +} diff --git a/src/jd/core/process/analyzer/classfile/visitor/OuterPutStaticVisitor.java b/src/jd/core/process/analyzer/classfile/visitor/OuterPutStaticVisitor.java new file mode 100644 index 00000000..0b17d5df --- /dev/null +++ b/src/jd/core/process/analyzer/classfile/visitor/OuterPutStaticVisitor.java @@ -0,0 +1,86 @@ +package jd.core.process.analyzer.classfile.visitor; + +import java.util.HashMap; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.accessor.Accessor; +import jd.core.model.classfile.accessor.AccessorConstants; +import jd.core.model.classfile.accessor.PutStaticAccessor; +import jd.core.model.classfile.constant.ConstantMethodref; +import jd.core.model.classfile.constant.ConstantNameAndType; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.Invokestatic; +import jd.core.model.instruction.bytecode.instruction.PutStatic; + +/* + * Replace 'TestInnerClass.access$0(1)' + * par 'TestInnerClass.test = 1' + */ +public class OuterPutStaticVisitor extends OuterGetStaticVisitor +{ + public OuterPutStaticVisitor( + HashMap innerClassesMap, ConstantPool constants) + { + super(innerClassesMap, constants); + } + + protected Accessor match(Instruction i) + { + if (i.opcode != ByteCodeConstants.INVOKESTATIC) + return null; + + Invokestatic is = (Invokestatic)i; + ConstantMethodref cmr = + constants.getConstantMethodref(is.index); + ConstantNameAndType cnat = + constants.getConstantNameAndType(cmr.name_and_type_index); + String descriptor = + constants.getConstantUtf8(cnat.descriptor_index); + + // One parameter ? + if (cmr.getNbrOfParameters() != 1) + return null; + + String className = constants.getConstantClassName(cmr.class_index); + ClassFile classFile = this.innerClassesMap.get(className); + if (classFile == null) + return null; + + String name = + constants.getConstantUtf8(cnat.name_index); + + Accessor accessor = classFile.getAccessor(name, descriptor); + + if ((accessor == null) || + (accessor.tag != AccessorConstants.ACCESSOR_PUTSTATIC)) + return null; + + return (PutStaticAccessor)accessor; + } + + protected Instruction newInstruction(Instruction i, Accessor a) + { + PutStaticAccessor psa = (PutStaticAccessor)a; + Invokestatic is = (Invokestatic)i; + + int nameIndex = this.constants.addConstantUtf8(psa.fieldName); + int descriptorIndex = + this.constants.addConstantUtf8(psa.fieldDescriptor); + int cnatIndex = + this.constants.addConstantNameAndType(nameIndex, descriptorIndex); + + int classNameIndex = this.constants.addConstantUtf8(psa.className); + int classIndex = this.constants.addConstantClass(classNameIndex); + + int cfrIndex = + this.constants.addConstantFieldref(classIndex, cnatIndex); + + Instruction valueref = is.args.remove(0); + + return new PutStatic( + ByteCodeConstants.PUTSTATIC, i.offset, i.lineNumber, + cfrIndex, valueref); + } +} diff --git a/src/jd/core/process/analyzer/classfile/visitor/ReferenceVisitor.java b/src/jd/core/process/analyzer/classfile/visitor/ReferenceVisitor.java new file mode 100644 index 00000000..02569e39 --- /dev/null +++ b/src/jd/core/process/analyzer/classfile/visitor/ReferenceVisitor.java @@ -0,0 +1,481 @@ +package jd.core.process.analyzer.classfile.visitor; + +import java.util.List; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.constant.Constant; +import jd.core.model.classfile.constant.ConstantClass; +import jd.core.model.classfile.constant.ConstantConstant; +import jd.core.model.classfile.constant.ConstantFieldref; +import jd.core.model.classfile.constant.ConstantMethodref; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.ANewArray; +import jd.core.model.instruction.bytecode.instruction.AThrow; +import jd.core.model.instruction.bytecode.instruction.ArrayLength; +import jd.core.model.instruction.bytecode.instruction.ArrayStoreInstruction; +import jd.core.model.instruction.bytecode.instruction.AssertInstruction; +import jd.core.model.instruction.bytecode.instruction.BinaryOperatorInstruction; +import jd.core.model.instruction.bytecode.instruction.CheckCast; +import jd.core.model.instruction.bytecode.instruction.ComplexConditionalBranchInstruction; +import jd.core.model.instruction.bytecode.instruction.ConvertInstruction; +import jd.core.model.instruction.bytecode.instruction.DupStore; +import jd.core.model.instruction.bytecode.instruction.GetField; +import jd.core.model.instruction.bytecode.instruction.IfCmp; +import jd.core.model.instruction.bytecode.instruction.IfInstruction; +import jd.core.model.instruction.bytecode.instruction.IndexInstruction; +import jd.core.model.instruction.bytecode.instruction.InitArrayInstruction; +import jd.core.model.instruction.bytecode.instruction.InstanceOf; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.InvokeInstruction; +import jd.core.model.instruction.bytecode.instruction.InvokeNoStaticInstruction; +import jd.core.model.instruction.bytecode.instruction.LookupSwitch; +import jd.core.model.instruction.bytecode.instruction.MonitorEnter; +import jd.core.model.instruction.bytecode.instruction.MonitorExit; +import jd.core.model.instruction.bytecode.instruction.MultiANewArray; +import jd.core.model.instruction.bytecode.instruction.New; +import jd.core.model.instruction.bytecode.instruction.NewArray; +import jd.core.model.instruction.bytecode.instruction.Pop; +import jd.core.model.instruction.bytecode.instruction.PutField; +import jd.core.model.instruction.bytecode.instruction.PutStatic; +import jd.core.model.instruction.bytecode.instruction.ReturnInstruction; +import jd.core.model.instruction.bytecode.instruction.StoreInstruction; +import jd.core.model.instruction.bytecode.instruction.TableSwitch; +import jd.core.model.instruction.bytecode.instruction.TernaryOpStore; +import jd.core.model.instruction.bytecode.instruction.TernaryOperator; +import jd.core.model.instruction.bytecode.instruction.UnaryOperatorInstruction; +import jd.core.model.instruction.fast.FastConstants; +import jd.core.model.instruction.fast.instruction.FastDeclaration; +import jd.core.model.instruction.fast.instruction.FastFor; +import jd.core.model.instruction.fast.instruction.FastForEach; +import jd.core.model.instruction.fast.instruction.FastInstruction; +import jd.core.model.instruction.fast.instruction.FastLabel; +import jd.core.model.instruction.fast.instruction.FastList; +import jd.core.model.instruction.fast.instruction.FastSwitch; +import jd.core.model.instruction.fast.instruction.FastSynchronized; +import jd.core.model.instruction.fast.instruction.FastTest2Lists; +import jd.core.model.instruction.fast.instruction.FastTestList; +import jd.core.model.instruction.fast.instruction.FastTry; +import jd.core.model.instruction.fast.instruction.FastSwitch.Pair; +import jd.core.model.instruction.fast.instruction.FastTry.FastCatch; +import jd.core.model.reference.ReferenceMap; +import jd.core.util.SignatureUtil; + + +public class ReferenceVisitor +{ + private ConstantPool constants; + private ReferenceMap referenceMap; + + public ReferenceVisitor(ConstantPool constants, ReferenceMap referenceMap) + { + this.constants = constants; + this.referenceMap = referenceMap; + } + + public void visit(Instruction instruction) + { + if (instruction == null) + return; + + String internalName; + + switch (instruction.opcode) + { + case ByteCodeConstants.ARRAYLENGTH: + { + ArrayLength al = (ArrayLength)instruction; + visit(al.arrayref); + } + break; + case ByteCodeConstants.AASTORE: + case ByteCodeConstants.ARRAYSTORE: + { + ArrayStoreInstruction asi = (ArrayStoreInstruction)instruction; + visit(asi.valueref); + } + break; + case ByteCodeConstants.ASSERT: + { + AssertInstruction ai = (AssertInstruction)instruction; + visit(ai.test); + visit(ai.msg); + } + break; + case ByteCodeConstants.ATHROW: + { + AThrow aThrow = (AThrow)instruction; + visit(aThrow.value); + } + break; + case ByteCodeConstants.UNARYOP: + { + UnaryOperatorInstruction uoi = (UnaryOperatorInstruction)instruction; + visit(uoi.value); + } + break; + case ByteCodeConstants.BINARYOP: + case ByteCodeConstants.ASSIGNMENT: + { + BinaryOperatorInstruction boi = (BinaryOperatorInstruction)instruction; + visit(boi.value1); + visit(boi.value2); + } + break; + case ByteCodeConstants.CHECKCAST: + { + CheckCast checkCast = (CheckCast)instruction; + visitCheckCastAndMultiANewArray(checkCast.index); + visit(checkCast.objectref); + } + break; + case ByteCodeConstants.STORE: + case ByteCodeConstants.ISTORE: + { + StoreInstruction storeInstruction = (StoreInstruction)instruction; + visit(storeInstruction.valueref); + } + break; + case ByteCodeConstants.ASTORE: + { + StoreInstruction storeInstruction = (StoreInstruction)instruction; + visit(storeInstruction.valueref); + } + break; + case ByteCodeConstants.DUPSTORE: + { + DupStore dupStore = (DupStore)instruction; + visit(dupStore.objectref); + } + break; + case ByteCodeConstants.CONVERT: + case ByteCodeConstants.IMPLICITCONVERT: + { + ConvertInstruction ci = (ConvertInstruction)instruction; + visit(ci.value); + } + break; + case ByteCodeConstants.IFCMP: + { + IfCmp ifCmp = (IfCmp)instruction; + visit(ifCmp.value1); + visit(ifCmp.value2); + } + break; + case ByteCodeConstants.IF: + case ByteCodeConstants.IFXNULL: + { + IfInstruction iff = (IfInstruction)instruction; + visit(iff.value); + } + break; + case ByteCodeConstants.COMPLEXIF: + { + List branchList = + ((ComplexConditionalBranchInstruction)instruction).instructions; + for (int i=branchList.size()-1; i>=0; --i) + visit(branchList.get(i)); + } + break; + case ByteCodeConstants.INSTANCEOF: + { + InstanceOf instanceOf = (InstanceOf)instruction; + visitCheckCastAndMultiANewArray(instanceOf.index); + visit(instanceOf.objectref); + } + break; + case ByteCodeConstants.INVOKEINTERFACE: + case ByteCodeConstants.INVOKESPECIAL: + case ByteCodeConstants.INVOKEVIRTUAL: + InvokeNoStaticInstruction insi = + (InvokeNoStaticInstruction)instruction; + visit(insi.objectref); + case ByteCodeConstants.INVOKESTATIC: + case ByteCodeConstants.INVOKENEW: + { + InvokeInstruction ii = (InvokeInstruction)instruction; + ConstantMethodref cmr = constants.getConstantMethodref(ii.index); + internalName = constants.getConstantClassName(cmr.class_index); + addReference(internalName); + visit(ii.args); + } + break; + case ByteCodeConstants.LOOKUPSWITCH: + { + LookupSwitch ls = (LookupSwitch)instruction; + visit(ls.key); + } + break; + case ByteCodeConstants.MONITORENTER: + { + MonitorEnter monitorEnter = (MonitorEnter)instruction; + visit(monitorEnter.objectref); + } + break; + case ByteCodeConstants.MONITOREXIT: + { + MonitorExit monitorExit = (MonitorExit)instruction; + visit(monitorExit.objectref); + } + break; + case ByteCodeConstants.MULTIANEWARRAY: + { + MultiANewArray multiANewArray = (MultiANewArray)instruction; + visitCheckCastAndMultiANewArray(multiANewArray.index); + Instruction[] dimensions = multiANewArray.dimensions; + for (int i=dimensions.length-1; i>=0; --i) + visit(dimensions[i]); + } + break; + case ByteCodeConstants.NEWARRAY: + { + NewArray newArray = (NewArray)instruction; + visit(newArray.dimension); + } + break; + case ByteCodeConstants.NEW: + { + New aNew = (New)instruction; + addReference(this.constants.getConstantClassName(aNew.index)); + } + break; + case ByteCodeConstants.ANEWARRAY: + { + ANewArray aNewArray = (ANewArray)instruction; + addReference( + this.constants.getConstantClassName(aNewArray.index)); + visit(aNewArray.dimension); + } + break; + case ByteCodeConstants.POP: + { + Pop pop = (Pop)instruction; + visit(pop.objectref); + } + break; + case ByteCodeConstants.PUTFIELD: + { + PutField putField = (PutField)instruction; + visit(putField.objectref); + visit(putField.valueref); + } + break; + case ByteCodeConstants.PUTSTATIC: + { + PutStatic putStatic = (PutStatic)instruction; + visit(putStatic.valueref); + } + break; + case ByteCodeConstants.XRETURN: + { + ReturnInstruction ri = (ReturnInstruction)instruction; + visit(ri.valueref); + } + break; + case ByteCodeConstants.TABLESWITCH: + { + TableSwitch ts = (TableSwitch)instruction; + visit(ts.key); + } + break; + case ByteCodeConstants.TERNARYOPSTORE: + { + TernaryOpStore tos = (TernaryOpStore)instruction; + visit(tos.objectref); + } + break; + case ByteCodeConstants.TERNARYOP: + { + TernaryOperator to = (TernaryOperator)instruction; + visit(to.test); + visit(to.value1); + visit(to.value2); + } + break; + case ByteCodeConstants.GETFIELD: + GetField getField = (GetField)instruction; + visit(getField.objectref); + case ByteCodeConstants.GETSTATIC: + case ByteCodeConstants.OUTERTHIS: + { + IndexInstruction indexInstruction = (IndexInstruction)instruction; + ConstantFieldref cfr = + constants.getConstantFieldref(indexInstruction.index); + internalName = constants.getConstantClassName(cfr.class_index); + addReference(internalName); + } + break; + case ByteCodeConstants.INITARRAY: + case ByteCodeConstants.NEWANDINITARRAY: + { + InitArrayInstruction iai = (InitArrayInstruction)instruction; + visit(iai.newArray); + for (int index=iai.values.size()-1; index>=0; --index) + visit(iai.values.get(index)); + } + break; + case FastConstants.FOR: + FastFor ff = (FastFor)instruction; + visit(ff.init); + visit(ff.inc); + case FastConstants.WHILE: + case FastConstants.DO_WHILE: + case FastConstants.IF_: + FastTestList ftl = (FastTestList)instruction; + visit(ftl.test); + case FastConstants.INFINITE_LOOP: + { + List instructions = + ((FastList)instruction).instructions; + visit(instructions); + } + break; + case FastConstants.FOREACH: + { + FastForEach ffe = (FastForEach)instruction; + visit(ffe.variable); + visit(ffe.values); + visit(ffe.instructions); + } + break; + case FastConstants.IF_ELSE: + { + FastTest2Lists ft2l = (FastTest2Lists)instruction; + visit(ft2l.test); + visit(ft2l.instructions); + visit(ft2l.instructions2); + } + break; + case FastConstants.IF_CONTINUE: + case FastConstants.IF_BREAK: + case FastConstants.IF_LABELED_BREAK: + case FastConstants.GOTO_CONTINUE: + case FastConstants.GOTO_BREAK: + case FastConstants.GOTO_LABELED_BREAK: + { + FastInstruction fi = (FastInstruction)instruction; + visit(fi.instruction); + } + break; + case FastConstants.SWITCH: + case FastConstants.SWITCH_ENUM: + case FastConstants.SWITCH_STRING: + { + FastSwitch fs = (FastSwitch)instruction; + visit(fs.test); + Pair[] pairs = fs.pairs; + for (int i=pairs.length-1; i>=0; --i) + { + List instructions = pairs[i].getInstructions(); + visit(instructions); + } + } + break; + case FastConstants.DECLARE: + { + FastDeclaration fd = (FastDeclaration)instruction; + visit(fd.instruction); + } + break; + case FastConstants.TRY: + { + FastTry ft = (FastTry)instruction; + visit(ft.instructions); + List catches = ft.catches; + for (int i=catches.size()-1; i>=0; --i) + visit(catches.get(i).instructions); + visit(ft.finallyInstructions); + } + break; + case FastConstants.SYNCHRONIZED: + { + FastSynchronized fsy = (FastSynchronized)instruction; + visit(fsy.monitor); + visit(fsy.instructions); + } + break; + case FastConstants.LABEL: + { + FastLabel fla = (FastLabel)instruction; + visit(fla.instruction); + } + break; + case ByteCodeConstants.LDC: + { + IndexInstruction indexInstruction = (IndexInstruction)instruction; + Constant cst = constants.get(indexInstruction.index); + + if (cst.tag == ConstantConstant.CONSTANT_Class) + { + ConstantClass cc = (ConstantClass)cst; + internalName = constants.getConstantUtf8(cc.name_index); + addReference(internalName); + } + } + break; + case ByteCodeConstants.ACONST_NULL: + case ByteCodeConstants.ARRAYLOAD: + case ByteCodeConstants.LOAD: + case ByteCodeConstants.ALOAD: + case ByteCodeConstants.ILOAD: + case ByteCodeConstants.BIPUSH: + case ByteCodeConstants.ICONST: + case ByteCodeConstants.LCONST: + case ByteCodeConstants.FCONST: + case ByteCodeConstants.DCONST: + case ByteCodeConstants.DUPLOAD: + case ByteCodeConstants.GOTO: + case ByteCodeConstants.IINC: + case ByteCodeConstants.PREINC: + case ByteCodeConstants.POSTINC: + case ByteCodeConstants.JSR: + case ByteCodeConstants.LDC2_W: + case ByteCodeConstants.NOP: + case ByteCodeConstants.SIPUSH: + case ByteCodeConstants.RET: + case ByteCodeConstants.RETURN: + case ByteCodeConstants.EXCEPTIONLOAD: + case ByteCodeConstants.RETURNADDRESSLOAD: + break; + default: + System.err.println( + "Can not count reference in " + + instruction.getClass().getName() + + ", opcode=" + instruction.opcode); + } + } + + private void visit(List instructions) + { + if (instructions != null) + { + for (int i=instructions.size()-1; i>=0; --i) + visit(instructions.get(i)); + } + } + + private void visitCheckCastAndMultiANewArray(int index) + { + Constant c = constants.get(index); + + if (c.tag == ConstantConstant.CONSTANT_Class) + { + addReference( + constants.getConstantUtf8(((ConstantClass)c).name_index)); + } + } + + private void addReference(String signature) + { + if (signature.charAt(0) == '[') + { + signature = SignatureUtil.CutArrayDimensionPrefix(signature); + + if (signature.charAt(0) == 'L') + referenceMap.add(SignatureUtil.GetInnerName(signature)); + } + else + { + referenceMap.add(signature); + } + } +} diff --git a/src/jd/core/process/analyzer/classfile/visitor/ReplaceDupLoadVisitor.java b/src/jd/core/process/analyzer/classfile/visitor/ReplaceDupLoadVisitor.java new file mode 100644 index 00000000..681e6918 --- /dev/null +++ b/src/jd/core/process/analyzer/classfile/visitor/ReplaceDupLoadVisitor.java @@ -0,0 +1,746 @@ +package jd.core.process.analyzer.classfile.visitor; + +import java.util.List; + +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.ANewArray; +import jd.core.model.instruction.bytecode.instruction.AThrow; +import jd.core.model.instruction.bytecode.instruction.ArrayLength; +import jd.core.model.instruction.bytecode.instruction.ArrayLoadInstruction; +import jd.core.model.instruction.bytecode.instruction.ArrayStoreInstruction; +import jd.core.model.instruction.bytecode.instruction.AssignmentInstruction; +import jd.core.model.instruction.bytecode.instruction.BinaryOperatorInstruction; +import jd.core.model.instruction.bytecode.instruction.CheckCast; +import jd.core.model.instruction.bytecode.instruction.ComplexConditionalBranchInstruction; +import jd.core.model.instruction.bytecode.instruction.ConvertInstruction; +import jd.core.model.instruction.bytecode.instruction.DupLoad; +import jd.core.model.instruction.bytecode.instruction.DupStore; +import jd.core.model.instruction.bytecode.instruction.GetField; +import jd.core.model.instruction.bytecode.instruction.IfCmp; +import jd.core.model.instruction.bytecode.instruction.IfInstruction; +import jd.core.model.instruction.bytecode.instruction.IncInstruction; +import jd.core.model.instruction.bytecode.instruction.InitArrayInstruction; +import jd.core.model.instruction.bytecode.instruction.InstanceOf; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.InvokeInstruction; +import jd.core.model.instruction.bytecode.instruction.InvokeNoStaticInstruction; +import jd.core.model.instruction.bytecode.instruction.LookupSwitch; +import jd.core.model.instruction.bytecode.instruction.MonitorEnter; +import jd.core.model.instruction.bytecode.instruction.MonitorExit; +import jd.core.model.instruction.bytecode.instruction.MultiANewArray; +import jd.core.model.instruction.bytecode.instruction.NewArray; +import jd.core.model.instruction.bytecode.instruction.Pop; +import jd.core.model.instruction.bytecode.instruction.PutField; +import jd.core.model.instruction.bytecode.instruction.PutStatic; +import jd.core.model.instruction.bytecode.instruction.ReturnInstruction; +import jd.core.model.instruction.bytecode.instruction.StoreInstruction; +import jd.core.model.instruction.bytecode.instruction.TableSwitch; +import jd.core.model.instruction.bytecode.instruction.TernaryOpStore; +import jd.core.model.instruction.bytecode.instruction.TernaryOperator; +import jd.core.model.instruction.bytecode.instruction.UnaryOperatorInstruction; +import jd.core.model.instruction.fast.FastConstants; +import jd.core.model.instruction.fast.instruction.FastDeclaration; +import jd.core.model.instruction.fast.instruction.FastFor; +import jd.core.model.instruction.fast.instruction.FastForEach; +import jd.core.model.instruction.fast.instruction.FastInstruction; +import jd.core.model.instruction.fast.instruction.FastLabel; +import jd.core.model.instruction.fast.instruction.FastList; +import jd.core.model.instruction.fast.instruction.FastSwitch; +import jd.core.model.instruction.fast.instruction.FastSynchronized; +import jd.core.model.instruction.fast.instruction.FastTest2Lists; +import jd.core.model.instruction.fast.instruction.FastTestList; +import jd.core.model.instruction.fast.instruction.FastTry; +import jd.core.model.instruction.fast.instruction.FastTry.FastCatch; + + +public class ReplaceDupLoadVisitor +{ + private DupStore dupStore; + private Instruction newInstruction; + private Instruction parentFound; + + public ReplaceDupLoadVisitor() + { + this.dupStore = null; + this.newInstruction = null; + this.parentFound = null; + } + + public ReplaceDupLoadVisitor(DupStore dupStore, Instruction newInstruction) + { + init(dupStore, newInstruction); + } + + public void init(DupStore dupStore, Instruction newInstruction) + { + this.dupStore = dupStore; + this.newInstruction = newInstruction; + this.parentFound = null; + } + + public void visit(Instruction instruction) + { + switch (instruction.opcode) + { + case ByteCodeConstants.ARRAYLENGTH: + { + ArrayLength al = (ArrayLength)instruction; + if (match(al, al.arrayref)) + al.arrayref = this.newInstruction; + else + visit(al.arrayref); + } + break; + case ByteCodeConstants.AASTORE: + case ByteCodeConstants.ARRAYSTORE: + { + ArrayStoreInstruction asi = (ArrayStoreInstruction)instruction; + if (match(asi, asi.arrayref)) + { + asi.arrayref = this.newInstruction; + } + else + { + visit(asi.arrayref); + + if (this.parentFound == null) + { + if (match(asi, asi.indexref)) + { + asi.indexref = this.newInstruction; + } + else + { + visit(asi.indexref); + + if (this.parentFound == null) + { + if (match(asi, asi.valueref)) + asi.valueref = this.newInstruction; + else + visit(asi.valueref); + } + } + } + } + } + break; + case ByteCodeConstants.ATHROW: + { + AThrow aThrow = (AThrow)instruction; + if (match(aThrow, aThrow.value)) + aThrow.value = this.newInstruction; + else + visit(aThrow.value); + } + break; + case ByteCodeConstants.UNARYOP: + { + UnaryOperatorInstruction uoi = (UnaryOperatorInstruction)instruction; + if (match(uoi, uoi.value)) + uoi.value = this.newInstruction; + else + visit(uoi.value); + } + break; + case ByteCodeConstants.BINARYOP: + { + BinaryOperatorInstruction boi = (BinaryOperatorInstruction)instruction; + if (match(boi, boi.value1)) + { + boi.value1 = this.newInstruction; + } + else + { + visit(boi.value1); + + if (this.parentFound == null) + { + if (match(boi, boi.value2)) + boi.value2 = this.newInstruction; + else + visit(boi.value2); + } + } + } + break; + case ByteCodeConstants.CHECKCAST: + { + CheckCast checkCast = (CheckCast)instruction; + if (match(checkCast, checkCast.objectref)) + checkCast.objectref = this.newInstruction; + else + visit(checkCast.objectref); + } + break; + case ByteCodeConstants.STORE: + case ByteCodeConstants.ASTORE: + case ByteCodeConstants.ISTORE: + { + StoreInstruction storeInstruction = (StoreInstruction)instruction; + if (match(storeInstruction, storeInstruction.valueref)) + storeInstruction.valueref = this.newInstruction; + else + visit(storeInstruction.valueref); + } + break; + case ByteCodeConstants.DUPSTORE: + { + DupStore dupStore = (DupStore)instruction; + if (match(dupStore, dupStore.objectref)) + dupStore.objectref = this.newInstruction; + else + visit(dupStore.objectref); + } + break; + case ByteCodeConstants.CONVERT: + case ByteCodeConstants.IMPLICITCONVERT: + { + ConvertInstruction ci = (ConvertInstruction)instruction; + if (match(ci, ci.value)) + ci.value = this.newInstruction; + else + visit(ci.value); + } + break; + case ByteCodeConstants.IFCMP: + { + IfCmp ifCmp = (IfCmp)instruction; + if (match(ifCmp, ifCmp.value1)) + { + ifCmp.value1 = this.newInstruction; + } + else + { + visit(ifCmp.value1); + + if (this.parentFound == null) + { + if (match(ifCmp, ifCmp.value2)) + ifCmp.value2 = this.newInstruction; + else + visit(ifCmp.value2); + } + } + } + break; + case ByteCodeConstants.IF: + case ByteCodeConstants.IFXNULL: + { + IfInstruction iff = (IfInstruction)instruction; + if (match(iff, iff.value)) + iff.value = this.newInstruction; + else + visit(iff.value); + } + break; + case ByteCodeConstants.COMPLEXIF: + { + List branchList = + ((ComplexConditionalBranchInstruction)instruction).instructions; + for (int i=branchList.size()-1; (i>=0) && (this.parentFound == null); --i) + { + visit(branchList.get(i)); + } + } + break; + case ByteCodeConstants.INSTANCEOF: + { + InstanceOf instanceOf = (InstanceOf)instruction; + if (match(instanceOf, instanceOf.objectref)) + instanceOf.objectref = this.newInstruction; + else + visit(instanceOf.objectref); + } + break; + case ByteCodeConstants.INVOKEINTERFACE: + case ByteCodeConstants.INVOKESPECIAL: + case ByteCodeConstants.INVOKEVIRTUAL: + { + InvokeNoStaticInstruction insi = + (InvokeNoStaticInstruction)instruction; + if (match(insi, insi.objectref)) + insi.objectref = this.newInstruction; + else + visit(insi.objectref); + } + case ByteCodeConstants.INVOKESTATIC: + case ByteCodeConstants.INVOKENEW: + { + List list = ((InvokeInstruction)instruction).args; + for (int i=list.size()-1; (i>=0) && (this.parentFound == null); --i) + { + if (match(instruction, list.get(i))) + list.set(i, this.newInstruction); + else + visit(list.get(i)); + } + } + break; + case ByteCodeConstants.LOOKUPSWITCH: + { + LookupSwitch ls = (LookupSwitch)instruction; + if (match(ls, ls.key)) + ls.key = this.newInstruction; + else + visit(ls.key); + } + break; + case ByteCodeConstants.MONITORENTER: + { + MonitorEnter monitorEnter = (MonitorEnter)instruction; + if (match(monitorEnter, monitorEnter.objectref)) + monitorEnter.objectref = this.newInstruction; + else + visit(monitorEnter.objectref); + } + break; + case ByteCodeConstants.MONITOREXIT: + { + MonitorExit monitorExit = (MonitorExit)instruction; + if (match(monitorExit, monitorExit.objectref)) + monitorExit.objectref = this.newInstruction; + else + visit(monitorExit.objectref); + } + break; + case ByteCodeConstants.MULTIANEWARRAY: + { + Instruction[] dimensions = ((MultiANewArray)instruction).dimensions; + for (int i=dimensions.length-1; (i>=0) && (this.parentFound == null); --i) + { + if (match(instruction, dimensions[i])) + dimensions[i] = this.newInstruction; + else + visit(dimensions[i]); + } + } + break; + case ByteCodeConstants.NEWARRAY: + { + NewArray newArray = (NewArray)instruction; + if (match(newArray, newArray.dimension)) + newArray.dimension = this.newInstruction; + else + visit(newArray.dimension); + } + break; + case ByteCodeConstants.ANEWARRAY: + { + ANewArray aNewArray = (ANewArray)instruction; + if (match(aNewArray, aNewArray.dimension)) + aNewArray.dimension = this.newInstruction; + else + visit(aNewArray.dimension); + } + break; + case ByteCodeConstants.POP: + { + Pop pop = (Pop)instruction; + if (match(pop, pop.objectref)) + pop.objectref = this.newInstruction; + else + visit(pop.objectref); + } + break; + case ByteCodeConstants.PUTFIELD: + { + PutField putField = (PutField)instruction; + if (match(putField, putField.objectref)) + { + putField.objectref = this.newInstruction; + } + else + { + visit(putField.objectref); + + if (this.parentFound == null) + { + if (match(putField, putField.valueref)) + putField.valueref = this.newInstruction; + else + visit(putField.valueref); + } + } + } + break; + case ByteCodeConstants.PUTSTATIC: + { + PutStatic putStatic = (PutStatic)instruction; + if (match(putStatic, putStatic.valueref)) + putStatic.valueref = this.newInstruction; + else + visit(putStatic.valueref); + } + break; + case ByteCodeConstants.XRETURN: + { + ReturnInstruction ri = (ReturnInstruction)instruction; + if (match(ri, ri.valueref)) + ri.valueref = this.newInstruction; + else + visit(ri.valueref); + } + break; + case ByteCodeConstants.TABLESWITCH: + { + TableSwitch ts = (TableSwitch)instruction; + if (match(ts, ts.key)) + ts.key = this.newInstruction; + else + visit(ts.key); + } + break; + case ByteCodeConstants.TERNARYOPSTORE: + { + TernaryOpStore tos = (TernaryOpStore)instruction; + if (match(tos, tos.objectref)) + tos.objectref = this.newInstruction; + else + visit(tos.objectref); + } + break; + case ByteCodeConstants.TERNARYOP: + { + TernaryOperator to = (TernaryOperator)instruction; + if (match(to, to.value1)) + { + to.value1 = this.newInstruction; + } + else + { + visit(to.value1); + + if (this.parentFound == null) + { + if (match(to, to.value2)) + to.value2 = this.newInstruction; + else + visit(to.value2); + } + } + } + break; + case ByteCodeConstants.ASSIGNMENT: + { + AssignmentInstruction ai = (AssignmentInstruction)instruction; + if (match(ai, ai.value1)) + { + ai.value1 = this.newInstruction; + } + else + { + visit(ai.value1); + + if (this.parentFound == null) + { + if (match(ai, ai.value2)) + ai.value2 = this.newInstruction; + else + visit(ai.value2); + } + } + } + break; + case ByteCodeConstants.ARRAYLOAD: + { + ArrayLoadInstruction ali = (ArrayLoadInstruction)instruction; + if (match(ali, ali.arrayref)) + { + ali.arrayref = this.newInstruction; + } + else + { + visit(ali.arrayref); + + if (this.parentFound == null) + { + if (match(ali, ali.indexref)) + ali.indexref = this.newInstruction; + else + visit(ali.indexref); + } + } + } + break; + case ByteCodeConstants.PREINC: + case ByteCodeConstants.POSTINC: + { + IncInstruction ii = (IncInstruction)instruction; + if (match(ii, ii.value)) + ii.value = this.newInstruction; + else + visit(ii.value); + } + break; + case ByteCodeConstants.GETFIELD: + { + GetField gf = (GetField)instruction; + if (match(gf, gf.objectref)) + gf.objectref = this.newInstruction; + else + visit(gf.objectref); + } + break; + case ByteCodeConstants.INITARRAY: + case ByteCodeConstants.NEWANDINITARRAY: + { + InitArrayInstruction iai = (InitArrayInstruction)instruction; + if (match(iai, iai.newArray)) + { + iai.newArray = this.newInstruction; + } + else + { + visit(iai.newArray); + + if ((this.parentFound == null) && (iai.values != null)) + visit(iai.values); + } + } + break; + case FastConstants.FOR: + { + FastFor ff = (FastFor)instruction; + + if (ff.init != null) + { + if (match(ff, ff.init)) + ff.init = this.newInstruction; + else + visit(ff.init); + } + + if ((this.parentFound == null) && (ff.inc != null)) + { + if (match(ff, ff.inc)) + ff.inc = this.newInstruction; + else + visit(ff.inc); + } + } + case FastConstants.WHILE: + case FastConstants.DO_WHILE: + case FastConstants.IF_: + { + FastTestList ftl = (FastTestList)instruction; + if (ftl.test != null) + { + if (match(ftl, ftl.test)) + ftl.test = this.newInstruction; + else + visit(ftl.test); + } + } + case FastConstants.INFINITE_LOOP: + { + List instructions = + ((FastList)instruction).instructions; + if (instructions != null) + visit(instructions); + } + break; + case FastConstants.FOREACH: + { + FastForEach ffe = (FastForEach)instruction; + if (match(ffe, ffe.variable)) + { + ffe.variable = this.newInstruction; + } + else + { + visit(ffe.variable); + + if (this.parentFound == null) + { + if (match(ffe, ffe.values)) + { + ffe.values = this.newInstruction; + } + else + { + visit(ffe.values); + + if (this.parentFound == null) + visit(ffe.instructions); + } + } + } + } + break; + case FastConstants.IF_ELSE: + { + FastTest2Lists ft2l = (FastTest2Lists)instruction; + if (match(ft2l, ft2l.test)) + { + ft2l.test = this.newInstruction; + } + else + { + visit(ft2l.test); + + if (this.parentFound == null) + { + visit(ft2l.instructions); + + if (this.parentFound == null) + visit(ft2l.instructions2); + } + } + } + break; + case FastConstants.IF_CONTINUE: + case FastConstants.IF_BREAK: + case FastConstants.IF_LABELED_BREAK: + case FastConstants.GOTO_CONTINUE: + case FastConstants.GOTO_BREAK: + case FastConstants.GOTO_LABELED_BREAK: + { + FastInstruction fi = (FastInstruction)instruction; + if (fi.instruction != null) + { + if (match(fi, fi.instruction)) + fi.instruction = this.newInstruction; + else + visit(fi.instruction); + } + } + break; + case FastConstants.SWITCH: + case FastConstants.SWITCH_ENUM: + case FastConstants.SWITCH_STRING: + { + FastSwitch fs = (FastSwitch)instruction; + if (match(fs, fs.test)) + { + fs.test = this.newInstruction; + } + else + { + visit(fs.test); + + FastSwitch.Pair[] pairs = fs.pairs; + for (int i=pairs.length-1; (i>=0) && (this.parentFound == null); --i) + visit(pairs[i].getInstructions()); + } + } + break; + case FastConstants.TRY: + { + FastTry ft = (FastTry)instruction; + visit(ft.instructions); + + if (this.parentFound == null) + { + if (ft.finallyInstructions != null) + visit(ft.finallyInstructions); + + List catchs = ft.catches; + for (int i=catchs.size()-1; (i>=0) && (this.parentFound == null); --i) + visit(catchs.get(i).instructions); + } + } + break; + case FastConstants.SYNCHRONIZED: + { + FastSynchronized fsd = (FastSynchronized)instruction; + if (match(fsd, fsd.monitor)) + { + fsd.monitor = this.newInstruction; + } + else + { + visit(fsd.monitor); + + if (this.parentFound == null) + visit(fsd.instructions); + } + } + break; + case FastConstants.LABEL: + { + FastLabel fl = (FastLabel)instruction; + if (fl.instruction != null) + { + if (match(fl, fl.instruction)) + fl.instruction = this.newInstruction; + else + visit(fl.instruction); + } + } + break; + case FastConstants.DECLARE: + { + FastDeclaration fd = (FastDeclaration)instruction; + if (fd.instruction != null) + { + if (match(fd, fd.instruction)) + fd.instruction = this.newInstruction; + else + visit(fd.instruction); + } + } + break; + case ByteCodeConstants.ACONST_NULL: + case ByteCodeConstants.LOAD: + case ByteCodeConstants.ALOAD: + case ByteCodeConstants.ILOAD: + case ByteCodeConstants.BIPUSH: + case ByteCodeConstants.ICONST: + case ByteCodeConstants.LCONST: + case ByteCodeConstants.FCONST: + case ByteCodeConstants.DCONST: + case ByteCodeConstants.DUPLOAD: + case ByteCodeConstants.GETSTATIC: + case ByteCodeConstants.OUTERTHIS: + case ByteCodeConstants.GOTO: + case ByteCodeConstants.IINC: + case ByteCodeConstants.JSR: + case ByteCodeConstants.LDC: + case ByteCodeConstants.LDC2_W: + case ByteCodeConstants.NEW: + case ByteCodeConstants.NOP: + case ByteCodeConstants.SIPUSH: + case ByteCodeConstants.RET: + case ByteCodeConstants.RETURN: + case ByteCodeConstants.EXCEPTIONLOAD: + case ByteCodeConstants.RETURNADDRESSLOAD: + break; + default: + System.err.println( + "Can not replace DupLoad in " + + instruction.getClass().getName() + + ", opcode=" + instruction.opcode); + } + } + + private void visit(List instructions) + { + for (int i=instructions.size()-1; i>=0; --i) + visit(instructions.get(i)); + } + + /** + * @return le dernier parent sur lequel une substitution a �t� faite + */ + public Instruction getParentFound() + { + return this.parentFound; + } + + private boolean match(Instruction parent, Instruction i) + { + if (i.opcode != ByteCodeConstants.DUPLOAD) + return false; + + DupLoad dupload = (DupLoad)i; + + if (dupload.dupStore == this.dupStore) + { + this.parentFound = parent; + return true; + } + + return false; + } +} diff --git a/src/jd/core/process/analyzer/classfile/visitor/ReplaceGetStaticVisitor.java b/src/jd/core/process/analyzer/classfile/visitor/ReplaceGetStaticVisitor.java new file mode 100644 index 00000000..a31a454e --- /dev/null +++ b/src/jd/core/process/analyzer/classfile/visitor/ReplaceGetStaticVisitor.java @@ -0,0 +1,568 @@ +package jd.core.process.analyzer.classfile.visitor; + +import java.util.List; + +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.ANewArray; +import jd.core.model.instruction.bytecode.instruction.AThrow; +import jd.core.model.instruction.bytecode.instruction.ArrayLength; +import jd.core.model.instruction.bytecode.instruction.ArrayLoadInstruction; +import jd.core.model.instruction.bytecode.instruction.ArrayStoreInstruction; +import jd.core.model.instruction.bytecode.instruction.AssertInstruction; +import jd.core.model.instruction.bytecode.instruction.AssignmentInstruction; +import jd.core.model.instruction.bytecode.instruction.BinaryOperatorInstruction; +import jd.core.model.instruction.bytecode.instruction.CheckCast; +import jd.core.model.instruction.bytecode.instruction.ComplexConditionalBranchInstruction; +import jd.core.model.instruction.bytecode.instruction.ConvertInstruction; +import jd.core.model.instruction.bytecode.instruction.DupStore; +import jd.core.model.instruction.bytecode.instruction.GetField; +import jd.core.model.instruction.bytecode.instruction.GetStatic; +import jd.core.model.instruction.bytecode.instruction.IfCmp; +import jd.core.model.instruction.bytecode.instruction.IfInstruction; +import jd.core.model.instruction.bytecode.instruction.IncInstruction; +import jd.core.model.instruction.bytecode.instruction.InitArrayInstruction; +import jd.core.model.instruction.bytecode.instruction.InstanceOf; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.InvokeInstruction; +import jd.core.model.instruction.bytecode.instruction.InvokeNoStaticInstruction; +import jd.core.model.instruction.bytecode.instruction.LookupSwitch; +import jd.core.model.instruction.bytecode.instruction.MonitorEnter; +import jd.core.model.instruction.bytecode.instruction.MonitorExit; +import jd.core.model.instruction.bytecode.instruction.MultiANewArray; +import jd.core.model.instruction.bytecode.instruction.NewArray; +import jd.core.model.instruction.bytecode.instruction.Pop; +import jd.core.model.instruction.bytecode.instruction.PutField; +import jd.core.model.instruction.bytecode.instruction.PutStatic; +import jd.core.model.instruction.bytecode.instruction.ReturnInstruction; +import jd.core.model.instruction.bytecode.instruction.StoreInstruction; +import jd.core.model.instruction.bytecode.instruction.TableSwitch; +import jd.core.model.instruction.bytecode.instruction.TernaryOpStore; +import jd.core.model.instruction.bytecode.instruction.TernaryOperator; +import jd.core.model.instruction.bytecode.instruction.UnaryOperatorInstruction; + + +public class ReplaceGetStaticVisitor +{ + private int index; + private Instruction newInstruction; + private Instruction parentFound; + + public ReplaceGetStaticVisitor(int index, Instruction newInstruction) + { + this.index = index; + this.newInstruction = newInstruction; + this.parentFound = null; + } + + public void visit(Instruction instruction) + { + switch (instruction.opcode) + { + case ByteCodeConstants.ARRAYLENGTH: + { + ArrayLength al = (ArrayLength)instruction; + if (match(al, al.arrayref)) + al.arrayref = this.newInstruction; + else + visit(al.arrayref); + } + break; + case ByteCodeConstants.AASTORE: + case ByteCodeConstants.ARRAYSTORE: + { + ArrayStoreInstruction asi = (ArrayStoreInstruction)instruction; + if (match(asi, asi.arrayref)) + { + asi.arrayref = this.newInstruction; + } + else + { + visit(asi.arrayref); + + if (this.parentFound == null) + { + if (match(asi, asi.indexref)) + { + asi.indexref = this.newInstruction; + } + else + { + visit(asi.indexref); + + if (this.parentFound == null) + { + if (match(asi, asi.valueref)) + asi.valueref = this.newInstruction; + else + visit(asi.valueref); + } + } + } + } + } + break; + case ByteCodeConstants.ASSERT: + { + AssertInstruction ai = (AssertInstruction)instruction; + if (match(ai, ai.test)) + { + ai.test = this.newInstruction; + } + else + { + visit(ai.test); + + if ((this.parentFound == null) && (ai.msg != null)) + { + if (match(ai, ai.msg)) + ai.msg = this.newInstruction; + else + visit(ai.msg); + } + } + } + break; + case ByteCodeConstants.ATHROW: + { + AThrow aThrow = (AThrow)instruction; + if (match(aThrow, aThrow.value)) + aThrow.value = this.newInstruction; + else + visit(aThrow.value); + } + break; + case ByteCodeConstants.UNARYOP: + { + UnaryOperatorInstruction uoi = (UnaryOperatorInstruction)instruction; + if (match(uoi, uoi.value)) + uoi.value = this.newInstruction; + else + visit(uoi.value); + } + break; + case ByteCodeConstants.BINARYOP: + { + BinaryOperatorInstruction boi = (BinaryOperatorInstruction)instruction; + if (match(boi, boi.value1)) + { + boi.value1 = this.newInstruction; + } + else + { + visit(boi.value1); + + if (this.parentFound == null) + { + if (match(boi, boi.value2)) + boi.value2 = this.newInstruction; + else + visit(boi.value2); + } + } + } + break; + case ByteCodeConstants.CHECKCAST: + { + CheckCast checkCast = (CheckCast)instruction; + if (match(checkCast, checkCast.objectref)) + checkCast.objectref = this.newInstruction; + else + visit(checkCast.objectref); + } + break; + case ByteCodeConstants.STORE: + case ByteCodeConstants.ASTORE: + case ByteCodeConstants.ISTORE: + { + StoreInstruction storeInstruction = (StoreInstruction)instruction; + if (match(storeInstruction, storeInstruction.valueref)) + storeInstruction.valueref = this.newInstruction; + else + visit(storeInstruction.valueref); + } + break; + case ByteCodeConstants.DUPSTORE: + { + DupStore dupStore = (DupStore)instruction; + if (match(dupStore, dupStore.objectref)) + dupStore.objectref = this.newInstruction; + else + visit(dupStore.objectref); + } + break; + case ByteCodeConstants.CONVERT: + case ByteCodeConstants.IMPLICITCONVERT: + { + ConvertInstruction ci = (ConvertInstruction)instruction; + if (match(ci, ci.value)) + ci.value = this.newInstruction; + else + visit(ci.value); + } + break; + case ByteCodeConstants.IFCMP: + { + IfCmp ifCmp = (IfCmp)instruction; + if (match(ifCmp, ifCmp.value1)) + { + ifCmp.value1 = this.newInstruction; + } + else + { + visit(ifCmp.value1); + + if (this.parentFound == null) + { + if (match(ifCmp, ifCmp.value2)) + ifCmp.value2 = this.newInstruction; + else + visit(ifCmp.value2); + } + } + } + break; + case ByteCodeConstants.IF: + case ByteCodeConstants.IFXNULL: + { + IfInstruction iff = (IfInstruction)instruction; + if (match(iff, iff.value)) + iff.value = this.newInstruction; + else + visit(iff.value); + } + break; + case ByteCodeConstants.COMPLEXIF: + { + List branchList = + ((ComplexConditionalBranchInstruction)instruction).instructions; + for (int i=branchList.size()-1; (i>=0) && (this.parentFound == null); --i) + { + visit(branchList.get(i)); + } + } + break; + case ByteCodeConstants.INSTANCEOF: + { + InstanceOf instanceOf = (InstanceOf)instruction; + if (match(instanceOf, instanceOf.objectref)) + instanceOf.objectref = this.newInstruction; + else + visit(instanceOf.objectref); + } + break; + case ByteCodeConstants.INVOKEINTERFACE: + case ByteCodeConstants.INVOKESPECIAL: + case ByteCodeConstants.INVOKEVIRTUAL: + { + InvokeNoStaticInstruction insi = + (InvokeNoStaticInstruction)instruction; + if (match(insi, insi.objectref)) + insi.objectref = this.newInstruction; + else + visit(insi.objectref); + } + case ByteCodeConstants.INVOKESTATIC: + case ByteCodeConstants.INVOKENEW: + { + List list = ((InvokeInstruction)instruction).args; + for (int i=list.size()-1; (i>=0) && (this.parentFound == null); --i) + { + if (match(instruction, list.get(i))) + list.set(i, this.newInstruction); + else + visit(list.get(i)); + } + } + break; + case ByteCodeConstants.LOOKUPSWITCH: + { + LookupSwitch ls = (LookupSwitch)instruction; + if (match(ls, ls.key)) + ls.key = this.newInstruction; + else + visit(ls.key); + } + break; + case ByteCodeConstants.MONITORENTER: + { + MonitorEnter monitorEnter = (MonitorEnter)instruction; + if (match(monitorEnter, monitorEnter.objectref)) + monitorEnter.objectref = this.newInstruction; + else + visit(monitorEnter.objectref); + } + break; + case ByteCodeConstants.MONITOREXIT: + { + MonitorExit monitorExit = (MonitorExit)instruction; + if (match(monitorExit, monitorExit.objectref)) + monitorExit.objectref = this.newInstruction; + else + visit(monitorExit.objectref); + } + break; + case ByteCodeConstants.MULTIANEWARRAY: + { + Instruction[] dimensions = ((MultiANewArray)instruction).dimensions; + for (int i=dimensions.length-1; (i>=0) && (this.parentFound == null); --i) + { + if (match(instruction, dimensions[i])) + dimensions[i] = this.newInstruction; + else + visit(dimensions[i]); + } + } + break; + case ByteCodeConstants.NEWARRAY: + { + NewArray newArray = (NewArray)instruction; + if (match(newArray, newArray.dimension)) + newArray.dimension = this.newInstruction; + else + visit(newArray.dimension); + } + break; + case ByteCodeConstants.ANEWARRAY: + { + ANewArray aNewArray = (ANewArray)instruction; + if (match(aNewArray, aNewArray.dimension)) + aNewArray.dimension = this.newInstruction; + else + visit(aNewArray.dimension); + } + break; + case ByteCodeConstants.POP: + { + Pop pop = (Pop)instruction; + if (match(pop, pop.objectref)) + pop.objectref = this.newInstruction; + else + visit(pop.objectref); + } + break; + case ByteCodeConstants.PUTFIELD: + { + PutField putField = (PutField)instruction; + if (match(putField, putField.objectref)) + { + putField.objectref = this.newInstruction; + } + else + { + visit(putField.objectref); + + if (this.parentFound == null) + { + if (match(putField, putField.valueref)) + putField.valueref = this.newInstruction; + else + visit(putField.valueref); + } + } + } + break; + case ByteCodeConstants.PUTSTATIC: + { + PutStatic putStatic = (PutStatic)instruction; + if (match(putStatic, putStatic.valueref)) + putStatic.valueref = this.newInstruction; + else + visit(putStatic.valueref); + } + break; + case ByteCodeConstants.XRETURN: + { + ReturnInstruction ri = (ReturnInstruction)instruction; + if (match(ri, ri.valueref)) + ri.valueref = this.newInstruction; + else + visit(ri.valueref); + } + break; + case ByteCodeConstants.TABLESWITCH: + { + TableSwitch ts = (TableSwitch)instruction; + if (match(ts, ts.key)) + ts.key = this.newInstruction; + else + visit(ts.key); + } + break; + case ByteCodeConstants.TERNARYOPSTORE: + { + TernaryOpStore tos = (TernaryOpStore)instruction; + if (match(tos, tos.objectref)) + tos.objectref = this.newInstruction; + else + visit(tos.objectref); + } + break; + case ByteCodeConstants.TERNARYOP: + { + TernaryOperator to = (TernaryOperator)instruction; + if (match(to, to.test)) + { + to.test = this.newInstruction; + } + else + { + visit(to.test); + + if (this.parentFound == null) + { + if (match(to, to.value1)) + { + to.value1 = this.newInstruction; + } + else + { + visit(to.value1); + + if (this.parentFound == null) + { + if (match(to, to.value2)) + to.value2 = this.newInstruction; + else + visit(to.value2); + } + } + } + } + } + break; + case ByteCodeConstants.ASSIGNMENT: + { + AssignmentInstruction ai = (AssignmentInstruction)instruction; + if (match(ai, ai.value1)) + { + ai.value1 = this.newInstruction; + } + else + { + visit(ai.value1); + + if (this.parentFound == null) + { + if (match(ai, ai.value2)) + ai.value2 = this.newInstruction; + else + visit(ai.value2); + } + } + } + break; + case ByteCodeConstants.ARRAYLOAD: + { + ArrayLoadInstruction ali = (ArrayLoadInstruction)instruction; + if (match(ali, ali.arrayref)) + { + ali.arrayref = this.newInstruction; + } + else + { + visit(ali.arrayref); + + if (this.parentFound == null) + { + if (match(ali, ali.indexref)) + ali.indexref = this.newInstruction; + else + visit(ali.indexref); + } + } + } + break; + case ByteCodeConstants.PREINC: + case ByteCodeConstants.POSTINC: + { + IncInstruction ii = (IncInstruction)instruction; + if (match(ii, ii.value)) + ii.value = this.newInstruction; + else + visit(ii.value); + } + break; + case ByteCodeConstants.GETFIELD: + { + GetField gf = (GetField)instruction; + if (match(gf, gf.objectref)) + gf.objectref = this.newInstruction; + else + visit(gf.objectref); + } + break; + case ByteCodeConstants.INITARRAY: + case ByteCodeConstants.NEWANDINITARRAY: + { + InitArrayInstruction iai = (InitArrayInstruction)instruction; + if (match(iai, iai.newArray)) + { + iai.newArray = this.newInstruction; + } + else + { + visit(iai.newArray); + + if ((this.parentFound == null) && (iai.values != null)) + visit(iai.values); + } + } + break; + case ByteCodeConstants.ACONST_NULL: + case ByteCodeConstants.LOAD: + case ByteCodeConstants.ALOAD: + case ByteCodeConstants.ILOAD: + case ByteCodeConstants.BIPUSH: + case ByteCodeConstants.ICONST: + case ByteCodeConstants.LCONST: + case ByteCodeConstants.FCONST: + case ByteCodeConstants.DCONST: + case ByteCodeConstants.DUPLOAD: + case ByteCodeConstants.GETSTATIC: + case ByteCodeConstants.GOTO: + case ByteCodeConstants.IINC: + case ByteCodeConstants.JSR: + case ByteCodeConstants.LDC: + case ByteCodeConstants.LDC2_W: + case ByteCodeConstants.NEW: + case ByteCodeConstants.NOP: + case ByteCodeConstants.SIPUSH: + case ByteCodeConstants.RET: + case ByteCodeConstants.RETURN: + case ByteCodeConstants.EXCEPTIONLOAD: + case ByteCodeConstants.RETURNADDRESSLOAD: + break; + default: + System.err.println( + "Can not replace DupLoad in " + + instruction.getClass().getName() + + ", opcode=" + instruction.opcode); + } + } + + private void visit(List instructions) + { + for (int i=instructions.size()-1; i>=0; --i) + visit(instructions.get(i)); + } + + /** + * @return le dernier parent sur lequel une substitution a �t� faite + */ + public Instruction getParentFound() + { + return this.parentFound; + } + + private boolean match(Instruction parent, Instruction i) + { + if ((i.opcode == ByteCodeConstants.GETSTATIC) && + (((GetStatic)i).index == this.index)) + { + this.parentFound = parent; + return true; + } + + return false; + } +} diff --git a/src/jd/core/process/analyzer/classfile/visitor/ReplaceMultipleOuterReferenceVisitor.java b/src/jd/core/process/analyzer/classfile/visitor/ReplaceMultipleOuterReferenceVisitor.java new file mode 100644 index 00000000..a5402ec5 --- /dev/null +++ b/src/jd/core/process/analyzer/classfile/visitor/ReplaceMultipleOuterReferenceVisitor.java @@ -0,0 +1,153 @@ +package jd.core.process.analyzer.classfile.visitor; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.Field; +import jd.core.model.classfile.constant.ConstantFieldref; +import jd.core.model.classfile.constant.ConstantNameAndType; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.ALoad; +import jd.core.model.instruction.bytecode.instruction.GetField; +import jd.core.model.instruction.bytecode.instruction.GetStatic; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.util.SignatureUtil; + + +/* + * Replace 'this.this$3.this$2.this$1.this$0.xxx' by 'TestInnerClass.this.xxx' + */ +public class ReplaceMultipleOuterReferenceVisitor + extends ReplaceOuterAccessorVisitor +{ + public ReplaceMultipleOuterReferenceVisitor(ClassFile classFile) + { + super(classFile); + } + + protected ClassFile match(Instruction instruction) + { + if (instruction.opcode != ByteCodeConstants.GETFIELD) + return null; + + GetField gf = (GetField)instruction; + + switch (gf.objectref.opcode) + { + case ByteCodeConstants.ALOAD: + { + ALoad aload = (ALoad)gf.objectref; + if (aload.index != 0) + return null; + Field field = this.classFile.getOuterThisField(); + if (field == null) + return null; + ConstantPool constants = classFile.getConstantPool(); + ConstantFieldref cfr = + constants.getConstantFieldref(gf.index); + if (cfr.class_index != classFile.getThisClassIndex()) + return null; + ConstantNameAndType cnat = + constants.getConstantNameAndType(cfr.name_and_type_index); + if ((field.name_index != cnat.name_index) || + (field.descriptor_index != cnat.descriptor_index)) + return null; + return this.classFile.getOuterClass(); + } + case ByteCodeConstants.OUTERTHIS: + { + ConstantPool constants = this.classFile.getConstantPool(); + GetStatic gs = (GetStatic)gf.objectref; + ConstantFieldref cfr = + constants.getConstantFieldref(gs.index); + String className = + constants.getConstantClassName(cfr.class_index); + ClassFile outerClass = this.classFile.getOuterClass(); + + while (outerClass != null) + { + if (outerClass.getThisClassName().equals(className)) + { + Field outerField = outerClass.getOuterThisField(); + + if (outerField == null) + return null; + + cfr = constants.getConstantFieldref(gf.index); + ConstantNameAndType cnat = + constants.getConstantNameAndType(cfr.name_and_type_index); + String fieldName = + constants.getConstantUtf8(cnat.name_index); + + ConstantPool outerConstants = + outerClass.getConstantPool(); + String outerFieldName = + outerConstants.getConstantUtf8(outerField.name_index); + + if (!fieldName.equals(outerFieldName)) + return null; + + String fieldDescriptor = + constants.getConstantUtf8(cnat.descriptor_index); + String outerFieldDescriptor = + outerConstants.getConstantUtf8(outerField.descriptor_index); + + if (!fieldDescriptor.equals(outerFieldDescriptor)) + return null; + + return outerClass.getOuterClass(); + } + + outerClass = outerClass.getOuterClass(); + } + + return null; + } + case ByteCodeConstants.GETFIELD: + { + ConstantPool constants = this.classFile.getConstantPool(); + ConstantFieldref cfr = + constants.getConstantFieldref(gf.index); + ConstantNameAndType cnat = + constants.getConstantNameAndType(cfr.name_and_type_index); + String descriptorName = + constants.getConstantUtf8(cnat.descriptor_index); + if (!SignatureUtil.IsObjectSignature(descriptorName)) + return null; + + ClassFile matchedClassFile = match(gf.objectref); + if ((matchedClassFile == null) || + !matchedClassFile.isAInnerClass()) + return null; + + Field matchedField = matchedClassFile.getOuterThisField(); + if (matchedField == null) + return null; + + String className = + constants.getConstantClassName(cfr.class_index); + + if (!className.equals(matchedClassFile.getThisClassName())) + return null; + + String fieldName = constants.getConstantUtf8(cnat.name_index); + + ConstantPool matchedConstants = matchedClassFile.getConstantPool(); + String matchedFieldName = + matchedConstants.getConstantUtf8(matchedField.name_index); + + if (! fieldName.equals(matchedFieldName)) + return null; + + String matchedDescriptorName = + matchedConstants.getConstantUtf8(matchedField.descriptor_index); + + if (! descriptorName.equals(matchedDescriptorName)) + return null; + + return matchedClassFile.getOuterClass(); + } + default: + return null; + } + } +} diff --git a/src/jd/core/process/analyzer/classfile/visitor/ReplaceOuterAccessorVisitor.java b/src/jd/core/process/analyzer/classfile/visitor/ReplaceOuterAccessorVisitor.java new file mode 100644 index 00000000..52515d9f --- /dev/null +++ b/src/jd/core/process/analyzer/classfile/visitor/ReplaceOuterAccessorVisitor.java @@ -0,0 +1,627 @@ +package jd.core.process.analyzer.classfile.visitor; + +import java.util.List; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.ClassFileConstants; +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.Method; +import jd.core.model.classfile.constant.ConstantFieldref; +import jd.core.model.classfile.constant.ConstantMethodref; +import jd.core.model.classfile.constant.ConstantNameAndType; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.ANewArray; +import jd.core.model.instruction.bytecode.instruction.AThrow; +import jd.core.model.instruction.bytecode.instruction.ArrayLength; +import jd.core.model.instruction.bytecode.instruction.ArrayLoadInstruction; +import jd.core.model.instruction.bytecode.instruction.ArrayStoreInstruction; +import jd.core.model.instruction.bytecode.instruction.AssertInstruction; +import jd.core.model.instruction.bytecode.instruction.AssignmentInstruction; +import jd.core.model.instruction.bytecode.instruction.BinaryOperatorInstruction; +import jd.core.model.instruction.bytecode.instruction.CheckCast; +import jd.core.model.instruction.bytecode.instruction.ComplexConditionalBranchInstruction; +import jd.core.model.instruction.bytecode.instruction.ConvertInstruction; +import jd.core.model.instruction.bytecode.instruction.DupStore; +import jd.core.model.instruction.bytecode.instruction.GetField; +import jd.core.model.instruction.bytecode.instruction.GetStatic; +import jd.core.model.instruction.bytecode.instruction.IfCmp; +import jd.core.model.instruction.bytecode.instruction.IfInstruction; +import jd.core.model.instruction.bytecode.instruction.IncInstruction; +import jd.core.model.instruction.bytecode.instruction.InitArrayInstruction; +import jd.core.model.instruction.bytecode.instruction.InstanceOf; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.InvokeInstruction; +import jd.core.model.instruction.bytecode.instruction.InvokeNoStaticInstruction; +import jd.core.model.instruction.bytecode.instruction.Invokestatic; +import jd.core.model.instruction.bytecode.instruction.LookupSwitch; +import jd.core.model.instruction.bytecode.instruction.MonitorEnter; +import jd.core.model.instruction.bytecode.instruction.MonitorExit; +import jd.core.model.instruction.bytecode.instruction.MultiANewArray; +import jd.core.model.instruction.bytecode.instruction.NewArray; +import jd.core.model.instruction.bytecode.instruction.Pop; +import jd.core.model.instruction.bytecode.instruction.PutField; +import jd.core.model.instruction.bytecode.instruction.PutStatic; +import jd.core.model.instruction.bytecode.instruction.ReturnInstruction; +import jd.core.model.instruction.bytecode.instruction.StoreInstruction; +import jd.core.model.instruction.bytecode.instruction.TableSwitch; +import jd.core.model.instruction.bytecode.instruction.TernaryOpStore; +import jd.core.model.instruction.bytecode.instruction.TernaryOperator; +import jd.core.model.instruction.bytecode.instruction.UnaryOperatorInstruction; + +/* + * Replace static call to "OuterClass access$0(InnerClass)" methods. + */ +public class ReplaceOuterAccessorVisitor +{ + protected ClassFile classFile; + + public ReplaceOuterAccessorVisitor(ClassFile classFile) + { + this.classFile = classFile; + } + + public void visit(Instruction instruction) + { + switch (instruction.opcode) + { + case ByteCodeConstants.ARRAYLENGTH: + { + ArrayLength al = (ArrayLength)instruction; + ClassFile matchedClassFile = match(al.arrayref); + if (matchedClassFile != null) + al.arrayref = newInstruction(matchedClassFile, al.arrayref); + else + visit(al.arrayref); + } + break; + case ByteCodeConstants.AASTORE: + case ByteCodeConstants.ARRAYSTORE: + { + ArrayStoreInstruction asi = (ArrayStoreInstruction)instruction; + ClassFile matchedClassFile = match(asi.arrayref); + if (matchedClassFile != null) + asi.arrayref = newInstruction(matchedClassFile, asi.arrayref); + else + visit(asi.arrayref); + matchedClassFile = match(asi.indexref); + if (matchedClassFile != null) + asi.indexref = newInstruction(matchedClassFile, asi.indexref); + else + visit(asi.indexref); + matchedClassFile = match(asi.valueref); + if (matchedClassFile != null) + asi.valueref = newInstruction(matchedClassFile, asi.valueref); + else + visit(asi.valueref); + } + break; + case ByteCodeConstants.ASSERT: + { + AssertInstruction ai = (AssertInstruction)instruction; + ClassFile matchedClassFile = match(ai.test); + if (matchedClassFile != null) + ai.test = newInstruction(matchedClassFile, ai.test); + else + visit(ai.test); + if (ai.msg != null) + { + matchedClassFile = match(ai.msg); + if (matchedClassFile != null) + ai.msg = newInstruction(matchedClassFile, ai.msg); + else + visit(ai.msg); + } + } + break; + case ByteCodeConstants.ATHROW: + { + AThrow aThrow = (AThrow)instruction; + ClassFile matchedClassFile = match(aThrow.value); + if (matchedClassFile != null) + aThrow.value = newInstruction(matchedClassFile, aThrow.value); + else + visit(aThrow.value); + } + break; + case ByteCodeConstants.UNARYOP: + { + UnaryOperatorInstruction uoi = (UnaryOperatorInstruction)instruction; + ClassFile matchedClassFile = match(uoi.value); + if (matchedClassFile != null) + uoi.value = newInstruction(matchedClassFile, uoi.value); + else + visit(uoi.value); + } + break; + case ByteCodeConstants.BINARYOP: + { + BinaryOperatorInstruction boi = (BinaryOperatorInstruction)instruction; + ClassFile matchedClassFile = match(boi.value1); + if (matchedClassFile != null) + boi.value1 = newInstruction(matchedClassFile, boi.value1); + else + visit(boi.value1); + matchedClassFile = match(boi.value2); + if (matchedClassFile != null) + boi.value2 = newInstruction(matchedClassFile, boi.value2); + else + visit(boi.value2); + } + break; + case ByteCodeConstants.CHECKCAST: + { + CheckCast checkCast = (CheckCast)instruction; + ClassFile matchedClassFile = match(checkCast.objectref); + if (matchedClassFile != null) + checkCast.objectref = newInstruction(matchedClassFile, checkCast.objectref); + else + visit(checkCast.objectref); + } + break; + case ByteCodeConstants.STORE: + case ByteCodeConstants.ASTORE: + case ByteCodeConstants.ISTORE: + { + StoreInstruction storeInstruction = (StoreInstruction)instruction; + ClassFile matchedClassFile = match(storeInstruction.valueref); + if (matchedClassFile != null) + storeInstruction.valueref = newInstruction(matchedClassFile, storeInstruction.valueref); + else + visit(storeInstruction.valueref); + } + break; + case ByteCodeConstants.DUPSTORE: + { + DupStore dupStore = (DupStore)instruction; + ClassFile matchedClassFile = match(dupStore.objectref); + if (matchedClassFile != null) + dupStore.objectref = newInstruction(matchedClassFile, dupStore.objectref); + else + visit(dupStore.objectref); + } + break; + case ByteCodeConstants.CONVERT: + case ByteCodeConstants.IMPLICITCONVERT: + { + ConvertInstruction ci = (ConvertInstruction)instruction; + ClassFile matchedClassFile = match(ci.value); + if (matchedClassFile != null) + ci.value = newInstruction(matchedClassFile, ci.value); + else + visit(ci.value); + } + break; + case ByteCodeConstants.IFCMP: + { + IfCmp ifCmp = (IfCmp)instruction; + ClassFile matchedClassFile = match(ifCmp.value1); + if (matchedClassFile != null) + ifCmp.value1 = newInstruction(matchedClassFile, ifCmp.value1); + else + visit(ifCmp.value1); + matchedClassFile = match(ifCmp.value2); + if (matchedClassFile != null) + ifCmp.value2 = newInstruction(matchedClassFile, ifCmp.value2); + else + visit(ifCmp.value2); + } + break; + case ByteCodeConstants.IF: + case ByteCodeConstants.IFXNULL: + { + IfInstruction iff = (IfInstruction)instruction; + ClassFile matchedClassFile = match(iff.value); + if (matchedClassFile != null) + iff.value = newInstruction(matchedClassFile, iff.value); + else + visit(iff.value); + } + break; + case ByteCodeConstants.COMPLEXIF: + { + List branchList = + ((ComplexConditionalBranchInstruction)instruction).instructions; + for (int i=branchList.size()-1; i>=0; --i) + visit(branchList.get(i)); + } + break; + case ByteCodeConstants.INSTANCEOF: + { + InstanceOf instanceOf = (InstanceOf)instruction; + ClassFile matchedClassFile = match(instanceOf.objectref); + if (matchedClassFile != null) + instanceOf.objectref = newInstruction(matchedClassFile, instanceOf.objectref); + else + visit(instanceOf.objectref); + } + break; + case ByteCodeConstants.INVOKEINTERFACE: + case ByteCodeConstants.INVOKESPECIAL: + case ByteCodeConstants.INVOKEVIRTUAL: + { + InvokeNoStaticInstruction insi = + (InvokeNoStaticInstruction)instruction; + ClassFile matchedClassFile = match(insi.objectref); + if (matchedClassFile != null) + insi.objectref = newInstruction(matchedClassFile, insi.objectref); + else + visit(insi.objectref); + } + case ByteCodeConstants.INVOKESTATIC: + case ByteCodeConstants.INVOKENEW: + { + List list = ((InvokeInstruction)instruction).args; + for (int i=list.size()-1; i>=0; --i) + { + ClassFile matchedClassFile = match(list.get(i)); + if (matchedClassFile != null) + list.set(i, newInstruction(matchedClassFile, list.get(i))); + else + visit(list.get(i)); + } + } + break; + case ByteCodeConstants.LOOKUPSWITCH: + { + LookupSwitch ls = (LookupSwitch)instruction; + ClassFile matchedClassFile = match(ls.key); + if (matchedClassFile != null) + ls.key = newInstruction(matchedClassFile, ls.key); + else + visit(ls.key); + } + break; + case ByteCodeConstants.MONITORENTER: + { + MonitorEnter monitorEnter = (MonitorEnter)instruction; + ClassFile matchedClassFile = match(monitorEnter.objectref); + if (matchedClassFile != null) + monitorEnter.objectref = newInstruction(matchedClassFile, monitorEnter.objectref); + else + visit(monitorEnter.objectref); + } + break; + case ByteCodeConstants.MONITOREXIT: + { + MonitorExit monitorExit = (MonitorExit)instruction; + ClassFile matchedClassFile = match(monitorExit.objectref); + if (matchedClassFile != null) + monitorExit.objectref = newInstruction(matchedClassFile, monitorExit.objectref); + else + visit(monitorExit.objectref); + } + break; + case ByteCodeConstants.MULTIANEWARRAY: + { + Instruction[] dimensions = ((MultiANewArray)instruction).dimensions; + for (int i=dimensions.length-1; i>=0; --i) + { + ClassFile matchedClassFile = match(dimensions[i]); + if (matchedClassFile != null) + dimensions[i] = newInstruction(matchedClassFile, dimensions[i]); + else + visit(dimensions[i]); + } + } + break; + case ByteCodeConstants.NEWARRAY: + { + NewArray newArray = (NewArray)instruction; + ClassFile matchedClassFile = match(newArray.dimension); + if (matchedClassFile != null) + newArray.dimension = newInstruction(matchedClassFile, newArray.dimension); + else + visit(newArray.dimension); + } + break; + case ByteCodeConstants.ANEWARRAY: + { + ANewArray aNewArray = (ANewArray)instruction; + ClassFile matchedClassFile = match(aNewArray.dimension); + if (matchedClassFile != null) + aNewArray.dimension = newInstruction(matchedClassFile, aNewArray.dimension); + else + visit(aNewArray.dimension); + } + break; + case ByteCodeConstants.POP: + { + Pop pop = (Pop)instruction; + ClassFile matchedClassFile = match(pop.objectref); + if (matchedClassFile != null) + pop.objectref = newInstruction(matchedClassFile, pop.objectref); + else + visit(pop.objectref); + } + break; + case ByteCodeConstants.PUTFIELD: + { + PutField putField = (PutField)instruction; + ClassFile matchedClassFile = match(putField.objectref); + if (matchedClassFile != null) + putField.objectref = newInstruction(matchedClassFile, putField.objectref); + else + visit(putField.objectref); + matchedClassFile = match(putField.valueref); + if (matchedClassFile != null) + putField.valueref = newInstruction(matchedClassFile, putField.valueref); + else + visit(putField.valueref); + } + break; + case ByteCodeConstants.PUTSTATIC: + { + PutStatic putStatic = (PutStatic)instruction; + ClassFile matchedClassFile = match(putStatic.valueref); + if (matchedClassFile != null) + putStatic.valueref = newInstruction(matchedClassFile, putStatic.valueref); + else + visit(putStatic.valueref); + } + break; + case ByteCodeConstants.XRETURN: + { + ReturnInstruction ri = (ReturnInstruction)instruction; + ClassFile matchedClassFile = match(ri.valueref); + if (matchedClassFile != null) + ri.valueref = newInstruction(matchedClassFile, ri.valueref); + else + visit(ri.valueref); + } + break; + case ByteCodeConstants.TABLESWITCH: + { + TableSwitch ts = (TableSwitch)instruction; + ClassFile matchedClassFile = match(ts.key); + if (matchedClassFile != null) + ts.key = newInstruction(matchedClassFile, ts.key); + else + visit(ts.key); + } + break; + case ByteCodeConstants.TERNARYOPSTORE: + { + TernaryOpStore tos = (TernaryOpStore)instruction; + ClassFile matchedClassFile = match(tos.objectref); + if (matchedClassFile != null) + tos.objectref = newInstruction(matchedClassFile, tos.objectref); + else + visit(tos.objectref); + } + break; + case ByteCodeConstants.TERNARYOP: + { + TernaryOperator to = (TernaryOperator)instruction; + ClassFile matchedClassFile = match(to.test); + if (matchedClassFile != null) + to.test = newInstruction(matchedClassFile, to.test); + else + visit(to.test); + matchedClassFile = match(to.value1); + if (matchedClassFile != null) + to.value1 = newInstruction(matchedClassFile, to.value1); + else + visit(to.value1); + matchedClassFile = match(to.value2); + if (matchedClassFile != null) + to.value2 = newInstruction(matchedClassFile, to.value2); + else + visit(to.value2); + } + break; + case ByteCodeConstants.ASSIGNMENT: + { + AssignmentInstruction ai = (AssignmentInstruction)instruction; + ClassFile matchedClassFile = match(ai.value1); + if (matchedClassFile != null) + ai.value1 = newInstruction(matchedClassFile, ai.value1); + else + visit(ai.value1); + matchedClassFile = match(ai.value2); + if (matchedClassFile != null) + ai.value2 = newInstruction(matchedClassFile, ai.value2); + else + visit(ai.value2); + } + break; + case ByteCodeConstants.ARRAYLOAD: + { + ArrayLoadInstruction ali = (ArrayLoadInstruction)instruction; + ClassFile matchedClassFile = match(ali.arrayref); + if (matchedClassFile != null) + ali.arrayref = newInstruction(matchedClassFile, ali.arrayref); + else + visit(ali.arrayref); + matchedClassFile = match(ali.indexref); + if (matchedClassFile != null) + ali.indexref = newInstruction(matchedClassFile, ali.indexref); + else + visit(ali.indexref); + } + break; + case ByteCodeConstants.PREINC: + case ByteCodeConstants.POSTINC: + { + IncInstruction ii = (IncInstruction)instruction; + ClassFile matchedClassFile = match(ii.value); + if (matchedClassFile != null) + ii.value = newInstruction(matchedClassFile, ii.value); + else + visit(ii.value); + } + break; + case ByteCodeConstants.GETFIELD: + { + GetField gf = (GetField)instruction; + ClassFile matchedClassFile = match(gf.objectref); + if (matchedClassFile != null) + gf.objectref = newInstruction(matchedClassFile, gf.objectref); + else + visit(gf.objectref); + } + break; + case ByteCodeConstants.INITARRAY: + case ByteCodeConstants.NEWANDINITARRAY: + { + InitArrayInstruction iai = (InitArrayInstruction)instruction; + ClassFile matchedClassFile = match(iai.newArray); + if (matchedClassFile != null) + iai.newArray = newInstruction(matchedClassFile, iai.newArray); + else + visit(iai.newArray); + if (iai.values != null) + visit(iai.values); + } + break; + case ByteCodeConstants.ACONST_NULL: + case ByteCodeConstants.LOAD: + case ByteCodeConstants.ALOAD: + case ByteCodeConstants.ILOAD: + case ByteCodeConstants.BIPUSH: + case ByteCodeConstants.ICONST: + case ByteCodeConstants.LCONST: + case ByteCodeConstants.FCONST: + case ByteCodeConstants.DCONST: + case ByteCodeConstants.DUPLOAD: + case ByteCodeConstants.GETSTATIC: + case ByteCodeConstants.OUTERTHIS: + case ByteCodeConstants.GOTO: + case ByteCodeConstants.IINC: + case ByteCodeConstants.JSR: + case ByteCodeConstants.LDC: + case ByteCodeConstants.LDC2_W: + case ByteCodeConstants.NEW: + case ByteCodeConstants.NOP: + case ByteCodeConstants.SIPUSH: + case ByteCodeConstants.RET: + case ByteCodeConstants.RETURN: + case ByteCodeConstants.EXCEPTIONLOAD: + case ByteCodeConstants.RETURNADDRESSLOAD: + break; + default: + System.err.println( + "Can not replace DupLoad in " + + instruction.getClass().getName() + + ", opcode=" + instruction.opcode); + } + } + + public void visit(List instructions) + { + for (int index=instructions.size()-1; index>=0; --index) + { + Instruction i = instructions.get(index); + ClassFile matchedClassFile = match(i); + + if (matchedClassFile != null) + instructions.set(index, newInstruction(matchedClassFile, i)); + else + visit(i); + } + } + + protected ClassFile match(Instruction instruction) + { + if (instruction.opcode != ByteCodeConstants.INVOKESTATIC) + return null; + + Invokestatic is = (Invokestatic)instruction; + if (is.args.size() != 1) + return null; + + ClassFile matchedClassFile = innerMatch(is.args.get(0)); + + if ((matchedClassFile == null) || !matchedClassFile.isAInnerClass()) + return null; + + ConstantPool constants = classFile.getConstantPool(); + + ConstantMethodref cmr = + constants.getConstantMethodref(is.index); + String className = + constants.getConstantClassName(cmr.class_index); + + if (!className.equals(matchedClassFile.getThisClassName())) + return null; + + ConstantNameAndType cnat = + constants.getConstantNameAndType(cmr.name_and_type_index); + String methodName = constants.getConstantUtf8(cnat.name_index); + String methodDescriptor = + constants.getConstantUtf8(cnat.descriptor_index); + Method method = + matchedClassFile.getMethod(methodName, methodDescriptor); + + if ((method == null) || + ((method.access_flags & (ClassFileConstants.ACC_SYNTHETIC|ClassFileConstants.ACC_STATIC)) + != (ClassFileConstants.ACC_SYNTHETIC|ClassFileConstants.ACC_STATIC))) + return null; + + ClassFile outerClassFile = matchedClassFile.getOuterClass(); + String returnedSignature = cmr.getReturnedSignature(); + + if (!returnedSignature.equals(outerClassFile.getInternalClassName())) + return null; + + return outerClassFile; + } + + private ClassFile innerMatch(Instruction instruction) + { + switch (instruction.opcode) + { + case ByteCodeConstants.OUTERTHIS: + { + GetStatic gs = (GetStatic)instruction; + ConstantPool constants = classFile.getConstantPool(); + + ConstantFieldref cfr = constants.getConstantFieldref(gs.index); + String className = + constants.getConstantClassName(cfr.class_index); + ClassFile outerClassFile = classFile.getOuterClass(); + + if ((outerClassFile == null) || + !className.equals(outerClassFile.getThisClassName())) + return null; + + ConstantNameAndType cnat = + constants.getConstantNameAndType(cfr.name_and_type_index); + String descriptor = + constants.getConstantUtf8(cnat.descriptor_index); + + if (! descriptor.equals(outerClassFile.getInternalClassName())) + return null; + + return outerClassFile; + } + case ByteCodeConstants.INVOKESTATIC: + return match(instruction); + default: + return null; + } + } + + private Instruction newInstruction(ClassFile matchedClassFile, Instruction i) + { + String internalMatchedClassName = + matchedClassFile.getInternalClassName(); + String matchedClassName = matchedClassFile.getThisClassName(); + + ConstantPool constants = this.classFile.getConstantPool(); + + int signatureIndex = constants.addConstantUtf8(matchedClassName); + int classIndex = constants.addConstantClass(signatureIndex); + int thisIndex = constants.thisLocalVariableNameIndex; + int descriptorIndex = + constants.addConstantUtf8(internalMatchedClassName); + int nameAndTypeIndex = constants.addConstantNameAndType( + thisIndex, descriptorIndex); + + int matchedThisFieldrefIndex = + constants.addConstantFieldref(classIndex, nameAndTypeIndex); + + return new GetStatic( + ByteCodeConstants.OUTERTHIS, i.offset, + i.lineNumber, matchedThisFieldrefIndex); + } +} diff --git a/src/jd/core/process/analyzer/classfile/visitor/ReplaceOuterReferenceVisitor.java b/src/jd/core/process/analyzer/classfile/visitor/ReplaceOuterReferenceVisitor.java new file mode 100644 index 00000000..3e046926 --- /dev/null +++ b/src/jd/core/process/analyzer/classfile/visitor/ReplaceOuterReferenceVisitor.java @@ -0,0 +1,497 @@ +package jd.core.process.analyzer.classfile.visitor; + +import java.util.List; + +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.ANewArray; +import jd.core.model.instruction.bytecode.instruction.AThrow; +import jd.core.model.instruction.bytecode.instruction.ArrayLength; +import jd.core.model.instruction.bytecode.instruction.ArrayLoadInstruction; +import jd.core.model.instruction.bytecode.instruction.ArrayStoreInstruction; +import jd.core.model.instruction.bytecode.instruction.AssertInstruction; +import jd.core.model.instruction.bytecode.instruction.AssignmentInstruction; +import jd.core.model.instruction.bytecode.instruction.BinaryOperatorInstruction; +import jd.core.model.instruction.bytecode.instruction.CheckCast; +import jd.core.model.instruction.bytecode.instruction.ComplexConditionalBranchInstruction; +import jd.core.model.instruction.bytecode.instruction.ConvertInstruction; +import jd.core.model.instruction.bytecode.instruction.DupStore; +import jd.core.model.instruction.bytecode.instruction.GetField; +import jd.core.model.instruction.bytecode.instruction.GetStatic; +import jd.core.model.instruction.bytecode.instruction.IfCmp; +import jd.core.model.instruction.bytecode.instruction.IfInstruction; +import jd.core.model.instruction.bytecode.instruction.IncInstruction; +import jd.core.model.instruction.bytecode.instruction.IndexInstruction; +import jd.core.model.instruction.bytecode.instruction.InitArrayInstruction; +import jd.core.model.instruction.bytecode.instruction.InstanceOf; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.InvokeInstruction; +import jd.core.model.instruction.bytecode.instruction.InvokeNoStaticInstruction; +import jd.core.model.instruction.bytecode.instruction.LookupSwitch; +import jd.core.model.instruction.bytecode.instruction.MonitorEnter; +import jd.core.model.instruction.bytecode.instruction.MonitorExit; +import jd.core.model.instruction.bytecode.instruction.MultiANewArray; +import jd.core.model.instruction.bytecode.instruction.NewArray; +import jd.core.model.instruction.bytecode.instruction.Pop; +import jd.core.model.instruction.bytecode.instruction.PutField; +import jd.core.model.instruction.bytecode.instruction.PutStatic; +import jd.core.model.instruction.bytecode.instruction.ReturnInstruction; +import jd.core.model.instruction.bytecode.instruction.StoreInstruction; +import jd.core.model.instruction.bytecode.instruction.TableSwitch; +import jd.core.model.instruction.bytecode.instruction.TernaryOpStore; +import jd.core.model.instruction.bytecode.instruction.TernaryOperator; +import jd.core.model.instruction.bytecode.instruction.UnaryOperatorInstruction; + +/* + * Replace 'ALoad(1)' in constructor by 'OuterThis()': + * replace '???.xxx' by 'TestInnerClass.this.xxx'. + */ +public class ReplaceOuterReferenceVisitor +{ + private int opcode; + private int index; + private int outerThisInstructionIndex; + + public ReplaceOuterReferenceVisitor( + int opcode, int index, int outerThisInstructionIndex) + { + this.opcode = opcode; + this.index = index; + this.outerThisInstructionIndex = outerThisInstructionIndex; + } + + public void init(int opcode, int index) + { + this.opcode = opcode; + this.index = index; + } + + public void visit(Instruction instruction) + { + switch (instruction.opcode) + { + case ByteCodeConstants.ARRAYLENGTH: + { + ArrayLength al = (ArrayLength)instruction; + if (match(al.arrayref)) + al.arrayref = newInstruction(al.arrayref); + else + visit(al.arrayref); + } + break; + case ByteCodeConstants.AASTORE: + case ByteCodeConstants.ARRAYSTORE: + { + ArrayStoreInstruction asi = (ArrayStoreInstruction)instruction; + if (match(asi.arrayref)) + asi.arrayref = newInstruction(asi.arrayref); + else + visit(asi.arrayref); + if (match(asi.indexref)) + asi.indexref = newInstruction(asi.indexref); + else + visit(asi.indexref); + if (match(asi.valueref)) + asi.valueref = newInstruction(asi.valueref); + else + visit(asi.valueref); + } + break; + case ByteCodeConstants.ASSERT: + { + AssertInstruction ai = (AssertInstruction)instruction; + if (match(ai.test)) + ai.test = newInstruction(ai.test); + else + visit(ai.test); + if (ai.msg != null) + { + if (match(ai.msg)) + ai.msg = newInstruction(ai.msg); + else + visit(ai.msg); + } + } + break; + case ByteCodeConstants.ATHROW: + { + AThrow aThrow = (AThrow)instruction; + if (match(aThrow.value)) + aThrow.value = newInstruction(aThrow.value); + else + visit(aThrow.value); + } + break; + case ByteCodeConstants.UNARYOP: + { + UnaryOperatorInstruction uoi = (UnaryOperatorInstruction)instruction; + if (match(uoi.value)) + uoi.value = newInstruction(uoi.value); + else + visit(uoi.value); + } + break; + case ByteCodeConstants.BINARYOP: + { + BinaryOperatorInstruction boi = (BinaryOperatorInstruction)instruction; + if (match(boi.value1)) + boi.value1 = newInstruction(boi.value1); + else + visit(boi.value1); + if (match(boi.value2)) + boi.value2 = newInstruction(boi.value2); + else + visit(boi.value2); + } + break; + case ByteCodeConstants.CHECKCAST: + { + CheckCast checkCast = (CheckCast)instruction; + if (match(checkCast.objectref)) + checkCast.objectref = newInstruction(checkCast.objectref); + else + visit(checkCast.objectref); + } + break; + case ByteCodeConstants.STORE: + case ByteCodeConstants.ASTORE: + case ByteCodeConstants.ISTORE: + { + StoreInstruction storeInstruction = (StoreInstruction)instruction; + if (match(storeInstruction.valueref)) + storeInstruction.valueref = newInstruction(storeInstruction.valueref); + else + visit(storeInstruction.valueref); + } + break; + case ByteCodeConstants.DUPSTORE: + { + DupStore dupStore = (DupStore)instruction; + if (match(dupStore.objectref)) + dupStore.objectref = newInstruction(dupStore.objectref); + else + visit(dupStore.objectref); + } + break; + case ByteCodeConstants.CONVERT: + case ByteCodeConstants.IMPLICITCONVERT: + { + ConvertInstruction ci = (ConvertInstruction)instruction; + if (match(ci.value)) + ci.value = newInstruction(ci.value); + else + visit(ci.value); + } + break; + case ByteCodeConstants.IFCMP: + { + IfCmp ifCmp = (IfCmp)instruction; + if (match(ifCmp.value1)) + ifCmp.value1 = newInstruction(ifCmp.value1); + else + visit(ifCmp.value1); + if (match(ifCmp.value2)) + ifCmp.value2 = newInstruction(ifCmp.value2); + else + visit(ifCmp.value2); + } + break; + case ByteCodeConstants.IF: + case ByteCodeConstants.IFXNULL: + { + IfInstruction iff = (IfInstruction)instruction; + if (match(iff.value)) + iff.value = newInstruction(iff.value); + else + visit(iff.value); + } + break; + case ByteCodeConstants.COMPLEXIF: + { + List branchList = + ((ComplexConditionalBranchInstruction)instruction).instructions; + for (int i=branchList.size()-1; i>=0; --i) + visit(branchList.get(i)); + } + break; + case ByteCodeConstants.INSTANCEOF: + { + InstanceOf instanceOf = (InstanceOf)instruction; + if (match(instanceOf.objectref)) + instanceOf.objectref = newInstruction(instanceOf.objectref); + else + visit(instanceOf.objectref); + } + break; + case ByteCodeConstants.INVOKEINTERFACE: + case ByteCodeConstants.INVOKESPECIAL: + case ByteCodeConstants.INVOKEVIRTUAL: + { + InvokeNoStaticInstruction insi = + (InvokeNoStaticInstruction)instruction; + if (match(insi.objectref)) + insi.objectref = newInstruction(insi.objectref); + else + visit(insi.objectref); + } + case ByteCodeConstants.INVOKESTATIC: + case ByteCodeConstants.INVOKENEW: + { + List list = ((InvokeInstruction)instruction).args; + for (int i=list.size()-1; i>=0; --i) + { + if (match(list.get(i))) + list.set(i, newInstruction(list.get(i))); + else + visit(list.get(i)); + } + } + break; + case ByteCodeConstants.LOOKUPSWITCH: + { + LookupSwitch ls = (LookupSwitch)instruction; + if (match(ls.key)) + ls.key = newInstruction(ls.key); + else + visit(ls.key); + } + break; + case ByteCodeConstants.MONITORENTER: + { + MonitorEnter monitorEnter = (MonitorEnter)instruction; + if (match(monitorEnter.objectref)) + monitorEnter.objectref = newInstruction(monitorEnter.objectref); + else + visit(monitorEnter.objectref); + } + break; + case ByteCodeConstants.MONITOREXIT: + { + MonitorExit monitorExit = (MonitorExit)instruction; + if (match(monitorExit.objectref)) + monitorExit.objectref = newInstruction(monitorExit.objectref); + else + visit(monitorExit.objectref); + } + break; + case ByteCodeConstants.MULTIANEWARRAY: + { + Instruction[] dimensions = ((MultiANewArray)instruction).dimensions; + for (int i=dimensions.length-1; i>=0; --i) + { + if (match(dimensions[i])) + dimensions[i] = newInstruction(dimensions[i]); + else + visit(dimensions[i]); + } + } + break; + case ByteCodeConstants.NEWARRAY: + { + NewArray newArray = (NewArray)instruction; + if (match(newArray.dimension)) + newArray.dimension = newInstruction(newArray.dimension); + else + visit(newArray.dimension); + } + break; + case ByteCodeConstants.ANEWARRAY: + { + ANewArray aNewArray = (ANewArray)instruction; + if (match(aNewArray.dimension)) + aNewArray.dimension = newInstruction(aNewArray.dimension); + else + visit(aNewArray.dimension); + } + break; + case ByteCodeConstants.POP: + { + Pop pop = (Pop)instruction; + if (match(pop.objectref)) + pop.objectref = newInstruction(pop.objectref); + else + visit(pop.objectref); + } + break; + case ByteCodeConstants.PUTFIELD: + { + PutField putField = (PutField)instruction; + if (match(putField.objectref)) + putField.objectref = newInstruction(putField.objectref); + else + visit(putField.objectref); + if (match(putField.valueref)) + putField.valueref = newInstruction(putField.valueref); + else + visit(putField.valueref); + } + break; + case ByteCodeConstants.PUTSTATIC: + { + PutStatic putStatic = (PutStatic)instruction; + if (match(putStatic.valueref)) + putStatic.valueref = newInstruction(putStatic.valueref); + else + visit(putStatic.valueref); + } + break; + case ByteCodeConstants.XRETURN: + { + ReturnInstruction ri = (ReturnInstruction)instruction; + if (match(ri.valueref)) + ri.valueref = newInstruction(ri.valueref); + else + visit(ri.valueref); + } + break; + case ByteCodeConstants.TABLESWITCH: + { + TableSwitch ts = (TableSwitch)instruction; + if (match(ts.key)) + ts.key = newInstruction(ts.key); + else + visit(ts.key); + } + break; + case ByteCodeConstants.TERNARYOPSTORE: + { + TernaryOpStore tos = (TernaryOpStore)instruction; + if (match(tos.objectref)) + tos.objectref = newInstruction(tos.objectref); + else + visit(tos.objectref); + } + break; + case ByteCodeConstants.TERNARYOP: + { + TernaryOperator to = (TernaryOperator)instruction; + if (match(to.test)) + to.test = newInstruction(to.test); + else + visit(to.test); + if (match(to.value1)) + to.value1 = newInstruction(to.value1); + else + visit(to.value1); + if (match(to.value2)) + to.value2 = newInstruction(to.value2); + else + visit(to.value2); + } + break; + case ByteCodeConstants.ASSIGNMENT: + { + AssignmentInstruction ai = (AssignmentInstruction)instruction; + if (match(ai.value1)) + ai.value1 = newInstruction(ai.value1); + else + visit(ai.value1); + if (match(ai.value2)) + ai.value2 = newInstruction(ai.value2); + else + visit(ai.value2); + } + break; + case ByteCodeConstants.ARRAYLOAD: + { + ArrayLoadInstruction ali = (ArrayLoadInstruction)instruction; + if (match(ali.arrayref)) + ali.arrayref = newInstruction(ali.arrayref); + else + visit(ali.arrayref); + if (match(ali.indexref)) + ali.indexref = newInstruction(ali.indexref); + else + visit(ali.indexref); + } + break; + case ByteCodeConstants.PREINC: + case ByteCodeConstants.POSTINC: + { + IncInstruction ii = (IncInstruction)instruction; + if (match(ii.value)) + ii.value = newInstruction(ii.value); + else + visit(ii.value); + } + break; + case ByteCodeConstants.GETFIELD: + { + GetField gf = (GetField)instruction; + if (match(gf.objectref)) + gf.objectref = newInstruction(gf.objectref); + else + visit(gf.objectref); + } + break; + case ByteCodeConstants.INITARRAY: + case ByteCodeConstants.NEWANDINITARRAY: + { + InitArrayInstruction iai = (InitArrayInstruction)instruction; + if (match(iai.newArray)) + iai.newArray = newInstruction(iai.newArray); + else + visit(iai.newArray); + if (iai.values != null) + visit(iai.values); + } + break; + case ByteCodeConstants.ACONST_NULL: + case ByteCodeConstants.LOAD: + case ByteCodeConstants.ALOAD: + case ByteCodeConstants.ILOAD: + case ByteCodeConstants.BIPUSH: + case ByteCodeConstants.ICONST: + case ByteCodeConstants.LCONST: + case ByteCodeConstants.FCONST: + case ByteCodeConstants.DCONST: + case ByteCodeConstants.DUPLOAD: + case ByteCodeConstants.GETSTATIC: + case ByteCodeConstants.OUTERTHIS: + case ByteCodeConstants.GOTO: + case ByteCodeConstants.IINC: + case ByteCodeConstants.JSR: + case ByteCodeConstants.LDC: + case ByteCodeConstants.LDC2_W: + case ByteCodeConstants.NEW: + case ByteCodeConstants.NOP: + case ByteCodeConstants.SIPUSH: + case ByteCodeConstants.RET: + case ByteCodeConstants.RETURN: + case ByteCodeConstants.EXCEPTIONLOAD: + case ByteCodeConstants.RETURNADDRESSLOAD: + break; + default: + System.err.println( + "Can not replace DupLoad in " + + instruction.getClass().getName() + + ", opcode=" + instruction.opcode); + } + } + + public void visit(List instructions) + { + for (int index=instructions.size()-1; index>=0; --index) + { + Instruction i = instructions.get(index); + + if (match(i)) + instructions.set(index, newInstruction(i)); + else + visit(i); + } + } + + private boolean match(Instruction i) + { + return + (i.opcode == this.opcode) && + (((IndexInstruction)i).index == this.index); + } + + private Instruction newInstruction(Instruction i) + { + return new GetStatic( + ByteCodeConstants.OUTERTHIS, i.offset, + i.lineNumber, this.outerThisInstructionIndex); + } +} diff --git a/src/jd/core/process/analyzer/classfile/visitor/ReplaceStringBuxxxerVisitor.java b/src/jd/core/process/analyzer/classfile/visitor/ReplaceStringBuxxxerVisitor.java new file mode 100644 index 00000000..a44ccc8b --- /dev/null +++ b/src/jd/core/process/analyzer/classfile/visitor/ReplaceStringBuxxxerVisitor.java @@ -0,0 +1,603 @@ +package jd.core.process.analyzer.classfile.visitor; + +import java.util.List; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.constant.ConstantClass; +import jd.core.model.classfile.constant.ConstantMethodref; +import jd.core.model.classfile.constant.ConstantNameAndType; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.ANewArray; +import jd.core.model.instruction.bytecode.instruction.AThrow; +import jd.core.model.instruction.bytecode.instruction.ArrayLength; +import jd.core.model.instruction.bytecode.instruction.ArrayLoadInstruction; +import jd.core.model.instruction.bytecode.instruction.ArrayStoreInstruction; +import jd.core.model.instruction.bytecode.instruction.AssertInstruction; +import jd.core.model.instruction.bytecode.instruction.AssignmentInstruction; +import jd.core.model.instruction.bytecode.instruction.BinaryOperatorInstruction; +import jd.core.model.instruction.bytecode.instruction.CheckCast; +import jd.core.model.instruction.bytecode.instruction.ComplexConditionalBranchInstruction; +import jd.core.model.instruction.bytecode.instruction.ConvertInstruction; +import jd.core.model.instruction.bytecode.instruction.DupStore; +import jd.core.model.instruction.bytecode.instruction.GetField; +import jd.core.model.instruction.bytecode.instruction.IfCmp; +import jd.core.model.instruction.bytecode.instruction.IfInstruction; +import jd.core.model.instruction.bytecode.instruction.InitArrayInstruction; +import jd.core.model.instruction.bytecode.instruction.InstanceOf; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.InvokeInstruction; +import jd.core.model.instruction.bytecode.instruction.InvokeNew; +import jd.core.model.instruction.bytecode.instruction.InvokeNoStaticInstruction; +import jd.core.model.instruction.bytecode.instruction.Invokestatic; +import jd.core.model.instruction.bytecode.instruction.Invokevirtual; +import jd.core.model.instruction.bytecode.instruction.LookupSwitch; +import jd.core.model.instruction.bytecode.instruction.MonitorEnter; +import jd.core.model.instruction.bytecode.instruction.MonitorExit; +import jd.core.model.instruction.bytecode.instruction.MultiANewArray; +import jd.core.model.instruction.bytecode.instruction.NewArray; +import jd.core.model.instruction.bytecode.instruction.Pop; +import jd.core.model.instruction.bytecode.instruction.PutField; +import jd.core.model.instruction.bytecode.instruction.PutStatic; +import jd.core.model.instruction.bytecode.instruction.ReturnInstruction; +import jd.core.model.instruction.bytecode.instruction.StoreInstruction; +import jd.core.model.instruction.bytecode.instruction.TableSwitch; +import jd.core.model.instruction.bytecode.instruction.TernaryOpStore; +import jd.core.model.instruction.bytecode.instruction.TernaryOperator; +import jd.core.model.instruction.bytecode.instruction.UnaryOperatorInstruction; +import jd.core.util.StringConstants; + + + +public class ReplaceStringBuxxxerVisitor +{ + private ConstantPool constants; + + public ReplaceStringBuxxxerVisitor(ConstantPool constants) + { + this.constants = constants; + } + + public void visit(Instruction instruction) + { + switch (instruction.opcode) + { + case ByteCodeConstants.ARRAYLENGTH: + { + ArrayLength al = (ArrayLength)instruction; + Instruction i = match(al.arrayref); + if (i == null) + visit(al.arrayref); + else + al.arrayref = i; + } + break; + case ByteCodeConstants.ARRAYLOAD: + { + ArrayLoadInstruction ali = (ArrayLoadInstruction)instruction; + Instruction i = match(ali.arrayref); + if (i == null) + visit(ali.arrayref); + else + ali.arrayref = i; + + i = match(ali.indexref); + if (i == null) + visit(ali.indexref); + else + ali.indexref = i; + } + break; + case ByteCodeConstants.AASTORE: + case ByteCodeConstants.ARRAYSTORE: + { + ArrayStoreInstruction asi = (ArrayStoreInstruction)instruction; + Instruction i = match(asi.arrayref); + if (i == null) + visit(asi.arrayref); + else + asi.arrayref = i; + + i = match(asi.indexref); + if (i == null) + visit(asi.indexref); + else + asi.indexref = i; + + i = match(asi.valueref); + if (i == null) + visit(asi.valueref); + else + asi.valueref = i; + } + break; + case ByteCodeConstants.ASSERT: + { + AssertInstruction ai = (AssertInstruction)instruction; + Instruction i = match(ai.test); + if (i == null) + visit(ai.test); + else + ai.test = i; + if (ai.msg != null) + { + i = match(ai.msg); + if (i == null) + visit(ai.msg); + else + ai.msg = i; + } + } + break; + case ByteCodeConstants.ASSIGNMENT: + { + AssignmentInstruction ai = (AssignmentInstruction)instruction; + Instruction i = match(ai.value1); + if (i == null) + visit(ai.value1); + else + ai.value1 = i; + + i = match(ai.value2); + if (i == null) + visit(ai.value2); + else + ai.value2 = i; + } + break; + case ByteCodeConstants.ATHROW: + { + AThrow aThrow = (AThrow)instruction; + visit(aThrow.value); + } + break; + case ByteCodeConstants.BINARYOP: + { + BinaryOperatorInstruction boi = + (BinaryOperatorInstruction)instruction; + Instruction i = match(boi.value1); + if (i == null) + visit(boi.value1); + else + boi.value1 = i; + + i = match(boi.value2); + if (i == null) + visit(boi.value2); + else + boi.value2 = i; + } + break; + case ByteCodeConstants.UNARYOP: + { + UnaryOperatorInstruction uoi = + (UnaryOperatorInstruction)instruction; + Instruction i = match(uoi.value); + if (i == null) + visit(uoi.value); + else + uoi.value = i; + } + break; + case ByteCodeConstants.DUPSTORE: + { + DupStore dupStore = (DupStore)instruction; + Instruction i = match(dupStore.objectref); + if (i == null) + visit(dupStore.objectref); + else + dupStore.objectref = i; + } + break; + case ByteCodeConstants.CHECKCAST: + { + CheckCast cc = (CheckCast)instruction; + Instruction i = match(cc.objectref); + if (i == null) + visit(cc.objectref); + else + cc.objectref = i; + } + break; + case ByteCodeConstants.CONVERT: + case ByteCodeConstants.IMPLICITCONVERT: + { + ConvertInstruction ci = (ConvertInstruction)instruction; + Instruction i = match(ci.value); + if (i == null) + visit(ci.value); + else + ci.value = i; + } + break; + case ByteCodeConstants.IF: + case ByteCodeConstants.IFXNULL: + { + IfInstruction ifInstruction = (IfInstruction)instruction; + Instruction i = match(ifInstruction.value); + if (i == null) + visit(ifInstruction.value); + else + ifInstruction.value = i; + } + break; + case ByteCodeConstants.IFCMP: + { + IfCmp ifCmpInstruction = (IfCmp)instruction; + Instruction i = match(ifCmpInstruction.value1); + if (i == null) + visit(ifCmpInstruction.value1); + else + ifCmpInstruction.value1 = i; + + i = match(ifCmpInstruction.value2); + if (i == null) + visit(ifCmpInstruction.value2); + else + ifCmpInstruction.value2 = i; + } + break; + case ByteCodeConstants.INSTANCEOF: + { + InstanceOf instanceOf = (InstanceOf)instruction; + Instruction i = match(instanceOf.objectref); + if (i == null) + visit(instanceOf.objectref); + else + instanceOf.objectref = i; + } + break; + case ByteCodeConstants.COMPLEXIF: + { + ComplexConditionalBranchInstruction complexIf = (ComplexConditionalBranchInstruction)instruction; + List branchList = complexIf.instructions; + for (int i=branchList.size()-1; i>=0; --i) + { + visit(branchList.get(i)); + } + } + break; + case ByteCodeConstants.GETFIELD: + { + GetField getField = (GetField)instruction; + Instruction i = match(getField.objectref); + if (i == null) + visit(getField.objectref); + else + getField.objectref = i; + } + break; + case ByteCodeConstants.INVOKEVIRTUAL: + case ByteCodeConstants.INVOKEINTERFACE: + case ByteCodeConstants.INVOKESPECIAL: + { + InvokeNoStaticInstruction insi = + (InvokeNoStaticInstruction)instruction; + Instruction i = match(insi.objectref); + if (i == null) + visit(insi.objectref); + else + insi.objectref = i; + replaceInArgs(insi.args); + } + break; + case ByteCodeConstants.INVOKESTATIC: + case ByteCodeConstants.INVOKENEW: + replaceInArgs(((InvokeInstruction)instruction).args); + break; + case ByteCodeConstants.LOOKUPSWITCH: + { + LookupSwitch lookupSwitch = (LookupSwitch)instruction; + Instruction i = match(lookupSwitch.key); + if (i == null) + visit(lookupSwitch.key); + else + lookupSwitch.key = i; + } + break; + case ByteCodeConstants.MULTIANEWARRAY: + { + MultiANewArray multiANewArray = (MultiANewArray)instruction; + Instruction[] dimensions = multiANewArray.dimensions; + Instruction ins; + + for (int i=dimensions.length-1; i>=0; i--) + { + ins = match(dimensions[i]); + if (ins == null) + visit(dimensions[i]); + else + dimensions[i] = ins; + } + } + break; + case ByteCodeConstants.NEWARRAY: + { + NewArray newArray = (NewArray)instruction; + Instruction i = match(newArray.dimension); + if (i == null) + visit(newArray.dimension); + else + newArray.dimension = i; + } + break; + case ByteCodeConstants.ANEWARRAY: + { + ANewArray newArray = (ANewArray)instruction; + Instruction i = match(newArray.dimension); + if (i == null) + visit(newArray.dimension); + else + newArray.dimension = i; + } + break; + case ByteCodeConstants.POP: + visit(((Pop)instruction).objectref); + break; + case ByteCodeConstants.PUTFIELD: + { + PutField putField = (PutField)instruction; + Instruction i = match(putField.objectref); + if (i == null) + visit(putField.objectref); + else + putField.objectref = i; + + i = match(putField.valueref); + if (i == null) + visit(putField.valueref); + else + putField.valueref = i; + } + break; + case ByteCodeConstants.PUTSTATIC: + { + PutStatic putStatic = (PutStatic)instruction; + Instruction i = match(putStatic.valueref); + if (i == null) + visit(putStatic.valueref); + else + putStatic.valueref = i; + } + break; + case ByteCodeConstants.XRETURN: + { + ReturnInstruction returnInstruction = + (ReturnInstruction)instruction; + Instruction i = match(returnInstruction.valueref); + if (i == null) + visit(returnInstruction.valueref); + else + returnInstruction.valueref = i; + } + break; + case ByteCodeConstants.STORE: + case ByteCodeConstants.ASTORE: + case ByteCodeConstants.ISTORE: + { + StoreInstruction storeInstruction = + (StoreInstruction)instruction; + Instruction i = match(storeInstruction.valueref); + if (i == null) + visit(storeInstruction.valueref); + else + storeInstruction.valueref = i; + } + break; + case ByteCodeConstants.TABLESWITCH: + { + TableSwitch tableSwitch = (TableSwitch)instruction; + Instruction i = match(tableSwitch.key); + if (i == null) + visit(tableSwitch.key); + else + tableSwitch.key = i; + } + break; + case ByteCodeConstants.TERNARYOPSTORE: + { + TernaryOpStore tosInstruction = (TernaryOpStore)instruction; + Instruction i = match(tosInstruction.objectref); + if (i == null) + visit(tosInstruction.objectref); + else + tosInstruction.objectref = i; + } + break; + case ByteCodeConstants.TERNARYOP: + { + TernaryOperator to = (TernaryOperator)instruction; + Instruction i = match(to.value1); + if (i == null) + visit(to.value1); + else + to.value1 = i; + + i = match(to.value2); + if (i == null) + visit(to.value2); + else + to.value2 = i; + } + break; + case ByteCodeConstants.MONITORENTER: + { + MonitorEnter meInstruction = (MonitorEnter)instruction; + Instruction i = match(meInstruction.objectref); + if (i == null) + visit(meInstruction.objectref); + else + meInstruction.objectref = i; + } + break; + case ByteCodeConstants.MONITOREXIT: + { + MonitorExit meInstruction = (MonitorExit)instruction; + Instruction i = match(meInstruction.objectref); + if (i == null) + visit(meInstruction.objectref); + else + meInstruction.objectref = i; + } + break; + case ByteCodeConstants.INITARRAY: + case ByteCodeConstants.NEWANDINITARRAY: + { + InitArrayInstruction iaInstruction = + (InitArrayInstruction)instruction; + Instruction i = match(iaInstruction.newArray); + if (i == null) + visit(iaInstruction.newArray); + else + iaInstruction.newArray = i; + + for (int index=iaInstruction.values.size()-1; index>=0; --index) + { + i = match(iaInstruction.values.get(index)); + if (i == null) + visit(iaInstruction.values.get(index)); + else + iaInstruction.values.set(index, i); + } + } + break; + case ByteCodeConstants.ACONST_NULL: + case ByteCodeConstants.DUPLOAD: + case ByteCodeConstants.LDC: + case ByteCodeConstants.LDC2_W: + case ByteCodeConstants.NEW: + case ByteCodeConstants.RETURN: + case ByteCodeConstants.BIPUSH: + case ByteCodeConstants.DCONST: + case ByteCodeConstants.FCONST: + case ByteCodeConstants.ICONST: + case ByteCodeConstants.LCONST: + case ByteCodeConstants.IINC: + case ByteCodeConstants.PREINC: + case ByteCodeConstants.POSTINC: + case ByteCodeConstants.JSR: + case ByteCodeConstants.GETSTATIC: + case ByteCodeConstants.OUTERTHIS: + case ByteCodeConstants.SIPUSH: + case ByteCodeConstants.LOAD: + case ByteCodeConstants.ALOAD: + case ByteCodeConstants.ILOAD: + case ByteCodeConstants.GOTO: + case ByteCodeConstants.EXCEPTIONLOAD: + case ByteCodeConstants.RET: + case ByteCodeConstants.RETURNADDRESSLOAD: + break; + default: + System.err.println( + "Can not replace StringBuxxxer in " + + instruction.getClass().getName() + " " + + instruction.opcode); + } + } + + + private void replaceInArgs(List args) + { + if (args.size() > 0) + { + Instruction ins; + + for (int i=args.size()-1; i>=0; --i) + { + ins = match(args.get(i)); + if (ins == null) + visit(args.get(i)); + else + args.set(i, ins); + } + } + } + + private Instruction match(Instruction i) + { + if (i.opcode == ByteCodeConstants.INVOKEVIRTUAL) + { + Invokevirtual iv = (Invokevirtual)i; + ConstantMethodref cmr = this.constants.getConstantMethodref(iv.index); + ConstantClass cc = this.constants.getConstantClass(cmr.class_index); + + if ((cc.name_index == constants.stringBufferClassNameIndex) || + (cc.name_index == constants.stringBuilderClassNameIndex)) + { + ConstantNameAndType cnat = + constants.getConstantNameAndType(cmr.name_and_type_index); + + if (cnat.name_index == constants.toStringIndex) + return match(iv.objectref, cmr.class_index); + } + } + + return null; + } + + private Instruction match(Instruction i, int classIndex) + { + if (i.opcode == ByteCodeConstants.INVOKEVIRTUAL) + { + InvokeNoStaticInstruction insi = (InvokeNoStaticInstruction)i; + ConstantMethodref cmr = + this.constants.getConstantMethodref(insi.index); + + if (cmr.class_index == classIndex) + { + ConstantNameAndType cnat = + constants.getConstantNameAndType(cmr.name_and_type_index); + + if ((cnat.name_index == this.constants.appendIndex) && + (insi.args.size() == 1)) + { + Instruction result = match(insi.objectref, cmr.class_index); + + if (result == null) + { + return insi.args.get(0); + } + else + { + return new BinaryOperatorInstruction( + ByteCodeConstants.BINARYOP, i.offset, i.lineNumber, + 4, StringConstants.INTERNAL_STRING_SIGNATURE, "+", + result, insi.args.get(0)); + } + } + } + } + else if (i.opcode == ByteCodeConstants.INVOKENEW) + { + InvokeNew in = (InvokeNew)i; + ConstantMethodref cmr = + this.constants.getConstantMethodref(in.index); + + if ((cmr.class_index == classIndex) && (in.args.size() == 1)) + { + Instruction arg0 = in.args.get(0); + + // Remove String.valueOf for String + if (arg0.opcode == ByteCodeConstants.INVOKESTATIC) + { + Invokestatic is = (Invokestatic)arg0; + cmr = this.constants.getConstantMethodref(is.index); + ConstantClass cc = this.constants.getConstantClass(cmr.class_index); + + if (cc.name_index == this.constants.stringClassNameIndex) + { + ConstantNameAndType cnat = + this.constants.getConstantNameAndType(cmr.name_and_type_index); + + if ((cnat.name_index == this.constants.valueOfIndex) && + (is.args.size() == 1)) + return is.args.get(0); + } + } + + return arg0; + } + } + + return null; + } +} diff --git a/src/jd/core/process/analyzer/classfile/visitor/SearchDupLoadInstructionVisitor.java b/src/jd/core/process/analyzer/classfile/visitor/SearchDupLoadInstructionVisitor.java new file mode 100644 index 00000000..d5e093a1 --- /dev/null +++ b/src/jd/core/process/analyzer/classfile/visitor/SearchDupLoadInstructionVisitor.java @@ -0,0 +1,259 @@ +package jd.core.process.analyzer.classfile.visitor; + +import java.util.List; + +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.ANewArray; +import jd.core.model.instruction.bytecode.instruction.AThrow; +import jd.core.model.instruction.bytecode.instruction.ArrayLength; +import jd.core.model.instruction.bytecode.instruction.ArrayLoadInstruction; +import jd.core.model.instruction.bytecode.instruction.ArrayStoreInstruction; +import jd.core.model.instruction.bytecode.instruction.AssertInstruction; +import jd.core.model.instruction.bytecode.instruction.BinaryOperatorInstruction; +import jd.core.model.instruction.bytecode.instruction.CheckCast; +import jd.core.model.instruction.bytecode.instruction.ComplexConditionalBranchInstruction; +import jd.core.model.instruction.bytecode.instruction.ConvertInstruction; +import jd.core.model.instruction.bytecode.instruction.DupLoad; +import jd.core.model.instruction.bytecode.instruction.DupStore; +import jd.core.model.instruction.bytecode.instruction.GetField; +import jd.core.model.instruction.bytecode.instruction.IfCmp; +import jd.core.model.instruction.bytecode.instruction.IfInstruction; +import jd.core.model.instruction.bytecode.instruction.IncInstruction; +import jd.core.model.instruction.bytecode.instruction.InitArrayInstruction; +import jd.core.model.instruction.bytecode.instruction.InstanceOf; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.InvokeInstruction; +import jd.core.model.instruction.bytecode.instruction.InvokeNoStaticInstruction; +import jd.core.model.instruction.bytecode.instruction.LookupSwitch; +import jd.core.model.instruction.bytecode.instruction.MonitorEnter; +import jd.core.model.instruction.bytecode.instruction.MonitorExit; +import jd.core.model.instruction.bytecode.instruction.MultiANewArray; +import jd.core.model.instruction.bytecode.instruction.NewArray; +import jd.core.model.instruction.bytecode.instruction.Pop; +import jd.core.model.instruction.bytecode.instruction.PutField; +import jd.core.model.instruction.bytecode.instruction.PutStatic; +import jd.core.model.instruction.bytecode.instruction.ReturnInstruction; +import jd.core.model.instruction.bytecode.instruction.StoreInstruction; +import jd.core.model.instruction.bytecode.instruction.TableSwitch; +import jd.core.model.instruction.bytecode.instruction.TernaryOpStore; +import jd.core.model.instruction.bytecode.instruction.UnaryOperatorInstruction; + + +/* + * Utilis� par TernaryOpReconstructor + */ +public class SearchDupLoadInstructionVisitor +{ + public static DupLoad visit(Instruction instruction, DupStore dupStore) + { + switch (instruction.opcode) + { + case ByteCodeConstants.ARRAYLENGTH: + return visit(((ArrayLength)instruction).arrayref, dupStore); + case ByteCodeConstants.ARRAYLOAD: + { + ArrayLoadInstruction ali = (ArrayLoadInstruction)instruction; + DupLoad dupLoad = visit(ali.arrayref, dupStore); + if (dupLoad != null) + return dupLoad; + return visit(ali.indexref, dupStore); + } + case ByteCodeConstants.AASTORE: + case ByteCodeConstants.ARRAYSTORE: + { + ArrayStoreInstruction asi = (ArrayStoreInstruction)instruction; + DupLoad dupLoad = visit(asi.arrayref, dupStore); + if (dupLoad != null) + return dupLoad; + dupLoad = visit(asi.indexref, dupStore); + if (dupLoad != null) + return dupLoad; + return visit(asi.valueref, dupStore); + } + case ByteCodeConstants.ASSERT: + { + AssertInstruction ai = (AssertInstruction)instruction; + DupLoad dupLoad = visit(ai.test, dupStore); + if (dupLoad != null) + return dupLoad; + if (ai.msg == null) + return null; + return visit(ai.msg, dupStore); + } + case ByteCodeConstants.ATHROW: + return visit(((AThrow)instruction).value, dupStore); + case ByteCodeConstants.UNARYOP: + return visit(((UnaryOperatorInstruction)instruction).value, dupStore); + case ByteCodeConstants.BINARYOP: + case ByteCodeConstants.ASSIGNMENT: + { + BinaryOperatorInstruction boi = + (BinaryOperatorInstruction)instruction; + DupLoad dupLoad = visit(boi.value1, dupStore); + if (dupLoad != null) + return dupLoad; + return visit(boi.value2, dupStore); + } + case ByteCodeConstants.CHECKCAST: + return visit(((CheckCast)instruction).objectref, dupStore); + case ByteCodeConstants.STORE: + case ByteCodeConstants.ASTORE: + case ByteCodeConstants.ISTORE: + return visit(((StoreInstruction)instruction).valueref, dupStore); + case ByteCodeConstants.DUPLOAD: + if (((DupLoad)instruction).dupStore == dupStore) + return (DupLoad)instruction; + break; + case ByteCodeConstants.DUPSTORE: + return visit(((DupStore)instruction).objectref, dupStore); + case ByteCodeConstants.CONVERT: + case ByteCodeConstants.IMPLICITCONVERT: + return visit(((ConvertInstruction)instruction).value, dupStore); + case ByteCodeConstants.IFCMP: + { + IfCmp ifCmp = (IfCmp)instruction; + DupLoad dupLoad = visit(ifCmp.value1, dupStore); + if (dupLoad != null) + return dupLoad; + return visit(ifCmp.value2, dupStore); + } + case ByteCodeConstants.IF: + case ByteCodeConstants.IFXNULL: + return visit(((IfInstruction)instruction).value, dupStore); + case ByteCodeConstants.COMPLEXIF: + { + List branchList = + ((ComplexConditionalBranchInstruction)instruction).instructions; + for (int i=branchList.size()-1; i>=0; --i) + { + DupLoad dupLoad = visit(branchList.get(i), dupStore); + if (dupLoad != null) + return dupLoad; + } + } + break; + case ByteCodeConstants.INSTANCEOF: + return visit(((InstanceOf)instruction).objectref, dupStore); + case ByteCodeConstants.INVOKEINTERFACE: + case ByteCodeConstants.INVOKESPECIAL: + case ByteCodeConstants.INVOKEVIRTUAL: + { + DupLoad dupLoad = visit( + ((InvokeNoStaticInstruction)instruction).objectref, dupStore); + if (dupLoad != null) + return dupLoad; + } + case ByteCodeConstants.INVOKESTATIC: + case ByteCodeConstants.INVOKENEW: + { + List list = ((InvokeInstruction)instruction).args; + for (int i=list.size()-1; i>=0; --i) + { + DupLoad dupLoad = visit(list.get(i), dupStore); + if (dupLoad != null) + return dupLoad; + } + } + break; + case ByteCodeConstants.LOOKUPSWITCH: + return visit(((LookupSwitch)instruction).key, dupStore); + case ByteCodeConstants.MONITORENTER: + return visit(((MonitorEnter)instruction).objectref, dupStore); + case ByteCodeConstants.MONITOREXIT: + return visit(((MonitorExit)instruction).objectref, dupStore); + case ByteCodeConstants.MULTIANEWARRAY: + { + Instruction[] dimensions = ((MultiANewArray)instruction).dimensions; + for (int i=dimensions.length-1; i>=0; --i) + { + DupLoad dupLoad = visit(dimensions[i], dupStore); + if (dupLoad != null) + return dupLoad; + } + } + break; + case ByteCodeConstants.NEWARRAY: + return visit(((NewArray)instruction).dimension, dupStore); + case ByteCodeConstants.ANEWARRAY: + return visit(((ANewArray)instruction).dimension, dupStore); + case ByteCodeConstants.POP: + return visit(((Pop)instruction).objectref, dupStore); + case ByteCodeConstants.PUTFIELD: + { + PutField putField = (PutField)instruction; + DupLoad dupLoad = visit(putField.objectref, dupStore); + if (dupLoad != null) + return dupLoad; + return visit(putField.valueref, dupStore); + } + case ByteCodeConstants.PUTSTATIC: + return visit(((PutStatic)instruction).valueref, dupStore); + case ByteCodeConstants.XRETURN: + return visit(((ReturnInstruction)instruction).valueref, dupStore); + case ByteCodeConstants.TABLESWITCH: + return visit(((TableSwitch)instruction).key, dupStore); + case ByteCodeConstants.TERNARYOPSTORE: + return visit(((TernaryOpStore)instruction).objectref, dupStore); + case ByteCodeConstants.PREINC: + case ByteCodeConstants.POSTINC: + return visit(((IncInstruction)instruction).value, dupStore); + case ByteCodeConstants.GETFIELD: + return visit(((GetField)instruction).objectref, dupStore); + case ByteCodeConstants.INITARRAY: + case ByteCodeConstants.NEWANDINITARRAY: + { + InitArrayInstruction iai = (InitArrayInstruction)instruction; + DupLoad dupLoad = visit(iai.newArray, dupStore); + if (dupLoad != null) + return dupLoad; + if (iai.values != null) + return visit(iai.values, dupStore); + } + break; + case ByteCodeConstants.ACONST_NULL: + case ByteCodeConstants.LOAD: + case ByteCodeConstants.ALOAD: + case ByteCodeConstants.ILOAD: + case ByteCodeConstants.BIPUSH: + case ByteCodeConstants.ICONST: + case ByteCodeConstants.LCONST: + case ByteCodeConstants.FCONST: + case ByteCodeConstants.DCONST: + case ByteCodeConstants.GETSTATIC: + case ByteCodeConstants.OUTERTHIS: + case ByteCodeConstants.GOTO: + case ByteCodeConstants.IINC: + case ByteCodeConstants.JSR: + case ByteCodeConstants.LDC: + case ByteCodeConstants.LDC2_W: + case ByteCodeConstants.NEW: + case ByteCodeConstants.NOP: + case ByteCodeConstants.SIPUSH: + case ByteCodeConstants.RET: + case ByteCodeConstants.RETURN: + case ByteCodeConstants.EXCEPTIONLOAD: + case ByteCodeConstants.RETURNADDRESSLOAD: + break; + default: + System.err.println( + "Can not search DupLoad instruction in " + + instruction.getClass().getName() + + ", opcode=" + instruction.opcode); + } + + return null; + } + + private static DupLoad visit( + List instructions, DupStore dupStore) + { + for (int i=instructions.size()-1; i>=0; --i) + { + DupLoad dupLoad = visit(instructions.get(i), dupStore); + if (dupLoad != null) + return dupLoad; + } + + return null; + } +} diff --git a/src/jd/core/process/analyzer/classfile/visitor/SearchInstructionByOffsetVisitor.java b/src/jd/core/process/analyzer/classfile/visitor/SearchInstructionByOffsetVisitor.java new file mode 100644 index 00000000..bd454d17 --- /dev/null +++ b/src/jd/core/process/analyzer/classfile/visitor/SearchInstructionByOffsetVisitor.java @@ -0,0 +1,240 @@ +package jd.core.process.analyzer.classfile.visitor; + +import java.util.List; + +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.ANewArray; +import jd.core.model.instruction.bytecode.instruction.AThrow; +import jd.core.model.instruction.bytecode.instruction.ArrayLength; +import jd.core.model.instruction.bytecode.instruction.ArrayStoreInstruction; +import jd.core.model.instruction.bytecode.instruction.AssertInstruction; +import jd.core.model.instruction.bytecode.instruction.BinaryOperatorInstruction; +import jd.core.model.instruction.bytecode.instruction.CheckCast; +import jd.core.model.instruction.bytecode.instruction.ComplexConditionalBranchInstruction; +import jd.core.model.instruction.bytecode.instruction.ConvertInstruction; +import jd.core.model.instruction.bytecode.instruction.DupStore; +import jd.core.model.instruction.bytecode.instruction.GetField; +import jd.core.model.instruction.bytecode.instruction.IfCmp; +import jd.core.model.instruction.bytecode.instruction.IfInstruction; +import jd.core.model.instruction.bytecode.instruction.IncInstruction; +import jd.core.model.instruction.bytecode.instruction.InitArrayInstruction; +import jd.core.model.instruction.bytecode.instruction.InstanceOf; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.InvokeInstruction; +import jd.core.model.instruction.bytecode.instruction.InvokeNoStaticInstruction; +import jd.core.model.instruction.bytecode.instruction.LookupSwitch; +import jd.core.model.instruction.bytecode.instruction.MonitorEnter; +import jd.core.model.instruction.bytecode.instruction.MonitorExit; +import jd.core.model.instruction.bytecode.instruction.MultiANewArray; +import jd.core.model.instruction.bytecode.instruction.NewArray; +import jd.core.model.instruction.bytecode.instruction.Pop; +import jd.core.model.instruction.bytecode.instruction.PutField; +import jd.core.model.instruction.bytecode.instruction.PutStatic; +import jd.core.model.instruction.bytecode.instruction.ReturnInstruction; +import jd.core.model.instruction.bytecode.instruction.StoreInstruction; +import jd.core.model.instruction.bytecode.instruction.TableSwitch; +import jd.core.model.instruction.bytecode.instruction.TernaryOpStore; +import jd.core.model.instruction.bytecode.instruction.UnaryOperatorInstruction; + + +/* + * Utilis� par TernaryOpReconstructor + */ +public class SearchInstructionByOffsetVisitor +{ + public static Instruction visit(Instruction instruction, int offset) + { + if (instruction.offset == offset) + return instruction; + + switch (instruction.opcode) + { + case ByteCodeConstants.ARRAYLENGTH: + return visit(((ArrayLength)instruction).arrayref, offset); + case ByteCodeConstants.AASTORE: + case ByteCodeConstants.ARRAYSTORE: + return visit(((ArrayStoreInstruction)instruction).arrayref, offset); + case ByteCodeConstants.ASSERT: + { + AssertInstruction ai = (AssertInstruction)instruction; + instruction = visit(ai.test, offset); + if (instruction != null) + return instruction; + if (ai.msg == null) + return null; + return visit(ai.msg, offset); + } + case ByteCodeConstants.ATHROW: + return visit(((AThrow)instruction).value, offset); + case ByteCodeConstants.UNARYOP: + return visit(((UnaryOperatorInstruction)instruction).value, offset); + case ByteCodeConstants.BINARYOP: + case ByteCodeConstants.ASSIGNMENT: + { + BinaryOperatorInstruction boi = + (BinaryOperatorInstruction)instruction; + instruction = visit(boi.value1, offset); + if (instruction != null) + return instruction; + return visit(boi.value2, offset); + } + case ByteCodeConstants.CHECKCAST: + return visit(((CheckCast)instruction).objectref, offset); + case ByteCodeConstants.STORE: + case ByteCodeConstants.ASTORE: + case ByteCodeConstants.ISTORE: + return visit(((StoreInstruction)instruction).valueref, offset); + case ByteCodeConstants.DUPSTORE: + return visit(((DupStore)instruction).objectref, offset); + case ByteCodeConstants.CONVERT: + case ByteCodeConstants.IMPLICITCONVERT: + return visit(((ConvertInstruction)instruction).value, offset); + case ByteCodeConstants.IFCMP: + { + IfCmp ifCmp = (IfCmp)instruction; + instruction = visit(ifCmp.value1, offset); + if (instruction != null) + return instruction; + return visit(ifCmp.value2, offset); + } + case ByteCodeConstants.IF: + case ByteCodeConstants.IFXNULL: + return visit(((IfInstruction)instruction).value, offset); + case ByteCodeConstants.COMPLEXIF: + { + List branchList = + ((ComplexConditionalBranchInstruction)instruction).instructions; + for (int i=branchList.size()-1; i>=0; --i) + { + instruction = visit(branchList.get(i), offset); + if (instruction != null) + return instruction; + } + } + break; + case ByteCodeConstants.INSTANCEOF: + return visit(((InstanceOf)instruction).objectref, offset); + case ByteCodeConstants.INVOKEINTERFACE: + case ByteCodeConstants.INVOKESPECIAL: + case ByteCodeConstants.INVOKEVIRTUAL: + { + Instruction result = visit( + ((InvokeNoStaticInstruction)instruction).objectref, offset); + if (result != null) + return result; + } + case ByteCodeConstants.INVOKESTATIC: + case ByteCodeConstants.INVOKENEW: + { + List list = ((InvokeInstruction)instruction).args; + for (int i=list.size()-1; i>=0; --i) + { + instruction = visit(list.get(i), offset); + if (instruction != null) + return instruction; + } + } + break; + case ByteCodeConstants.LOOKUPSWITCH: + return visit(((LookupSwitch)instruction).key, offset); + case ByteCodeConstants.MONITORENTER: + return visit(((MonitorEnter)instruction).objectref, offset); + case ByteCodeConstants.MONITOREXIT: + return visit(((MonitorExit)instruction).objectref, offset); + case ByteCodeConstants.MULTIANEWARRAY: + { + Instruction[] dimensions = ((MultiANewArray)instruction).dimensions; + for (int i=dimensions.length-1; i>=0; --i) + { + instruction = visit(dimensions[i], offset); + if (instruction != null) + return instruction; + } + } + break; + case ByteCodeConstants.NEWARRAY: + return visit(((NewArray)instruction).dimension, offset); + case ByteCodeConstants.ANEWARRAY: + return visit(((ANewArray)instruction).dimension, offset); + case ByteCodeConstants.POP: + return visit(((Pop)instruction).objectref, offset); + case ByteCodeConstants.PUTFIELD: + { + PutField putField = (PutField)instruction; + instruction = visit(putField.objectref, offset); + if (instruction != null) + return instruction; + return visit(putField.valueref, offset); + } + case ByteCodeConstants.PUTSTATIC: + return visit(((PutStatic)instruction).valueref, offset); + case ByteCodeConstants.XRETURN: + return visit(((ReturnInstruction)instruction).valueref, offset); + case ByteCodeConstants.TABLESWITCH: + return visit(((TableSwitch)instruction).key, offset); + case ByteCodeConstants.TERNARYOPSTORE: + return visit(((TernaryOpStore)instruction).objectref, offset); + case ByteCodeConstants.PREINC: + case ByteCodeConstants.POSTINC: + return visit(((IncInstruction)instruction).value, offset); + case ByteCodeConstants.GETFIELD: + return visit(((GetField)instruction).objectref, offset); + case ByteCodeConstants.INITARRAY: + case ByteCodeConstants.NEWANDINITARRAY: + { + InitArrayInstruction iai = (InitArrayInstruction)instruction; + instruction = visit(iai.newArray, offset); + if (instruction != null) + return instruction; + if (iai.values != null) + return visit(iai.values, offset); + } + break; + case ByteCodeConstants.ACONST_NULL: + case ByteCodeConstants.ARRAYLOAD: + case ByteCodeConstants.LOAD: + case ByteCodeConstants.ALOAD: + case ByteCodeConstants.ILOAD: + case ByteCodeConstants.BIPUSH: + case ByteCodeConstants.ICONST: + case ByteCodeConstants.LCONST: + case ByteCodeConstants.FCONST: + case ByteCodeConstants.DCONST: + case ByteCodeConstants.DUPLOAD: + case ByteCodeConstants.GETSTATIC: + case ByteCodeConstants.OUTERTHIS: + case ByteCodeConstants.GOTO: + case ByteCodeConstants.IINC: + case ByteCodeConstants.JSR: + case ByteCodeConstants.LDC: + case ByteCodeConstants.LDC2_W: + case ByteCodeConstants.NEW: + case ByteCodeConstants.NOP: + case ByteCodeConstants.SIPUSH: + case ByteCodeConstants.RET: + case ByteCodeConstants.RETURN: + case ByteCodeConstants.EXCEPTIONLOAD: + case ByteCodeConstants.RETURNADDRESSLOAD: + break; + default: + System.err.println( + "Can not search instruction in " + + instruction.getClass().getName() + + ", opcode=" + instruction.opcode); + } + + return null; + } + + private static Instruction visit(List instructions, int offset) + { + for (int i=instructions.size()-1; i>=0; --i) + { + Instruction instruction = visit(instructions.get(i), offset); + if (instruction != null) + return instruction; + } + + return null; + } +} diff --git a/src/jd/core/process/analyzer/classfile/visitor/SearchInstructionByOpcodeVisitor.java b/src/jd/core/process/analyzer/classfile/visitor/SearchInstructionByOpcodeVisitor.java new file mode 100644 index 00000000..2ca56e7c --- /dev/null +++ b/src/jd/core/process/analyzer/classfile/visitor/SearchInstructionByOpcodeVisitor.java @@ -0,0 +1,388 @@ +package jd.core.process.analyzer.classfile.visitor; + +import java.util.List; + +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.ANewArray; +import jd.core.model.instruction.bytecode.instruction.AThrow; +import jd.core.model.instruction.bytecode.instruction.ArrayLength; +import jd.core.model.instruction.bytecode.instruction.ArrayStoreInstruction; +import jd.core.model.instruction.bytecode.instruction.BinaryOperatorInstruction; +import jd.core.model.instruction.bytecode.instruction.CheckCast; +import jd.core.model.instruction.bytecode.instruction.ComplexConditionalBranchInstruction; +import jd.core.model.instruction.bytecode.instruction.ConvertInstruction; +import jd.core.model.instruction.bytecode.instruction.DupStore; +import jd.core.model.instruction.bytecode.instruction.GetField; +import jd.core.model.instruction.bytecode.instruction.IfCmp; +import jd.core.model.instruction.bytecode.instruction.IfInstruction; +import jd.core.model.instruction.bytecode.instruction.IncInstruction; +import jd.core.model.instruction.bytecode.instruction.InitArrayInstruction; +import jd.core.model.instruction.bytecode.instruction.InstanceOf; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.InvokeInstruction; +import jd.core.model.instruction.bytecode.instruction.InvokeNoStaticInstruction; +import jd.core.model.instruction.bytecode.instruction.LookupSwitch; +import jd.core.model.instruction.bytecode.instruction.MonitorEnter; +import jd.core.model.instruction.bytecode.instruction.MonitorExit; +import jd.core.model.instruction.bytecode.instruction.MultiANewArray; +import jd.core.model.instruction.bytecode.instruction.NewArray; +import jd.core.model.instruction.bytecode.instruction.Pop; +import jd.core.model.instruction.bytecode.instruction.PutField; +import jd.core.model.instruction.bytecode.instruction.PutStatic; +import jd.core.model.instruction.bytecode.instruction.ReturnInstruction; +import jd.core.model.instruction.bytecode.instruction.StoreInstruction; +import jd.core.model.instruction.bytecode.instruction.TableSwitch; +import jd.core.model.instruction.bytecode.instruction.TernaryOpStore; +import jd.core.model.instruction.bytecode.instruction.TernaryOperator; +import jd.core.model.instruction.bytecode.instruction.UnaryOperatorInstruction; +import jd.core.model.instruction.fast.FastConstants; +import jd.core.model.instruction.fast.instruction.FastDeclaration; +import jd.core.model.instruction.fast.instruction.FastFor; +import jd.core.model.instruction.fast.instruction.FastForEach; +import jd.core.model.instruction.fast.instruction.FastInstruction; +import jd.core.model.instruction.fast.instruction.FastLabel; +import jd.core.model.instruction.fast.instruction.FastList; +import jd.core.model.instruction.fast.instruction.FastSwitch; +import jd.core.model.instruction.fast.instruction.FastSynchronized; +import jd.core.model.instruction.fast.instruction.FastTest2Lists; +import jd.core.model.instruction.fast.instruction.FastTestList; +import jd.core.model.instruction.fast.instruction.FastTry; +import jd.core.model.instruction.fast.instruction.FastSwitch.Pair; +import jd.core.model.instruction.fast.instruction.FastTry.FastCatch; + + +/* + * Utilis� par TernaryOpReconstructor + */ +public class SearchInstructionByOpcodeVisitor +{ + public static Instruction visit(Instruction instruction, int opcode) + throws RuntimeException + { + if (instruction == null) + throw new RuntimeException("Null instruction"); + + if (instruction.opcode == opcode) + return instruction; + + switch (instruction.opcode) + { + case ByteCodeConstants.ARRAYLENGTH: + return visit(((ArrayLength)instruction).arrayref, opcode); + case ByteCodeConstants.AASTORE: + case ByteCodeConstants.ARRAYSTORE: + return visit(((ArrayStoreInstruction)instruction).arrayref, opcode); + case ByteCodeConstants.ATHROW: + return visit(((AThrow)instruction).value, opcode); + case ByteCodeConstants.UNARYOP: + return visit(((UnaryOperatorInstruction)instruction).value, opcode); + case ByteCodeConstants.BINARYOP: + case ByteCodeConstants.ASSIGNMENT: + { + BinaryOperatorInstruction boi = + (BinaryOperatorInstruction)instruction; + Instruction tmp = visit(boi.value1, opcode); + if (tmp != null) + return tmp; + return visit(boi.value2, opcode); + } + case ByteCodeConstants.CHECKCAST: + return visit(((CheckCast)instruction).objectref, opcode); + case ByteCodeConstants.STORE: + case ByteCodeConstants.ASTORE: + case ByteCodeConstants.ISTORE: + return visit(((StoreInstruction)instruction).valueref, opcode); + case ByteCodeConstants.DUPSTORE: + return visit(((DupStore)instruction).objectref, opcode); + case ByteCodeConstants.CONVERT: + case ByteCodeConstants.IMPLICITCONVERT: + return visit(((ConvertInstruction)instruction).value, opcode); + case ByteCodeConstants.IFCMP: + { + IfCmp ifCmp = (IfCmp)instruction; + Instruction tmp = visit(ifCmp.value1, opcode); + if (tmp != null) + return tmp; + return visit(ifCmp.value2, opcode); + } + case ByteCodeConstants.IF: + case ByteCodeConstants.IFXNULL: + return visit(((IfInstruction)instruction).value, opcode); + case ByteCodeConstants.COMPLEXIF: + { + List branchList = + ((ComplexConditionalBranchInstruction)instruction).instructions; + for (int i=branchList.size()-1; i>=0; --i) + { + Instruction tmp = visit(branchList.get(i), opcode); + if (tmp != null) + return tmp; + } + } + break; + case ByteCodeConstants.INSTANCEOF: + return visit(((InstanceOf)instruction).objectref, opcode); + case ByteCodeConstants.INVOKEINTERFACE: + case ByteCodeConstants.INVOKESPECIAL: + case ByteCodeConstants.INVOKEVIRTUAL: + { + Instruction result = visit( + ((InvokeNoStaticInstruction)instruction).objectref, opcode); + if (result != null) + return result; + } + case ByteCodeConstants.INVOKESTATIC: + case ByteCodeConstants.INVOKENEW: + { + List list = ((InvokeInstruction)instruction).args; + for (int i=list.size()-1; i>=0; --i) + { + Instruction tmp = visit(list.get(i), opcode); + if (tmp != null) + return tmp; + } + } + break; + case ByteCodeConstants.LOOKUPSWITCH: + return visit(((LookupSwitch)instruction).key, opcode); + case ByteCodeConstants.MONITORENTER: + return visit(((MonitorEnter)instruction).objectref, opcode); + case ByteCodeConstants.MONITOREXIT: + return visit(((MonitorExit)instruction).objectref, opcode); + case ByteCodeConstants.MULTIANEWARRAY: + { + Instruction[] dimensions = ((MultiANewArray)instruction).dimensions; + for (int i=dimensions.length-1; i>=0; --i) + { + Instruction tmp = visit(dimensions[i], opcode); + if (tmp != null) + return tmp; + } + } + break; + case ByteCodeConstants.NEWARRAY: + return visit(((NewArray)instruction).dimension, opcode); + case ByteCodeConstants.ANEWARRAY: + return visit(((ANewArray)instruction).dimension, opcode); + case ByteCodeConstants.POP: + return visit(((Pop)instruction).objectref, opcode); + case ByteCodeConstants.PUTFIELD: + { + PutField putField = (PutField)instruction; + Instruction tmp = visit(putField.objectref, opcode); + if (tmp != null) + return tmp; + return visit(putField.valueref, opcode); + } + case ByteCodeConstants.PUTSTATIC: + return visit(((PutStatic)instruction).valueref, opcode); + case ByteCodeConstants.XRETURN: + return visit(((ReturnInstruction)instruction).valueref, opcode); + case ByteCodeConstants.TABLESWITCH: + return visit(((TableSwitch)instruction).key, opcode); + case ByteCodeConstants.TERNARYOPSTORE: + return visit(((TernaryOpStore)instruction).objectref, opcode); + case ByteCodeConstants.PREINC: + case ByteCodeConstants.POSTINC: + return visit(((IncInstruction)instruction).value, opcode); + case ByteCodeConstants.GETFIELD: + return visit(((GetField)instruction).objectref, opcode); + case ByteCodeConstants.INITARRAY: + case ByteCodeConstants.NEWANDINITARRAY: + { + InitArrayInstruction iai = (InitArrayInstruction)instruction; + Instruction tmp = visit(iai.newArray, opcode); + if (tmp != null) + return tmp; + if (iai.values != null) + return visit(iai.values, opcode); + } + break; + case ByteCodeConstants.TERNARYOP: + { + TernaryOperator to = (TernaryOperator)instruction; + Instruction tmp = visit(to.value1, opcode); + if (tmp != null) + return tmp; + return visit(to.value2, opcode); + } + case FastConstants.TRY: + { + FastTry ft = (FastTry)instruction; + Instruction tmp = visit(ft.instructions, opcode); + if (tmp != null) + return tmp; + List catches = ft.catches; + for (int i=catches.size()-1; i>=0; --i) + { + tmp = visit(catches.get(i).instructions, opcode); + if (tmp != null) + return tmp; + } + if (ft.finallyInstructions != null) + return visit(ft.finallyInstructions, opcode); + } + break; + case FastConstants.SYNCHRONIZED: + { + FastSynchronized fsy = (FastSynchronized)instruction; + Instruction tmp = visit(fsy.monitor, opcode); + if (tmp != null) + return tmp; + return visit(fsy.instructions, opcode); + } + case FastConstants.FOR: + { + FastFor ff = (FastFor)instruction; + if (ff.init != null) + { + Instruction tmp = visit(ff.init, opcode); + if (tmp != null) + return tmp; + } + if (ff.inc != null) + { + Instruction tmp = visit(ff.inc, opcode); + if (tmp != null) + return tmp; + } + } + case FastConstants.WHILE: + case FastConstants.DO_WHILE: + case FastConstants.IF_: + { + FastTestList ftl = (FastTestList)instruction; + if (ftl.test != null) + { + Instruction tmp = visit(ftl.test, opcode); + if (tmp != null) + return tmp; + } + } + case FastConstants.INFINITE_LOOP: + { + List instructions = + ((FastList)instruction).instructions; + if (instructions != null) + return visit(instructions, opcode); + } + break; + case FastConstants.FOREACH: + { + FastForEach ffe = (FastForEach)instruction; + Instruction tmp = visit(ffe.variable, opcode); + if (tmp != null) + return tmp; + tmp = visit(ffe.values, opcode); + if (tmp != null) + return tmp; + return visit(ffe.instructions, opcode); + } + case FastConstants.IF_ELSE: + { + FastTest2Lists ft2l = (FastTest2Lists)instruction; + Instruction tmp = visit(ft2l.test, opcode); + if (tmp != null) + return tmp; + tmp = visit(ft2l.instructions, opcode); + if (tmp != null) + return tmp; + return visit(ft2l.instructions2, opcode); + } + case FastConstants.IF_CONTINUE: + case FastConstants.IF_BREAK: + case FastConstants.IF_LABELED_BREAK: + case FastConstants.GOTO_CONTINUE: + case FastConstants.GOTO_BREAK: + case FastConstants.GOTO_LABELED_BREAK: + { + FastInstruction fi = (FastInstruction)instruction; + if (fi.instruction != null) + return visit(fi.instruction, opcode); + } + break; + case FastConstants.DECLARE: + { + FastDeclaration fd = (FastDeclaration)instruction; + if (fd.instruction != null) + return visit(fd.instruction, opcode); + } + break; + case FastConstants.SWITCH: + case FastConstants.SWITCH_ENUM: + case FastConstants.SWITCH_STRING: + { + FastSwitch fs = (FastSwitch)instruction; + Instruction tmp = visit(fs.test, opcode); + if (tmp != null) + return tmp; + + Pair[] pairs = fs.pairs; + for (int i=pairs.length-1; i>=0; --i) + { + List instructions = pairs[i].getInstructions(); + if (instructions != null) + { + tmp = visit(instructions, opcode); + if (tmp != null) + return tmp; + } + } + } + break; + case FastConstants.LABEL: + { + FastLabel fla = (FastLabel)instruction; + if (fla.instruction != null) + return visit(fla.instruction, opcode); + } + break; + case ByteCodeConstants.ACONST_NULL: + case ByteCodeConstants.ARRAYLOAD: + case ByteCodeConstants.LOAD: + case ByteCodeConstants.ALOAD: + case ByteCodeConstants.ILOAD: + case ByteCodeConstants.BIPUSH: + case ByteCodeConstants.ICONST: + case ByteCodeConstants.LCONST: + case ByteCodeConstants.FCONST: + case ByteCodeConstants.DCONST: + case ByteCodeConstants.DUPLOAD: + case ByteCodeConstants.EXCEPTIONLOAD: + case ByteCodeConstants.GETSTATIC: + case ByteCodeConstants.OUTERTHIS: + case ByteCodeConstants.GOTO: + case ByteCodeConstants.IINC: + case ByteCodeConstants.JSR: + case ByteCodeConstants.LDC: + case ByteCodeConstants.LDC2_W: + case ByteCodeConstants.NEW: + case ByteCodeConstants.NOP: + case ByteCodeConstants.RET: + case ByteCodeConstants.RETURN: + case ByteCodeConstants.RETURNADDRESSLOAD: + case ByteCodeConstants.SIPUSH: + break; + default: + System.err.println( + "Can not search instruction in " + + instruction.getClass().getName() + + ", opcode=" + instruction.opcode); + } + + return null; + } + + private static Instruction visit(List instructions, int opcode) + throws RuntimeException + { + for (int i=instructions.size()-1; i>=0; --i) + { + Instruction instruction = visit(instructions.get(i), opcode); + if (instruction != null) + return instruction; + } + + return null; + } +} diff --git a/src/jd/core/process/analyzer/classfile/visitor/SetConstantTypeInStringIndexOfMethodsVisitor.java b/src/jd/core/process/analyzer/classfile/visitor/SetConstantTypeInStringIndexOfMethodsVisitor.java new file mode 100644 index 00000000..b16bab46 --- /dev/null +++ b/src/jd/core/process/analyzer/classfile/visitor/SetConstantTypeInStringIndexOfMethodsVisitor.java @@ -0,0 +1,280 @@ +package jd.core.process.analyzer.classfile.visitor; + +import java.util.List; + +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.constant.ConstantClass; +import jd.core.model.classfile.constant.ConstantMethodref; +import jd.core.model.classfile.constant.ConstantNameAndType; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.ANewArray; +import jd.core.model.instruction.bytecode.instruction.AThrow; +import jd.core.model.instruction.bytecode.instruction.ArrayLength; +import jd.core.model.instruction.bytecode.instruction.ArrayStoreInstruction; +import jd.core.model.instruction.bytecode.instruction.AssertInstruction; +import jd.core.model.instruction.bytecode.instruction.BinaryOperatorInstruction; +import jd.core.model.instruction.bytecode.instruction.CheckCast; +import jd.core.model.instruction.bytecode.instruction.ComplexConditionalBranchInstruction; +import jd.core.model.instruction.bytecode.instruction.ConvertInstruction; +import jd.core.model.instruction.bytecode.instruction.DupStore; +import jd.core.model.instruction.bytecode.instruction.GetField; +import jd.core.model.instruction.bytecode.instruction.IConst; +import jd.core.model.instruction.bytecode.instruction.IfCmp; +import jd.core.model.instruction.bytecode.instruction.IfInstruction; +import jd.core.model.instruction.bytecode.instruction.IncInstruction; +import jd.core.model.instruction.bytecode.instruction.InitArrayInstruction; +import jd.core.model.instruction.bytecode.instruction.InstanceOf; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.InvokeInstruction; +import jd.core.model.instruction.bytecode.instruction.InvokeNoStaticInstruction; +import jd.core.model.instruction.bytecode.instruction.Invokevirtual; +import jd.core.model.instruction.bytecode.instruction.LookupSwitch; +import jd.core.model.instruction.bytecode.instruction.MonitorEnter; +import jd.core.model.instruction.bytecode.instruction.MonitorExit; +import jd.core.model.instruction.bytecode.instruction.MultiANewArray; +import jd.core.model.instruction.bytecode.instruction.NewArray; +import jd.core.model.instruction.bytecode.instruction.Pop; +import jd.core.model.instruction.bytecode.instruction.PutField; +import jd.core.model.instruction.bytecode.instruction.PutStatic; +import jd.core.model.instruction.bytecode.instruction.ReturnInstruction; +import jd.core.model.instruction.bytecode.instruction.StoreInstruction; +import jd.core.model.instruction.bytecode.instruction.TableSwitch; +import jd.core.model.instruction.bytecode.instruction.TernaryOpStore; +import jd.core.model.instruction.bytecode.instruction.UnaryOperatorInstruction; + +/* + * Search : + public int indexOf(int ch) + public int indexOf(int ch, int fromIndex) + public int lastIndexOf(int ch) + public int lastIndexOf(int ch, int fromIndex) + */ +public class SetConstantTypeInStringIndexOfMethodsVisitor +{ + protected ConstantPool constants; + + public SetConstantTypeInStringIndexOfMethodsVisitor(ConstantPool constants) + { + this.constants = constants; + } + + public void visit(Instruction instruction) + { + switch (instruction.opcode) + { + case ByteCodeConstants.ARRAYLENGTH: + visit(((ArrayLength)instruction).arrayref); + break; + case ByteCodeConstants.AASTORE: + case ByteCodeConstants.ARRAYSTORE: + visit(((ArrayStoreInstruction)instruction).arrayref); + break; + case ByteCodeConstants.ASSERT: + { + AssertInstruction ai = (AssertInstruction)instruction; + visit(ai.test); + if (ai.msg != null) + visit(ai.msg); + } + break; + case ByteCodeConstants.ATHROW: + visit(((AThrow)instruction).value); + break; + case ByteCodeConstants.UNARYOP: + visit(((UnaryOperatorInstruction)instruction).value); + break; + case ByteCodeConstants.BINARYOP: + case ByteCodeConstants.ASSIGNMENT: + { + BinaryOperatorInstruction boi = + (BinaryOperatorInstruction)instruction; + visit(boi.value1); + visit(boi.value2); + } + break; + case ByteCodeConstants.CHECKCAST: + visit(((CheckCast)instruction).objectref); + break; + case ByteCodeConstants.STORE: + case ByteCodeConstants.ASTORE: + case ByteCodeConstants.ISTORE: + visit(((StoreInstruction)instruction).valueref); + break; + case ByteCodeConstants.DUPSTORE: + visit(((DupStore)instruction).objectref); + break; + case ByteCodeConstants.CONVERT: + case ByteCodeConstants.IMPLICITCONVERT: + visit(((ConvertInstruction)instruction).value); + break; + case ByteCodeConstants.IFCMP: + { + IfCmp ifCmp = (IfCmp)instruction; + visit(ifCmp.value1); + visit(ifCmp.value2); + } + break; + case ByteCodeConstants.IF: + case ByteCodeConstants.IFXNULL: + visit(((IfInstruction)instruction).value); + break; + case ByteCodeConstants.COMPLEXIF: + { + List branchList = + ((ComplexConditionalBranchInstruction)instruction).instructions; + for (int i=branchList.size()-1; i>=0; --i) + visit(branchList.get(i)); + } + break; + case ByteCodeConstants.INSTANCEOF: + visit(((InstanceOf)instruction).objectref); + break; + case ByteCodeConstants.INVOKEVIRTUAL: + { + Invokevirtual iv = (Invokevirtual)instruction; + ConstantMethodref cmr = + this.constants.getConstantMethodref(iv.index); + ConstantClass cc = this.constants.getConstantClass(cmr.class_index); + + if (cc.name_index == this.constants.stringClassNameIndex) + { + int nbrOfParameters = iv.args.size(); + + if ((1 <= nbrOfParameters) && (nbrOfParameters <= 2)) + { + int opcode = iv.args.get(0).opcode; + + if (((opcode==ByteCodeConstants.BIPUSH) || + (opcode==ByteCodeConstants.SIPUSH)) && + cmr.getReturnedSignature().equals("I") && + cmr.getListOfParameterSignatures().get(0).equals("I")) + { + ConstantNameAndType cnat = + this.constants.getConstantNameAndType( + cmr.name_and_type_index); + String name = + this.constants.getConstantUtf8(cnat.name_index); + + if ("indexOf".equals(name) || + "lastIndexOf".equals(name)) + { + // Change constant type + IConst ic = (IConst)iv.args.get(0); + ic.setReturnedSignature("C"); + break; + } + } + } + } + } + case ByteCodeConstants.INVOKEINTERFACE: + case ByteCodeConstants.INVOKESPECIAL: + visit(((InvokeNoStaticInstruction)instruction).objectref); + case ByteCodeConstants.INVOKESTATIC: + case ByteCodeConstants.INVOKENEW: + { + List list = ((InvokeInstruction)instruction).args; + for (int i=list.size()-1; i>=0; --i) + visit(list.get(i)); + } + break; + case ByteCodeConstants.LOOKUPSWITCH: + visit(((LookupSwitch)instruction).key); + break; + case ByteCodeConstants.MONITORENTER: + visit(((MonitorEnter)instruction).objectref); + break; + case ByteCodeConstants.MONITOREXIT: + visit(((MonitorExit)instruction).objectref); + break; + case ByteCodeConstants.MULTIANEWARRAY: + { + Instruction[] dimensions = ((MultiANewArray)instruction).dimensions; + for (int i=dimensions.length-1; i>=0; --i) + visit(dimensions[i]); + } + break; + case ByteCodeConstants.NEWARRAY: + visit(((NewArray)instruction).dimension); + break; + case ByteCodeConstants.ANEWARRAY: + visit(((ANewArray)instruction).dimension); + break; + case ByteCodeConstants.POP: + visit(((Pop)instruction).objectref); + break; + case ByteCodeConstants.PUTFIELD: + { + PutField putField = (PutField)instruction; + visit(putField.objectref); + visit(putField.valueref); + } + break; + case ByteCodeConstants.PUTSTATIC: + visit(((PutStatic)instruction).valueref); + break; + case ByteCodeConstants.XRETURN: + visit(((ReturnInstruction)instruction).valueref); + break; + case ByteCodeConstants.TABLESWITCH: + visit(((TableSwitch)instruction).key); + break; + case ByteCodeConstants.TERNARYOPSTORE: + visit(((TernaryOpStore)instruction).objectref); + break; + case ByteCodeConstants.PREINC: + case ByteCodeConstants.POSTINC: + visit(((IncInstruction)instruction).value); + break; + case ByteCodeConstants.GETFIELD: + visit(((GetField)instruction).objectref); + break; + case ByteCodeConstants.INITARRAY: + case ByteCodeConstants.NEWANDINITARRAY: + { + InitArrayInstruction iai = (InitArrayInstruction)instruction; + visit(iai.newArray); + if (iai.values != null) + visit(iai.values); + } + break; + case ByteCodeConstants.ACONST_NULL: + case ByteCodeConstants.ARRAYLOAD: + case ByteCodeConstants.LOAD: + case ByteCodeConstants.ALOAD: + case ByteCodeConstants.ILOAD: + case ByteCodeConstants.BIPUSH: + case ByteCodeConstants.ICONST: + case ByteCodeConstants.LCONST: + case ByteCodeConstants.FCONST: + case ByteCodeConstants.DCONST: + case ByteCodeConstants.DUPLOAD: + case ByteCodeConstants.GETSTATIC: + case ByteCodeConstants.OUTERTHIS: + case ByteCodeConstants.GOTO: + case ByteCodeConstants.IINC: + case ByteCodeConstants.JSR: + case ByteCodeConstants.LDC: + case ByteCodeConstants.LDC2_W: + case ByteCodeConstants.NEW: + case ByteCodeConstants.NOP: + case ByteCodeConstants.SIPUSH: + case ByteCodeConstants.RET: + case ByteCodeConstants.RETURN: + case ByteCodeConstants.EXCEPTIONLOAD: + case ByteCodeConstants.RETURNADDRESSLOAD: + break; + default: + System.err.println( + "Can not search String.indexOf in " + + instruction.getClass().getName() + + ", opcode=" + instruction.opcode); + } + } + + public void visit(List instructions) + { + for (int i=instructions.size()-1; i>=0; --i) + visit(instructions.get(i)); + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/ComparisonInstructionAnalyzer.java b/src/jd/core/process/analyzer/instruction/bytecode/ComparisonInstructionAnalyzer.java new file mode 100644 index 00000000..c5e2cdf9 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/ComparisonInstructionAnalyzer.java @@ -0,0 +1,837 @@ +package jd.core.process.analyzer.instruction.bytecode; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.BranchInstruction; +import jd.core.model.instruction.bytecode.instruction.ComplexConditionalBranchInstruction; +import jd.core.model.instruction.bytecode.instruction.ConditionalBranchInstruction; +import jd.core.model.instruction.bytecode.instruction.Goto; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.TernaryOperator; + + +/** + * Aggrege les instructions 'if' + */ +public class ComparisonInstructionAnalyzer +{ + /* + * debut de liste fin de liste + * | | + * Liste ... --|----|---|==0===1===2===3===4===5===6==7=...=n---|--| ... + */ + public static void Aggregate(List list) + { + int afterOffest = -1; + int index = list.size(); + + while (index-- > 0) + { + Instruction instruction = list.get(index); + + switch (instruction.opcode) + { + case ByteCodeConstants.IF: + case ByteCodeConstants.IFCMP: + case ByteCodeConstants.IFXNULL: + if (index > 0) + { + Instruction prevI = list.get(index-1); + + switch (prevI.opcode) + { + case ByteCodeConstants.IF: + case ByteCodeConstants.IFCMP: + case ByteCodeConstants.IFXNULL: + case ByteCodeConstants.GOTO: + { + BranchInstruction bi = (BranchInstruction)instruction; + BranchInstruction prevBi = (BranchInstruction)prevI; + + int prevBiJumpOffset = prevBi.GetJumpOffset(); + + // Le 2eme if appartient-il au meme bloc que le 1er ? + if ((prevBiJumpOffset == bi.GetJumpOffset()) || + ((prevBi.branch > 0) && (prevBiJumpOffset <= afterOffest))) + { + // Oui + // Test complexe : plusieurs instructions byte-code de test + index = AnalyzeIfInstructions( + list, index, bi, afterOffest); + } + } + break; + } + } + } + + afterOffest = instruction.offset; + } + } + + /* + * debut de liste fin de liste + * | index | + * | | | + * Liste ... --|----|---|==0===1===2===3===4===5===6==7=...=n---|--| ... + * if if ? + * | | | + * Offsets | | afterLastBiOffset + * Instruction (if) prevLast last (if) + */ + private static int AnalyzeIfInstructions( + List list, int index, + BranchInstruction lastBi, int afterOffest) + { + int arrayLength = list.get(list.size()-1).offset; + boolean[] offsetToPreviousGotoFlag = new boolean[arrayLength]; + boolean[] inversedTernaryOpLogic = new boolean[arrayLength]; + + // Recherche de l'indexe de la premiere instruction 'if' du bloc et + // initialisation de 'offsetToPreviousGotoFlag' + int firstIndex = SearchFirstIndex( + list, index, lastBi, afterOffest, + offsetToPreviousGotoFlag, inversedTernaryOpLogic); + + firstIndex = ReduceFirstIndex(list, firstIndex, index); + + if (firstIndex < index) + { + // Extraction des instructions de test formant un bloc + List branchInstructions = + new ArrayList(index - firstIndex + 1); + + branchInstructions.add(lastBi); + while (index > firstIndex) + branchInstructions.add(list.remove(--index)); + + Collections.reverse(branchInstructions); + list.set(index, CreateIfInstructions( + offsetToPreviousGotoFlag, inversedTernaryOpLogic, + branchInstructions, lastBi)); + } + + return index; + } + + private static int ReduceFirstIndex( + List list, int firstIndex, int lastIndex) + { + int firstOffset = (firstIndex == 0) ? 0 : list.get(firstIndex-1).offset; + int newFirstOffset = firstOffset; + int lastOffset = list.get(lastIndex).offset; + + // Reduce 'firstIndex' with previous instructions + int index = firstIndex; + while (index-- > 0) + { + Instruction i = list.get(index); + + switch (i.opcode) + { + case ByteCodeConstants.IF: + case ByteCodeConstants.IFCMP: + case ByteCodeConstants.IFXNULL: + case ByteCodeConstants.GOTO: + int jumpOffset = ((BranchInstruction)i).GetJumpOffset(); + if ((newFirstOffset < jumpOffset) && (jumpOffset <= lastOffset)) + newFirstOffset = jumpOffset; + } + } + + // Reduce 'firstIndex' with next instructions + index = list.size(); + while (--index > lastIndex) + { + Instruction i = list.get(index); + + switch (i.opcode) + { + case ByteCodeConstants.IF: + case ByteCodeConstants.IFCMP: + case ByteCodeConstants.IFXNULL: + case ByteCodeConstants.GOTO: + int jumpOffset = ((BranchInstruction)i).GetJumpOffset(); + if ((newFirstOffset < jumpOffset) && (jumpOffset <= lastOffset)) + newFirstOffset = jumpOffset; + } + } + + // Search index associated with 'firstOffset' + if (newFirstOffset != firstOffset) + { + for (index=firstIndex; index<=lastIndex; index++) + { + Instruction i = list.get(index); + if (i.offset > newFirstOffset) + { + firstIndex = index; + break; + } + } + } + + return firstIndex; + } + + private static int SearchFirstIndex( + List list, int lastIndex, + BranchInstruction lastBi, int afterOffest, + boolean[] offsetToPreviousGotoFlag, + boolean[] inversedTernaryOpLogic) + { + int index = lastIndex; + int lastBiJumpOffset = lastBi.GetJumpOffset(); + + Instruction nextInstruction = lastBi; + + while (index-- > 0) + { + Instruction instruction = list.get(index); + int opcode = instruction.opcode; + + if ((opcode == ByteCodeConstants.IF) || + (opcode == ByteCodeConstants.IFCMP) || + (opcode == ByteCodeConstants.IFXNULL)) + { + BranchInstruction bi = (BranchInstruction)instruction; + int jumpOffset = bi.GetJumpOffset(); + + // L'instruction if courante appartient-elle au meme bloc que le 1er ? + if (jumpOffset == lastBiJumpOffset) + { + if ((bi.branch > 0) && + (instruction.lineNumber != Instruction.UNKNOWN_LINE_NUMBER) && + (nextInstruction.lineNumber != Instruction.UNKNOWN_LINE_NUMBER)) + { + if (instruction.lineNumber+2 <= nextInstruction.lineNumber) + { + // Amelioration par rapport a JAD : possibilite de + // construire deux instructions 'if' pourtant compatibles + break; // Non + } + else + { + // Est-ce que l'une des instructions suivantes a un + // numero de ligne <= a instruction.lineNumber et < + // a nextInstruction.lineNumber + int lenght = list.size(); + boolean instructionBetweenIf = false; + + // ATTENTION: Fragment de code ralentissement grandement la decompilation + for (int i=lastIndex+1; i afterOffest))) + { + break; // Non + } + } + else if (opcode == ByteCodeConstants.GOTO) + { + Goto g = (Goto)instruction; + int jumpOffset = g.GetJumpOffset(); + + // Ce 'goto' appartient-il au meme bloc que le 1er 'if' ? + if ((jumpOffset != lastBiJumpOffset) && + ((jumpOffset <= nextInstruction.offset) || + (jumpOffset > afterOffest))) + break; // Non + + // Recherche de l'offset de l'instruction avant le 'goto' + if (index <= 0) + break; // Non + + Instruction lastInstructionValue1 = list.get(index-1); + opcode = lastInstructionValue1.opcode; + + if ((opcode != ByteCodeConstants.IF) && + (opcode != ByteCodeConstants.IFCMP) && + (opcode != ByteCodeConstants.IFXNULL)) + break; // Non + + int jumpOffsetValue1 = + ((BranchInstruction)lastInstructionValue1).GetJumpOffset(); + + if ((g.offset < jumpOffsetValue1) && + (jumpOffsetValue1 <= lastBi.offset)) + break; // Non + + // offset de l'instruction avant le saut du goto + Instruction lastInstructionValue2 = list.get(lastIndex); + + for (int jumpIndex=lastIndex-1; jumpIndex>index; jumpIndex--) + { + Instruction jumpInstruction = list.get(jumpIndex); + if (jumpOffset > jumpInstruction.offset) + { + lastInstructionValue2 = jumpInstruction; + break; + } + } + + opcode = lastInstructionValue2.opcode; + + if ((opcode != ByteCodeConstants.IF) && + (opcode != ByteCodeConstants.IFCMP) && + (opcode != ByteCodeConstants.IFXNULL)) + break; // Non + + int jumpOffsetValue2 = + ((BranchInstruction)lastInstructionValue2).GetJumpOffset(); + + if (jumpOffsetValue1 == jumpOffsetValue2) + { + // Oui ! S�quence dans le bon sens + int nextOffset = nextInstruction.offset; + for (int j=g.offset+1; j il FAUT inverser le 1er test + int nextOffset = nextInstruction.offset; + for (int j=g.offset+1; j branchInstructions, + BranchInstruction lastBi) + { + // Reconstruction des operateurs ternaires + // -> Elimination des instructions 'Goto' + ReconstructTernaryOperators( + offsetToPreviousGotoFlag, inversedTernaryOpLogic, + branchInstructions, lastBi); + + // Creation de l'instruction ComplexBranchList + ComplexConditionalBranchInstruction cbl = + AssembleAndCreateIfInstructions(branchInstructions, lastBi); + + // Affectation des comparaisons & des operateurs + SetOperator(cbl, lastBi, false); + + return cbl; + } + + private static void ReconstructTernaryOperators( + boolean[] offsetToPreviousGotoFlag, + boolean[] inversedTernaryOpLogic, + List branchInstructions, + BranchInstruction lastBi) + { + if (branchInstructions.size() <= 1) + return; + + // Recherche des instructions 'if' sautant vers des instructions 'goto' + // en commencant par la derniere instruction + int index = branchInstructions.size()-1; + int nextOffest = branchInstructions.get(index).offset; + + while (index-- > 0) + { + Instruction i = branchInstructions.get(index); + + switch (i.opcode) + { + case ByteCodeConstants.IF: + case ByteCodeConstants.IFCMP: + case ByteCodeConstants.IFXNULL: + BranchInstruction lastTernaryOpTestBi = (BranchInstruction)i; + int lastTernaryOpTestBiJumpOffset = + lastTernaryOpTestBi.GetJumpOffset(); + + if ((lastTernaryOpTestBiJumpOffset < 0) || + (lastBi.offset < lastTernaryOpTestBiJumpOffset) || + !offsetToPreviousGotoFlag[lastTernaryOpTestBiJumpOffset]) + break; + + // Extraction de la sous liste d'instructions constituant + // le test de l'operateur ternaire + ArrayList ternaryOpTestInstructions = + new ArrayList(); + ternaryOpTestInstructions.add(lastTernaryOpTestBi); + + while (index > 0) + { + Instruction ternaryOpTestInstruction = + branchInstructions.get(--index); + + int opcode = ternaryOpTestInstruction.opcode; + + if ((opcode != ByteCodeConstants.IF) && + (opcode != ByteCodeConstants.IFCMP) && + (opcode != ByteCodeConstants.IFXNULL) && + (opcode != ByteCodeConstants.GOTO)) + { + index++; + break; + } + + BranchInstruction bi = + (BranchInstruction)ternaryOpTestInstruction; + int branchOffset = bi.branch; + int jumpOffset = bi.offset + branchOffset; + + // L'instruction if courante appartient-elle au meme bloc que le 1er ? + if ((jumpOffset != lastTernaryOpTestBiJumpOffset) && + ((branchOffset <= 0) || (jumpOffset > nextOffest))) + { + // Non + index++; + break; + } + + branchInstructions.remove(index); + ternaryOpTestInstructions.add(ternaryOpTestInstruction); + } + + Instruction test; + + if (ternaryOpTestInstructions.size() > 1) + { + Collections.reverse(ternaryOpTestInstructions); + test = CreateIfInstructions( + offsetToPreviousGotoFlag, inversedTernaryOpLogic, + ternaryOpTestInstructions, lastTernaryOpTestBi); + } + else + { + test = lastTernaryOpTestBi; + } + InverseComparison(test); + + // Extraction de la sous liste d'instructions constituant + // la premiere valeur de l'operateur ternaire (instructions + // entre le test et l'instruction 'goto') + ArrayList ternaryOpValue1Instructions = + new ArrayList(); + + index++; + + while (index < branchInstructions.size()) + { + Instruction instruction = + branchInstructions.get(index); + + if (instruction.offset >= lastTernaryOpTestBiJumpOffset) + break; + + ternaryOpValue1Instructions.add(instruction); + branchInstructions.remove(index); + } + + // Remove last 'goto' instruction + Goto g = (Goto)ternaryOpValue1Instructions.remove( + ternaryOpValue1Instructions.size()-1); + + BranchInstruction value1; + + if (ternaryOpValue1Instructions.size() > 1) + { + BranchInstruction lastTernaryOpValueBi = + (BranchInstruction)ternaryOpValue1Instructions.get( + ternaryOpValue1Instructions.size()-1); + // Creation de l'instruction ComplexBranchList + value1 = AssembleAndCreateIfInstructions( + ternaryOpValue1Instructions, lastTernaryOpValueBi); + } + else + { + value1 = (BranchInstruction)ternaryOpValue1Instructions.get( + ternaryOpValue1Instructions.size()-1); + } + + int gotoJumpOffset; + + if (inversedTernaryOpLogic[g.offset]) + { + gotoJumpOffset = value1.GetJumpOffset(); + InverseComparison(value1); + } + else + { + gotoJumpOffset = g.GetJumpOffset(); + } + + // Extraction de la sous liste d'instructions constituant + // la seconde valeur de l'operateur ternaire (instructions entre + // l'instruction 'goto' et la prochaine instruction 'goto' ou + // jusqu'au saut du test) + ArrayList ternaryOpValue2Instructions = + new ArrayList(); + + while (index < branchInstructions.size()) + { + Instruction instruction = + branchInstructions.get(index); + + if ((instruction.opcode == ByteCodeConstants.GOTO) || + (instruction.offset >= gotoJumpOffset)) + break; + + ternaryOpValue2Instructions.add(instruction); + branchInstructions.remove(index); + } + + BranchInstruction value2; + + if (ternaryOpValue2Instructions.size() > 1) + { + BranchInstruction lastTernaryOpValueBi = + (BranchInstruction)ternaryOpValue2Instructions.get( + ternaryOpValue2Instructions.size()-1); + // Creation de l'instruction ComplexBranchList + value2 = AssembleAndCreateIfInstructions( + ternaryOpValue2Instructions, lastTernaryOpValueBi); + } + else + { + value2 = (BranchInstruction)ternaryOpValue2Instructions.get( + ternaryOpValue2Instructions.size()-1); + } + + index--; + + // Create ternary operator + TernaryOperator to = new TernaryOperator( + ByteCodeConstants.TERNARYOP, value2.offset, + test.lineNumber, test, value1, value2); + + ArrayList instructions = + new ArrayList(1); + instructions.add(to); + + // Create complex if instruction + ComplexConditionalBranchInstruction cbl = new ComplexConditionalBranchInstruction( + ByteCodeConstants.COMPLEXIF, value2.offset, test.lineNumber, + ByteCodeConstants.CMP_NONE, instructions, + value2.branch); + + branchInstructions.set(index, cbl); + + break; + } + + nextOffest = i.offset; + } + } + + private static ComplexConditionalBranchInstruction AssembleAndCreateIfInstructions( + List branchInstructions, + BranchInstruction lastBi) + { + int length = branchInstructions.size(); + int lastBiOffset = lastBi.offset; + + // Search sub test block + for (int i=0; i 0) && (jumpOffset < lastBiOffset)) + { + // Inner jump + BranchInstruction subLastBi = lastBi; + ArrayList subBranchInstructions = + new ArrayList(); + + // Extract sub list + subBranchInstructions.add(branchInstruction); + i++; + + while (i < length) + { + branchInstruction = + (BranchInstruction)branchInstructions.get(i); + + if (branchInstruction.offset >= jumpOffset) + break; + + subBranchInstructions.add(branchInstruction); + subLastBi = branchInstruction; + branchInstructions.remove(i); + --length; + } + + --i; + + if (subBranchInstructions.size() > 1) + { + // Recursive call + branchInstructions.set(i, + AssembleAndCreateIfInstructions( + subBranchInstructions, subLastBi)); + } + } + } + + // + AnalyzeLastTestBlock(branchInstructions); + + // First branch instruction line number + int lineNumber = branchInstructions.get(0).lineNumber; + + return new ComplexConditionalBranchInstruction( + ByteCodeConstants.COMPLEXIF, lastBi.offset, lineNumber, + ByteCodeConstants.CMP_NONE, branchInstructions, lastBi.branch); + } + + private static void AnalyzeLastTestBlock( + List branchInstructions) + { + int length = branchInstructions.size(); + + if (length > 1) + { + length--; + BranchInstruction branchInstruction = + (BranchInstruction)branchInstructions.get(0); + int firstJumpOffset = branchInstruction.GetJumpOffset(); + + // Search sub list + for (int i=1; i subJumpInstructions = + new ArrayList(length); + + // Extract sub list + subJumpInstructions.add(branchInstruction); + i++; + + while (i <= length) + { + subLastBi = (BranchInstruction)branchInstructions.remove(i); + subJumpInstructions.add(subLastBi); + length--; + } + + // Recursive call + AnalyzeLastTestBlock(subJumpInstructions); + + // First branch instruction line number + int lineNumber = branchInstructions.get(0).lineNumber; + + branchInstructions.set( + --i, new ComplexConditionalBranchInstruction( + ByteCodeConstants.COMPLEXIF, subLastBi.offset, + lineNumber, ByteCodeConstants.CMP_NONE, + subJumpInstructions, subLastBi.branch)); + } + } + } + } + + private static void SetOperator( + ComplexConditionalBranchInstruction cbl, + BranchInstruction lastBi, boolean inverse) + { + List instructions = cbl.instructions; + int lastIndex = instructions.size()-1; + BranchInstruction firstBi = (BranchInstruction)instructions.get(0); + + if (firstBi.GetJumpOffset() == lastBi.GetJumpOffset()) + { + cbl.cmp = inverse ? + ByteCodeConstants.CMP_AND : ByteCodeConstants.CMP_OR; + + for (int i=0; i<=lastIndex; ++i) + SetOperator(instructions.get(i), inverse); + } + else + { + cbl.cmp = inverse ? + ByteCodeConstants.CMP_OR : ByteCodeConstants.CMP_AND; + + // Inverse all comparaisons except last one + boolean tmpInverse = !inverse; + int i = 0; + + while (i < lastIndex) + SetOperator(instructions.get(i++), tmpInverse); + + SetOperator(instructions.get(i), inverse); + } + } + + private static void SetOperator(Instruction instruction, boolean inverse) + { + switch (instruction.opcode) + { + case ByteCodeConstants.TERNARYOP: + { + TernaryOperator to = (TernaryOperator)instruction; + SetOperator(to.value1, inverse); + SetOperator(to.value2, inverse); + } + break; + case ByteCodeConstants.COMPLEXIF: + { + ComplexConditionalBranchInstruction cbl = (ComplexConditionalBranchInstruction)instruction; + int length = cbl.instructions.size(); + + if (length == 1) + { + SetOperator(cbl.instructions.get(0), inverse); + } + else if (length > 1) + { + SetOperator( + cbl, + (BranchInstruction)cbl.instructions.get(length-1), + inverse); + } + } + break; + default: + { + if (inverse) + { + ConditionalBranchInstruction cbi = + (ConditionalBranchInstruction)instruction; + cbi.cmp = ByteCodeConstants.CMP_MAX_INDEX - cbi.cmp; + } + } + break; + } + } + + public static void InverseComparison(Instruction instruction) + { + switch (instruction.opcode) + { + case ByteCodeConstants.IF: + case ByteCodeConstants.IFCMP: + case ByteCodeConstants.IFXNULL: + ConditionalBranchInstruction cbi = + (ConditionalBranchInstruction)instruction; + cbi.cmp = ByteCodeConstants.CMP_MAX_INDEX - cbi.cmp; + break; + case ByteCodeConstants.COMPLEXIF: + ComplexConditionalBranchInstruction ccbi = + (ComplexConditionalBranchInstruction)instruction; + ccbi.cmp = ByteCodeConstants.CMP_OR - ccbi.cmp; + for (int i=ccbi.instructions.size()-1; i>=0; --i) + InverseComparison(ccbi.instructions.get(i)); + break; + case ByteCodeConstants.TERNARYOP: + TernaryOperator to = (TernaryOperator)instruction; + InverseComparison(to.value1); + InverseComparison(to.value2); + break; +// default: +// System.out.println("debug"); + } + } + + public static int GetLastIndex(List list, int firstIndex) + { + int lenght = list.size(); + int index = firstIndex+1; + + // Recherche de la potentielle derniere instruction de saut + while (index < lenght) + { + Instruction instruction = list.get(index); + int opcode = instruction.opcode; + + if ((opcode == ByteCodeConstants.IF) || + (opcode == ByteCodeConstants.IFCMP) || + (opcode == ByteCodeConstants.IFXNULL) || + (opcode == ByteCodeConstants.GOTO)) + { + index++; + } + else + { + break; + } + } + + if (index-1 == firstIndex) + return firstIndex; + + boolean[] dummy = new boolean[list.get(lenght-1).offset]; + + while (--index > firstIndex) + { + // Verification que la potentielle derniere instruction de saut a + // comme premiere instruction l'instruction � l'indexe 'firstIndex' + // Recherche de l'indexe de la premiere instruction 'if' du bloc et + // initialisation de 'offsetToPreviousGotoFlag' + BranchInstruction lastBi = (BranchInstruction)list.get(index); + int afterOffest = (index+1 < lenght) ? list.get(index+1).offset : -1; + + int firstIndexTmp = SearchFirstIndex( + list, index, lastBi, afterOffest, dummy, dummy); + + firstIndexTmp = ReduceFirstIndex(list, firstIndexTmp, index); + + if (firstIndex == firstIndexTmp) + { + // Trouv� + break; + } + } + + return index; + } +} \ No newline at end of file diff --git a/src/jd/core/process/analyzer/instruction/bytecode/InstructionListBuilder.java b/src/jd/core/process/analyzer/instruction/bytecode/InstructionListBuilder.java new file mode 100644 index 00000000..eb793cd3 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/InstructionListBuilder.java @@ -0,0 +1,365 @@ +package jd.core.process.analyzer.instruction.bytecode; + +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.Method; +import jd.core.model.classfile.attribute.CodeException; +import jd.core.model.classfile.attribute.LineNumber; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.ExceptionLoad; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.ReturnAddressLoad; +import jd.core.process.analyzer.instruction.bytecode.factory.InstructionFactory; +import jd.core.process.analyzer.instruction.bytecode.factory.InstructionFactoryConstants; +import jd.core.process.analyzer.instruction.bytecode.util.ByteCodeUtil; +import jd.core.util.IntSet; +import jd.core.util.SignatureUtil; + + +public class InstructionListBuilder +{ + private static CodeExceptionComparator COMPARATOR = + new CodeExceptionComparator(); + + public static void Build( + ClassFile classFile, Method method, + List list, + List listForAnalyze) + throws Exception + { + byte[] code = method.getCode(); + + if (code != null) + { + int offset = 0; + + try + { + final int length = code.length; + + // Declaration du tableau de sauts utile pour reconstruire les + // instructions de pre et post incrementation : si une + // instruction 'iinc' est une instruction vers laquelle on + // saute, elle ne sera pas agreg�e a l'instruction precedante + // ou suivante. + boolean[] jumps = new boolean[length]; + + // Declaration du tableau des sauts vers les sous procedures + // (jsr ... ret). A chaque d�but de sous procedures, une pseudo + // adresse de retour doit etre inseree sur la pile. + IntSet offsetSet = new IntSet(); + + // Population des deux tableaux dans la meme passe. + PopulateJumpsArrayAndSubProcOffsets(code, length, jumps, offsetSet); + + // Initialisation de variables additionnelles pour le traitement + // des sous procedures. + int[] subProcOffsets = offsetSet.toArray(); + int subProcOffsetsIndex = 0; + int subProcOffset = + (subProcOffsets == null) ? -1 : subProcOffsets[0]; + + // Declaration de variables additionnelles pour le traitement + // des blocs 'catch' et 'finally'. + final Stack stack = new Stack(); + final CodeException[] codeExceptions = method.getCodeExceptions(); + int codeExceptionsIndex = 0; + int exceptionOffset; + ConstantPool constants = classFile.getConstantPool(); + + if (codeExceptions == null) + { + exceptionOffset = -1; + } + else + { + // Sort codeExceptions by handler_pc + Arrays.sort(codeExceptions, COMPARATOR); + exceptionOffset = codeExceptions[0].handler_pc; + } + + // Declaration de variables additionnelles pour le traitement + // des numeros de ligne + LineNumber[] lineNumbers = method.getLineNumbers(); + int lineNumbersIndex = 0; + int lineNumber; + int nextLineOffset; + + if (lineNumbers == null) + { + lineNumber = Instruction.UNKNOWN_LINE_NUMBER; + nextLineOffset = -1; + } + else + { + LineNumber ln = lineNumbers[lineNumbersIndex]; + lineNumber = ln.line_number; + nextLineOffset = -1; + + int startPc = ln.start_pc; + while (++lineNumbersIndex < lineNumbers.length) + { + ln = lineNumbers[lineNumbersIndex]; + if (ln.start_pc != startPc) + { + nextLineOffset = ln.start_pc; + break; + } + lineNumber = ln.line_number; + } + } + + // Boucle principale : agregation des instructions + for (offset=0; offset= codeExceptions.length) + { + nextOffsetException = -1; + break; + } + + nextOffsetException = + codeExceptions[codeExceptionsIndex].handler_pc; + + if (nextOffsetException != exceptionOffset) + break; + } + exceptionOffset = nextOffsetException; + } + + // Ajout de ReturnAddressLoad + if (offset == subProcOffset) + { + // Ajout d'une pseudo adresse de retour en debut de + // sous procedure. Lors de l'execution, cette + // adresse est normalement plac�e sur la pile par + // l'instruction JSR. + stack.push(new ReturnAddressLoad( + ByteCodeConstants.RETURNADDRESSLOAD, + offset, lineNumber)); + + if (++subProcOffsetsIndex >= subProcOffsets.length) + subProcOffset = -1; + else + subProcOffset = subProcOffsets[subProcOffsetsIndex]; + } + + // Traitement des numeros de ligne + if (offset == nextLineOffset) + { + LineNumber ln = lineNumbers[lineNumbersIndex]; + lineNumber = ln.line_number; + nextLineOffset = -1; + + int startPc = ln.start_pc; + while (++lineNumbersIndex < lineNumbers.length) + { + ln = lineNumbers[lineNumbersIndex]; + if (ln.start_pc != startPc) + { + nextLineOffset = ln.start_pc; + break; + } + lineNumber = ln.line_number; + } + } + + // Generation d'instruction + offset += factory.create( + classFile, method, list, listForAnalyze, stack, + code, offset, lineNumber, jumps); + } + else + { + String msg = "No factory for " + + ByteCodeConstants.OPCODE_NAMES[opcode]; + System.err.println(msg); + throw new Exception(msg); + } + } + + if (! stack.isEmpty()) + { + final String className = classFile.getClassName(); + final String methodName = + classFile.getConstantPool().getConstantUtf8(method.name_index); + System.err.println( + "'" + className + '.' + methodName + + "' build error: stack not empty. stack=" + stack); + } + } + catch (Exception e) + { + // Bad byte code ... generate, for example, by Eclipse Java + // Compiler or Harmony: + // Byte code: + // 0: aload_0 + // 1: invokevirtual 16 TryCatchFinallyClassForTest:before ()V + // 4: iconst_1 + // 5: ireturn + // 6: astore_1 <----- Error: EmptyStackException + // 7: aload_0 + // 8: invokevirtual 19 TryCatchFinallyClassForTest:inCatch1 ()V + // 11: aload_0 + // 12: invokevirtual 22 TryCatchFinallyClassForTest:after ()V + // 15: iconst_2 + // 16: ireturn + throw new InstructionListException(classFile, method, offset, e); + } + } + } + + private static void PopulateJumpsArrayAndSubProcOffsets( + byte[] code, int length, boolean[] jumps, IntSet offsetSet) + { + for (int offset=0; offset + { + public int compare(CodeException ce1, CodeException ce2) + { + if (ce1.handler_pc != ce2.handler_pc) + return ce1.handler_pc - ce2.handler_pc; + + if (ce1.end_pc != ce2.end_pc) + return ce1.end_pc - ce2.end_pc; + + if (ce1.start_pc != ce2.start_pc) + return ce1.start_pc - ce2.start_pc; + + return ce1.index - ce2.index; + } + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/InstructionListException.java b/src/jd/core/process/analyzer/instruction/bytecode/InstructionListException.java new file mode 100644 index 00000000..fbee8d19 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/InstructionListException.java @@ -0,0 +1,37 @@ +package jd.core.process.analyzer.instruction.bytecode; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.Method; + + +public class InstructionListException extends RuntimeException +{ + private static final long serialVersionUID = -2987531947933382754L; + + public InstructionListException( + ClassFile classFile, Method method, int offset, Throwable cause) + { + super(FormatMessage(classFile, method, offset), cause); + } + + private static String FormatMessage( + ClassFile classFile, Method method, int offset) + { + ConstantPool constants = classFile.getConstantPool(); + + String name = constants.getConstantUtf8(method.name_index); + String descriptor = constants.getConstantUtf8(method.descriptor_index); + + StringBuffer sb = new StringBuffer(); + + sb.append("method='"); + sb.append(name); + sb.append("', descriptor='"); + sb.append(descriptor); + sb.append("', offset="); + sb.append(offset); + + return sb.toString(); + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/AALoadFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/AALoadFactory.java new file mode 100644 index 00000000..59087bc4 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/AALoadFactory.java @@ -0,0 +1,36 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.AALoad; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class AALoadFactory extends InstructionFactory +{ + public AALoadFactory() + { + } + + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + final Instruction index = stack.pop(); + final Instruction arrayref = stack.pop(); + final Instruction instruction = new AALoad( + ByteCodeConstants.ARRAYLOAD, offset, lineNumber, arrayref, index); + + stack.push(instruction); + listForAnalyze.add(instruction); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/AAStoreFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/AAStoreFactory.java new file mode 100644 index 00000000..651516d8 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/AAStoreFactory.java @@ -0,0 +1,33 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.AAStore; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class AAStoreFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + final Instruction valueref = stack.pop(); + final Instruction index = stack.pop(); + final Instruction arrayref = stack.pop(); + final Instruction instruction = + new AAStore(opcode, offset, lineNumber, arrayref, index, valueref); + + list.add(instruction); + listForAnalyze.add(instruction); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/AConstNullFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/AConstNullFactory.java new file mode 100644 index 00000000..52b4434b --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/AConstNullFactory.java @@ -0,0 +1,27 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.AConstNull; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class AConstNullFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + + stack.push(new AConstNull(opcode, offset, lineNumber)); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/ALoadFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/ALoadFactory.java new file mode 100644 index 00000000..c8cc3543 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/ALoadFactory.java @@ -0,0 +1,38 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.ALoad; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class ALoadFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + + int index; + + if (opcode == ByteCodeConstants.ALOAD) + index = code[offset+1] & 255; + else + index = opcode - ByteCodeConstants.ALOAD_0; + + final Instruction instruction = + new ALoad(ByteCodeConstants.ALOAD, offset, lineNumber, index); + + stack.push(instruction); + listForAnalyze.add(instruction); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/ANewArrayFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/ANewArrayFactory.java new file mode 100644 index 00000000..4069c884 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/ANewArrayFactory.java @@ -0,0 +1,32 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.ANewArray; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class ANewArrayFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + final int index = + ((code[offset+1] & 255) << 8) | (code[offset+2] & 255); + final Instruction instruction = + new ANewArray(opcode, offset, lineNumber, index, stack.pop()); + + stack.push(instruction); + listForAnalyze.add(instruction); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/AStoreFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/AStoreFactory.java new file mode 100644 index 00000000..a19139df --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/AStoreFactory.java @@ -0,0 +1,37 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.AStore; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class AStoreFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + int index; + + if (opcode == ByteCodeConstants.ASTORE) + index = code[offset+1] & 255; + else + index = (code[offset] & 255) - ByteCodeConstants.ASTORE_0; + + final Instruction instruction = new AStore( + ByteCodeConstants.ASTORE, offset, lineNumber, index, stack.pop()); + + list.add(instruction); + listForAnalyze.add(instruction); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/AThrowFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/AThrowFactory.java new file mode 100644 index 00000000..f13323f8 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/AThrowFactory.java @@ -0,0 +1,27 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.AThrow; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class AThrowFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + + list.add(new AThrow(opcode, offset, lineNumber, stack.pop())); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/ArrayLengthFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/ArrayLengthFactory.java new file mode 100644 index 00000000..1c14907f --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/ArrayLengthFactory.java @@ -0,0 +1,27 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.ArrayLength; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class ArrayLengthFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + + stack.push(new ArrayLength(opcode, offset, lineNumber, stack.pop())); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/ArrayLoadInstructionFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/ArrayLoadInstructionFactory.java new file mode 100644 index 00000000..a93990c2 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/ArrayLoadInstructionFactory.java @@ -0,0 +1,40 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.ArrayLoadInstruction; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class ArrayLoadInstructionFactory extends InstructionFactory +{ + private String signature; + + public ArrayLoadInstructionFactory(String signature) + { + this.signature = signature; + } + + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + final Instruction index = stack.pop(); + final Instruction arrayref = stack.pop(); + final Instruction instruction = new ArrayLoadInstruction( + ByteCodeConstants.ARRAYLOAD, offset, lineNumber, arrayref, + index, this.signature); + + stack.push(instruction); + listForAnalyze.add(instruction); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/ArrayStoreInstructionFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/ArrayStoreInstructionFactory.java new file mode 100644 index 00000000..9e42f323 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/ArrayStoreInstructionFactory.java @@ -0,0 +1,41 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.ArrayStoreInstruction; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class ArrayStoreInstructionFactory extends InstructionFactory +{ + private String signature; + + public ArrayStoreInstructionFactory(String signature) + { + this.signature = signature; + } + + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + final Instruction valueref = stack.pop(); + final Instruction index = stack.pop(); + final Instruction arrayref = stack.pop(); + final Instruction instruction = new ArrayStoreInstruction( + ByteCodeConstants.ARRAYSTORE, offset, lineNumber, arrayref, + index, this.signature, valueref); + + list.add(instruction); + listForAnalyze.add(instruction); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/BIPushFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/BIPushFactory.java new file mode 100644 index 00000000..20b015f7 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/BIPushFactory.java @@ -0,0 +1,28 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.BIPush; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class BIPushFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + + stack.push(new BIPush( + opcode, offset, lineNumber, (byte)(code[offset+1] & 255))); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/BinaryOperatorFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/BinaryOperatorFactory.java new file mode 100644 index 00000000..80174185 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/BinaryOperatorFactory.java @@ -0,0 +1,46 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.BinaryOperatorInstruction; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class BinaryOperatorFactory extends InstructionFactory +{ + protected int priority; + protected String signature; + protected String operator; + + public BinaryOperatorFactory( + int priority, String signature, String operator) + { + this.priority = priority; + this.signature = signature; + this.operator = operator; + } + + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + final Instruction i2 = stack.pop(); + final Instruction i1 = stack.pop(); + + final Instruction instruction = new BinaryOperatorInstruction( + ByteCodeConstants.BINARYOP, offset, lineNumber, this.priority, + this.signature, this.operator, i1, i2); + + stack.push(instruction); + listForAnalyze.add(instruction); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/CheckCastFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/CheckCastFactory.java new file mode 100644 index 00000000..aae003dd --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/CheckCastFactory.java @@ -0,0 +1,29 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.CheckCast; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class CheckCastFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + final int index = ((code[offset+1] & 255) << 8) | (code[offset+2] & 255); + + stack.push(new CheckCast( + opcode, offset, lineNumber, index, stack.pop())); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/CmpFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/CmpFactory.java new file mode 100644 index 00000000..e490560c --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/CmpFactory.java @@ -0,0 +1,39 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.BinaryOperatorInstruction; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class CmpFactory extends BinaryOperatorFactory +{ + public CmpFactory( + int priority, String signature, String operator) + { + super(priority, signature, operator); + } + + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + final Instruction i2 = stack.pop(); + final Instruction i1 = stack.pop(); + final Instruction newInstruction = new BinaryOperatorInstruction( + ByteCodeConstants.BINARYOP, offset, lineNumber, this.priority, + this.signature, this.operator, i1, i2); + + stack.push(newInstruction); + listForAnalyze.add(newInstruction); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/ConvertInstructionFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/ConvertInstructionFactory.java new file mode 100644 index 00000000..7ef1512d --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/ConvertInstructionFactory.java @@ -0,0 +1,36 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.ConvertInstruction; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class ConvertInstructionFactory extends InstructionFactory +{ + private String signature; + + public ConvertInstructionFactory(String signature) + { + this.signature = signature; + } + + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + + stack.push(new ConvertInstruction( + ByteCodeConstants.CONVERT, offset, lineNumber, + stack.pop(), this.signature)); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/DConstFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/DConstFactory.java new file mode 100644 index 00000000..73cb70b3 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/DConstFactory.java @@ -0,0 +1,29 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.DConst; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class DConstFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + final int index = opcode - ByteCodeConstants.DCONST_0; + + stack.push(new DConst( + ByteCodeConstants.DCONST, offset, lineNumber, index)); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/DLoadFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/DLoadFactory.java new file mode 100644 index 00000000..1d79c8a6 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/DLoadFactory.java @@ -0,0 +1,37 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.LoadInstruction; + + +public class DLoadFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + int index; + + if (opcode == ByteCodeConstants.DLOAD) + index = code[offset+1] & 255; + else + index = opcode - ByteCodeConstants.DLOAD_0; + + final Instruction instruction = new LoadInstruction( + ByteCodeConstants.LOAD, offset, lineNumber, index, "D"); + + stack.push(instruction); + listForAnalyze.add(instruction); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/DStoreFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/DStoreFactory.java new file mode 100644 index 00000000..e0699df7 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/DStoreFactory.java @@ -0,0 +1,38 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.StoreInstruction; + + +public class DStoreFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + int index; + + if (opcode == ByteCodeConstants.DSTORE) + index = code[offset+1] & 255; + else + index = opcode - ByteCodeConstants.DSTORE_0; + + final Instruction instruction = new StoreInstruction( + ByteCodeConstants.STORE, offset, lineNumber, + index, "D", stack.pop()); + + list.add(instruction); + listForAnalyze.add(instruction); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/DummyFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/DummyFactory.java new file mode 100644 index 00000000..7282a324 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/DummyFactory.java @@ -0,0 +1,22 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class DummyFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + return ByteCodeConstants.NO_OF_OPERANDS[code[offset] & 255]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/Dup2Factory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/Dup2Factory.java new file mode 100644 index 00000000..26a6173f --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/Dup2Factory.java @@ -0,0 +1,57 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.DupStore; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class Dup2Factory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + Instruction i1 = stack.pop(); + + String signature1 = i1.getReturnedSignature( + classFile.getConstantPool(), method.getLocalVariables()); + + if ("J".equals(signature1) || "D".equals(signature1)) + { + // ..., value => ..., value, value + DupStore dupStore1 = new DupStore( + ByteCodeConstants.DUPSTORE, offset, lineNumber, i1); + + list.add(dupStore1); + stack.push(dupStore1.getDupLoad1()); + stack.push(dupStore1.getDupLoad2()); + } + else + { + // ..., value2, value1 => ..., value2, value1, value2, value1 + Instruction i2 = stack.pop(); + + DupStore dupStore1 = new DupStore( + ByteCodeConstants.DUPSTORE, offset, lineNumber, i1); + DupStore dupStore2 = new DupStore( + ByteCodeConstants.DUPSTORE, offset, lineNumber, i2); + + list.add(dupStore1); + list.add(dupStore2); + stack.push(dupStore2.getDupLoad1()); + stack.push(dupStore1.getDupLoad1()); + stack.push(dupStore2.getDupLoad2()); + stack.push(dupStore1.getDupLoad2()); + } + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/Dup2X1Factory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/Dup2X1Factory.java new file mode 100644 index 00000000..aad76caa --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/Dup2X1Factory.java @@ -0,0 +1,60 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.DupStore; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class Dup2X1Factory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + Instruction i1 = stack.pop(); + Instruction i2 = stack.pop(); + + String signature1 = i1.getReturnedSignature( + classFile.getConstantPool(), method.getLocalVariables()); + + if ("J".equals(signature1) || "D".equals(signature1)) + { + // ..., value2, value1 => ..., value1, value2, value1 + DupStore dupStore1 = new DupStore( + ByteCodeConstants.DUPSTORE, offset, lineNumber, i1); + + list.add(dupStore1); + stack.push(dupStore1.getDupLoad1()); + stack.push(i2); + stack.push(dupStore1.getDupLoad2()); + } + else + { + // ..., value3, value2, value1 => ..., value2, value1, value3, value2, value1 + Instruction i3 = stack.pop(); + + DupStore dupStore1 = new DupStore( + ByteCodeConstants.DUPSTORE, offset, lineNumber, i1); + DupStore dupStore2 = new DupStore( + ByteCodeConstants.DUPSTORE, offset, lineNumber, i2); + + list.add(dupStore1); + list.add(dupStore2); + stack.push(dupStore2.getDupLoad1()); + stack.push(dupStore1.getDupLoad1()); + stack.push(i3); + stack.push(dupStore2.getDupLoad2()); + stack.push(dupStore1.getDupLoad2()); + } + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/Dup2X2Factory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/Dup2X2Factory.java new file mode 100644 index 00000000..b2fedc53 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/Dup2X2Factory.java @@ -0,0 +1,106 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.DupStore; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class Dup2X2Factory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + Instruction i1 = stack.pop(); + Instruction i2 = stack.pop(); + + String signature1 = i1.getReturnedSignature( + classFile.getConstantPool(), method.getLocalVariables()); + String signature2 = i2.getReturnedSignature( + classFile.getConstantPool(), method.getLocalVariables()); + + if ("J".equals(signature1) || "D".equals(signature1)) + { + if ("J".equals(signature2) || "D".equals(signature2)) + { + // ..., value2, value1 => ..., value1, value2, value1 + DupStore dupStore1 = new DupStore( + ByteCodeConstants.DUPSTORE, offset, lineNumber, i1); + + list.add(dupStore1); + stack.push(dupStore1.getDupLoad1()); + stack.push(i2); + stack.push(dupStore1.getDupLoad2()); + } + else + { + // ..., value3, value2, value1 => ..., value1, value3, value2, value1 + Instruction i3 = stack.pop(); + + DupStore dupStore1 = new DupStore( + ByteCodeConstants.DUPSTORE, offset, lineNumber, i1); + + list.add(dupStore1); + stack.push(dupStore1.getDupLoad1()); + stack.push(i3); + stack.push(i2); + stack.push(dupStore1.getDupLoad2()); + } + } + else + { + Instruction i3 = stack.pop(); + + String signature3 = i3.getReturnedSignature( + classFile.getConstantPool(), method.getLocalVariables()); + + if ("J".equals(signature3) || "D".equals(signature3)) + { + // ..., value3, value2, value1 => ..., value2, value1, value3, value2, value1 + DupStore dupStore1 = new DupStore( + ByteCodeConstants.DUPSTORE, offset, lineNumber, i1); + DupStore dupStore2 = new DupStore( + ByteCodeConstants.DUPSTORE, offset, lineNumber, i2); + + list.add(dupStore1); + list.add(dupStore2); + + stack.push(dupStore2.getDupLoad1()); + stack.push(dupStore1.getDupLoad1()); + stack.push(i3); + stack.push(dupStore2.getDupLoad2()); + stack.push(dupStore1.getDupLoad2()); + } + else + { + // ..., value4, value3, value2, value1 => ..., value2, value1, value4, value3, value2, value1 + Instruction i4 = stack.pop(); + + DupStore dupStore1 = new DupStore( + ByteCodeConstants.DUPSTORE, offset, lineNumber, i1); + DupStore dupStore2 = new DupStore( + ByteCodeConstants.DUPSTORE, offset, lineNumber, i2); + + list.add(dupStore1); + list.add(dupStore2); + + stack.push(dupStore2.getDupLoad1()); + stack.push(dupStore1.getDupLoad1()); + stack.push(i4); + stack.push(i3); + stack.push(dupStore2.getDupLoad2()); + stack.push(dupStore1.getDupLoad2()); + } + } + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/DupFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/DupFactory.java new file mode 100644 index 00000000..4e8ff11f --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/DupFactory.java @@ -0,0 +1,34 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.DupStore; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class DupFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + Instruction i = stack.pop(); + + // ..., value => ..., value, value + DupStore dupStore = new DupStore( + ByteCodeConstants.DUPSTORE, offset, lineNumber, i); + + list.add(dupStore); + stack.push(dupStore.getDupLoad1()); + stack.push(dupStore.getDupLoad2()); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/DupX1Factory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/DupX1Factory.java new file mode 100644 index 00000000..30befe75 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/DupX1Factory.java @@ -0,0 +1,36 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.DupStore; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class DupX1Factory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + Instruction i1 = stack.pop(); + Instruction i2 = stack.pop(); + + // ..., value2, value1 => ..., value1, value2, value1 + DupStore dupStore1 = new DupStore( + ByteCodeConstants.DUPSTORE, offset, lineNumber, i1); + + list.add(dupStore1); + stack.push(dupStore1.getDupLoad1()); + stack.push(i2); + stack.push(dupStore1.getDupLoad2()); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/DupX2Factory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/DupX2Factory.java new file mode 100644 index 00000000..d4210a99 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/DupX2Factory.java @@ -0,0 +1,53 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.DupStore; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class DupX2Factory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + Instruction i1 = stack.pop(); + Instruction i2 = stack.pop(); + + DupStore dupStore1 = new DupStore( + ByteCodeConstants.DUPSTORE, offset, lineNumber, i1); + + list.add(dupStore1); + + String signature2 = i2.getReturnedSignature( + classFile.getConstantPool(), null); + + if ("J".equals(signature2) || "D".equals(signature2)) + { + // ..., value2, value1 => ..., value1, value2, value1 + stack.push(dupStore1.getDupLoad1()); + stack.push(i2); + stack.push(dupStore1.getDupLoad2()); + } + else + { + // ..., value3, value2, value1 => ..., value1, value3, value2, value1 + Instruction i3 = stack.pop(); + + stack.push(dupStore1.getDupLoad1()); + stack.push(i3); + stack.push(i2); + stack.push(dupStore1.getDupLoad2()); + } + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/FConstFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/FConstFactory.java new file mode 100644 index 00000000..e3b919cc --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/FConstFactory.java @@ -0,0 +1,29 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.FConst; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class FConstFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + final int index = opcode - ByteCodeConstants.FCONST_0; + + stack.push(new FConst( + ByteCodeConstants.FCONST, offset, lineNumber, index)); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/FLoadFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/FLoadFactory.java new file mode 100644 index 00000000..fe0b3c58 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/FLoadFactory.java @@ -0,0 +1,37 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.LoadInstruction; + + +public class FLoadFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + int index; + + if (opcode == ByteCodeConstants.FLOAD) + index = code[offset+1] & 255; + else + index = opcode - ByteCodeConstants.FLOAD_0; + + final Instruction instruction = new LoadInstruction( + ByteCodeConstants.LOAD, offset, lineNumber, index, "F"); + + stack.push(instruction); + listForAnalyze.add(instruction); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/FStoreFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/FStoreFactory.java new file mode 100644 index 00000000..e9a8ac2e --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/FStoreFactory.java @@ -0,0 +1,38 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.StoreInstruction; + + +public class FStoreFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + int index; + + if (opcode == ByteCodeConstants.FSTORE) + index = code[offset+1] & 255; + else + index = opcode - ByteCodeConstants.FSTORE_0; + + final Instruction instruction = new StoreInstruction( + ByteCodeConstants.STORE, offset, + lineNumber, index, "F", stack.pop()); + + list.add(instruction); + listForAnalyze.add(instruction); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/GetFieldFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/GetFieldFactory.java new file mode 100644 index 00000000..d8454d61 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/GetFieldFactory.java @@ -0,0 +1,29 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.GetField; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class GetFieldFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + final int index = ((code[offset+1] & 255) << 8) | (code[offset+2] & 255); + + stack.push(new GetField( + opcode, offset, lineNumber, index, stack.pop())); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/GetStaticFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/GetStaticFactory.java new file mode 100644 index 00000000..1805da3c --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/GetStaticFactory.java @@ -0,0 +1,28 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.GetStatic; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class GetStaticFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + final int index = ((code[offset+1] & 255) << 8) | (code[offset+2] & 255); + + stack.push(new GetStatic(opcode, offset, lineNumber, index)); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/GotoFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/GotoFactory.java new file mode 100644 index 00000000..ae6858ee --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/GotoFactory.java @@ -0,0 +1,262 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.Goto; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.TernaryOpStore; +import jd.core.process.analyzer.instruction.bytecode.util.ByteCodeUtil; + + +public class GotoFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + final int value = + (short)(((code[offset+1] & 255) << 8) | (code[offset+2] & 255)); + + if (!stack.isEmpty() && !list.isEmpty()) + generateTernaryOpStore( + list, listForAnalyze, stack, code, offset, value); + + list.add(new Goto(opcode, offset, lineNumber, value)); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } + + private static void generateTernaryOpStore( + List list, List listForAnalyze, + Stack stack, byte[] code, int offset, int value) + { + int i = list.size(); + + while (i-- > 0) + { + Instruction previousInstruction = list.get(i); + + switch (previousInstruction.opcode) + { + case ByteCodeConstants.IF: + case ByteCodeConstants.IFCMP: + case ByteCodeConstants.IFXNULL: + { + // Gestion de l'operateur ternaire + final int ternaryOp2ndValueOffset = + search2ndValueOffset(code, offset, offset+value); + + final Instruction value0 = stack.pop(); + TernaryOpStore tos = new TernaryOpStore( + ByteCodeConstants.TERNARYOPSTORE, offset-1, + value0.lineNumber, value0, ternaryOp2ndValueOffset); + + list.add(tos); + listForAnalyze.add(tos); + } + return; + } + } + } + + private static int search2ndValueOffset( + byte[] code, int offset, int jumpOffset) + { + int result = offset; + + while (offset < jumpOffset) + { + int opcode = code[offset] & 255; + + // on retient l'offset de la derniere op�ration placant une + // information sur la pile. + switch (opcode) + { + case ByteCodeConstants.ACONST_NULL: + case ByteCodeConstants.ICONST_M1: + case ByteCodeConstants.ICONST_0: + case ByteCodeConstants.ICONST_1: + case ByteCodeConstants.ICONST_2: + case ByteCodeConstants.ICONST_3: + case ByteCodeConstants.ICONST_4: + case ByteCodeConstants.ICONST_5: + case ByteCodeConstants.LCONST_0: + case ByteCodeConstants.LCONST_1: + case ByteCodeConstants.FCONST_0: + case ByteCodeConstants.FCONST_1: + case ByteCodeConstants.FCONST_2: + case ByteCodeConstants.DCONST_0: + case ByteCodeConstants.DCONST_1: + case ByteCodeConstants.BIPUSH: + case ByteCodeConstants.SIPUSH: + case ByteCodeConstants.LDC: + case ByteCodeConstants.LDC_W: + case ByteCodeConstants.LDC2_W: + case ByteCodeConstants.ILOAD: + case ByteCodeConstants.LLOAD: + case ByteCodeConstants.FLOAD: + case ByteCodeConstants.DLOAD: + case ByteCodeConstants.ALOAD: + case ByteCodeConstants.ILOAD_0: + case ByteCodeConstants.ILOAD_1: + case ByteCodeConstants.ILOAD_2: + case ByteCodeConstants.ILOAD_3: + case ByteCodeConstants.LLOAD_0: + case ByteCodeConstants.LLOAD_1: + case ByteCodeConstants.LLOAD_2: + case ByteCodeConstants.LLOAD_3: + case ByteCodeConstants.FLOAD_0: + case ByteCodeConstants.FLOAD_1: + case ByteCodeConstants.FLOAD_2: + case ByteCodeConstants.FLOAD_3: + case ByteCodeConstants.DLOAD_0: + case ByteCodeConstants.DLOAD_1: + case ByteCodeConstants.DLOAD_2: + case ByteCodeConstants.DLOAD_3: + case ByteCodeConstants.ALOAD_0: + case ByteCodeConstants.ALOAD_1: + case ByteCodeConstants.ALOAD_2: + case ByteCodeConstants.ALOAD_3: + case ByteCodeConstants.IALOAD: + case ByteCodeConstants.LALOAD: + case ByteCodeConstants.FALOAD: + case ByteCodeConstants.DALOAD: + case ByteCodeConstants.AALOAD: + case ByteCodeConstants.BALOAD: + case ByteCodeConstants.CALOAD: + case ByteCodeConstants.SALOAD: + case ByteCodeConstants.DUP: + case ByteCodeConstants.DUP_X1: + case ByteCodeConstants.DUP_X2: + case ByteCodeConstants.DUP2: + case ByteCodeConstants.DUP2_X1: + case ByteCodeConstants.DUP2_X2: + case ByteCodeConstants.SWAP: + case ByteCodeConstants.IADD: + case ByteCodeConstants.LADD: + case ByteCodeConstants.FADD: + case ByteCodeConstants.DADD: + case ByteCodeConstants.ISUB: + case ByteCodeConstants.LSUB: + case ByteCodeConstants.FSUB: + case ByteCodeConstants.DSUB: + case ByteCodeConstants.IMUL: + case ByteCodeConstants.LMUL: + case ByteCodeConstants.FMUL: + case ByteCodeConstants.DMUL: + case ByteCodeConstants.IDIV: + case ByteCodeConstants.LDIV: + case ByteCodeConstants.FDIV: + case ByteCodeConstants.DDIV: + case ByteCodeConstants.IREM: + case ByteCodeConstants.LREM: + case ByteCodeConstants.FREM: + case ByteCodeConstants.DREM: + case ByteCodeConstants.INEG: + case ByteCodeConstants.LNEG: + case ByteCodeConstants.FNEG: + case ByteCodeConstants.DNEG: + case ByteCodeConstants.ISHL: + case ByteCodeConstants.LSHL: + case ByteCodeConstants.ISHR: + case ByteCodeConstants.LSHR: + case ByteCodeConstants.IUSHR: + case ByteCodeConstants.LUSHR: + case ByteCodeConstants.IAND: + case ByteCodeConstants.LAND: + case ByteCodeConstants.IOR: + case ByteCodeConstants.LOR: + case ByteCodeConstants.IXOR: + case ByteCodeConstants.LXOR: + case ByteCodeConstants.IINC: + case ByteCodeConstants.I2L: + case ByteCodeConstants.I2F: + case ByteCodeConstants.I2D: + case ByteCodeConstants.L2I: + case ByteCodeConstants.L2F: + case ByteCodeConstants.L2D: + case ByteCodeConstants.F2I: + case ByteCodeConstants.F2L: + case ByteCodeConstants.F2D: + case ByteCodeConstants.D2I: + case ByteCodeConstants.D2L: + case ByteCodeConstants.D2F: + case ByteCodeConstants.I2B: + case ByteCodeConstants.I2C: + case ByteCodeConstants.I2S: + case ByteCodeConstants.LCMP: + case ByteCodeConstants.FCMPL: + case ByteCodeConstants.FCMPG: + case ByteCodeConstants.DCMPL: + case ByteCodeConstants.DCMPG: + case ByteCodeConstants.GETSTATIC: + case ByteCodeConstants.OUTERTHIS: + case ByteCodeConstants.GETFIELD: + case ByteCodeConstants.INVOKEVIRTUAL: + case ByteCodeConstants.INVOKESPECIAL: + case ByteCodeConstants.INVOKESTATIC: + case ByteCodeConstants.INVOKEINTERFACE: + case ByteCodeConstants.NEW: + case ByteCodeConstants.NEWARRAY: + case ByteCodeConstants.ANEWARRAY: + case ByteCodeConstants.ARRAYLENGTH: + case ByteCodeConstants.CHECKCAST: + case ByteCodeConstants.INSTANCEOF: + case ByteCodeConstants.WIDE: + case ByteCodeConstants.MULTIANEWARRAY: + // Extension for decompiler + case ByteCodeConstants.ICONST: + case ByteCodeConstants.LCONST: + case ByteCodeConstants.FCONST: + case ByteCodeConstants.DCONST: + case ByteCodeConstants.DUPLOAD: + case ByteCodeConstants.ASSIGNMENT: + case ByteCodeConstants.UNARYOP: + case ByteCodeConstants.BINARYOP: + case ByteCodeConstants.LOAD: + case ByteCodeConstants.EXCEPTIONLOAD: + case ByteCodeConstants.ARRAYLOAD: + case ByteCodeConstants.INVOKENEW: + case ByteCodeConstants.CONVERT: + case ByteCodeConstants.IMPLICITCONVERT: + case ByteCodeConstants.PREINC: + case ByteCodeConstants.POSTINC: + result = offset; + } + + int nbOfOperands = ByteCodeConstants.NO_OF_OPERANDS[opcode]; + + switch (nbOfOperands) + { + case ByteCodeConstants.NO_OF_OPERANDS_UNPREDICTABLE: + switch (opcode) + { + case ByteCodeConstants.TABLESWITCH: + offset = ByteCodeUtil.NextTableSwitchOffset(code, offset); + break; + case ByteCodeConstants.LOOKUPSWITCH: + offset = ByteCodeUtil.NextLookupSwitchOffset(code, offset); + break; + case ByteCodeConstants.WIDE: + offset = ByteCodeUtil.NextWideOffset(code, offset); + } + break; + case ByteCodeConstants.NO_OF_OPERANDS_UNDEFINED: + break; + default: + offset += nbOfOperands; + } + + ++offset; + } + + return result; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/GotoWFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/GotoWFactory.java new file mode 100644 index 00000000..a69962c8 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/GotoWFactory.java @@ -0,0 +1,30 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.Goto; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class GotoWFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + final int value = ((code[offset+1] & 255) << 24) | ((code[offset+2] & 255) << 16) | + ((code[offset+3] & 255) << 8 ) | (code[offset+4] & 255); + + list.add(new Goto( + ByteCodeConstants.GOTO, offset, lineNumber, value)); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/IBinaryOperatorFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/IBinaryOperatorFactory.java new file mode 100644 index 00000000..6720cbd1 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/IBinaryOperatorFactory.java @@ -0,0 +1,43 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.IBinaryOperatorInstruction; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class IBinaryOperatorFactory extends InstructionFactory +{ + protected int priority; + protected String operator; + + public IBinaryOperatorFactory(int priority, String operator) + { + this.priority = priority; + this.operator = operator; + } + + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + final Instruction i2 = stack.pop(); + final Instruction i1 = stack.pop(); + + final Instruction instruction = new IBinaryOperatorInstruction( + ByteCodeConstants.BINARYOP, offset, lineNumber, this.priority, + this.operator, i1, i2); + + stack.push(instruction); + listForAnalyze.add(instruction); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/IConstFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/IConstFactory.java new file mode 100644 index 00000000..ae8da2f4 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/IConstFactory.java @@ -0,0 +1,29 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.IConst; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class IConstFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + final int index = opcode - ByteCodeConstants.ICONST_0; + + stack.push(new IConst( + ByteCodeConstants.ICONST, offset, lineNumber, index)); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/IIncFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/IIncFactory.java new file mode 100644 index 00000000..b89b7892 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/IIncFactory.java @@ -0,0 +1,67 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.IInc; +import jd.core.model.instruction.bytecode.instruction.ILoad; +import jd.core.model.instruction.bytecode.instruction.IncInstruction; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class IIncFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + final int index = code[offset+1]; + final int count = code[offset+2]; + Instruction instruction; + + if (stack.isEmpty() || jumps[offset]) + { + // Normal case + list.add(instruction = + new IInc(opcode, offset, lineNumber, index, count)); + listForAnalyze.add(instruction); + } + else + { + instruction = stack.lastElement(); + + if ((instruction.opcode == ByteCodeConstants.ILOAD) && + (((ILoad)instruction).index == index)) + { + // Replace IInc instruction by a post-inc instruction + stack.pop(); + stack.push(instruction = new IncInstruction( + ByteCodeConstants.POSTINC, offset, + lineNumber, instruction, count)); + listForAnalyze.add(instruction); + } + else if ((count == -1) || (count == 1)) + { + // Place a temporary IInc instruction on stack to build a + // pre-inc instruction. See ILoadFactory. + stack.push(instruction = + new IInc(opcode, offset, lineNumber, index, count)); + } + else + { + // Normal case + list.add(instruction = + new IInc(opcode, offset, lineNumber, index, count)); + listForAnalyze.add(instruction); + } + } + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/ILoadFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/ILoadFactory.java new file mode 100644 index 00000000..7186c56b --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/ILoadFactory.java @@ -0,0 +1,77 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.IInc; +import jd.core.model.instruction.bytecode.instruction.ILoad; +import jd.core.model.instruction.bytecode.instruction.IncInstruction; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class ILoadFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + int index; + + if (opcode == ByteCodeConstants.ILOAD) + index = code[offset+1] & 255; + else + index = opcode - ByteCodeConstants.ILOAD_0; + + Instruction instruction = + new ILoad(ByteCodeConstants.ILOAD, offset, lineNumber, index); + + if (stack.isEmpty() || jumps[offset]) + { + // Normal case + stack.push(instruction); + } + else + { + Instruction last = stack.lastElement(); + + if (last.opcode == ByteCodeConstants.IINC) + { + if (((IInc)last).index == index) + { + listForAnalyze.add(instruction); + + // Replace temporary IInc instruction by a pre-inc instruction + IInc iinc = (IInc)last; + stack.pop(); + stack.push(instruction = new IncInstruction( + ByteCodeConstants.PREINC, iinc.offset, + iinc.lineNumber, instruction, iinc.count)); + } + else + { + // Unkwown pattern. Move IInc instruction from stack to list. + stack.pop(); + list.add(last); + listForAnalyze.add(last); + // Store ILoad instruction + stack.push(instruction); + } + } + else + { + // Normal case + stack.push(instruction); + } + } + + listForAnalyze.add(instruction); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/IStoreFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/IStoreFactory.java new file mode 100644 index 00000000..62f79156 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/IStoreFactory.java @@ -0,0 +1,37 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.IStore; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class IStoreFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + int index; + + if (code[offset] == ByteCodeConstants.ISTORE) + index = code[offset+1] & 255; + else + index = (code[offset] & 255) - ByteCodeConstants.ISTORE_0; + + final Instruction instruction = new IStore( + ByteCodeConstants.ISTORE, offset, lineNumber, index, stack.pop()); + + list.add(instruction); + listForAnalyze.add(instruction); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/IfCmpFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/IfCmpFactory.java new file mode 100644 index 00000000..09a3efd8 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/IfCmpFactory.java @@ -0,0 +1,43 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.IfCmp; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class IfCmpFactory extends InstructionFactory +{ + protected int cmp; + + public IfCmpFactory(int cmp) + { + this.cmp = cmp; + } + + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + final int branch = + (short)(((code[offset+1] & 255) << 8) | (code[offset+2] & 255)); + final Instruction value2 = stack.pop(); + final Instruction value1 = stack.pop(); + + final Instruction newInstruction = new IfCmp( + ByteCodeConstants.IFCMP, offset, lineNumber, + this.cmp, value1, value2, branch); + + list.add(newInstruction); + listForAnalyze.add(newInstruction); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/IfFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/IfFactory.java new file mode 100644 index 00000000..599a1e15 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/IfFactory.java @@ -0,0 +1,38 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.IfInstruction; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class IfFactory extends InstructionFactory +{ + protected int cmp; + + public IfFactory(int cmp) + { + this.cmp = cmp; + } + + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + final int branch = + (short)(((code[offset+1] & 255) << 8) | (code[offset+2] & 255)); + final Instruction value = stack.pop(); + + list.add(new IfInstruction( + ByteCodeConstants.IF, offset, lineNumber, this.cmp, value, branch)); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/IfXNullFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/IfXNullFactory.java new file mode 100644 index 00000000..1f51bc7f --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/IfXNullFactory.java @@ -0,0 +1,63 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.DupLoad; +import jd.core.model.instruction.bytecode.instruction.IfInstruction; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class IfXNullFactory extends InstructionFactory +{ + public int cmp; + + public IfXNullFactory(int cmp) + { + this.cmp = cmp; + } + + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + final int branch = + (short)(((code[offset+1] & 255) << 8) | (code[offset+2] & 255)); + + list.add(new IfInstruction( + ByteCodeConstants.IFXNULL, offset, lineNumber, + this.cmp, stack.pop(), branch)); + + if (!stack.isEmpty()) + { + Instruction instruction = stack.lastElement(); + if (instruction.opcode == ByteCodeConstants.DUPLOAD) + { + int nextOffset = + offset + ByteCodeConstants.NO_OF_OPERANDS[opcode] + 1; + + if (nextOffset < code.length) + { + switch (code[nextOffset] & 255) + { + case ByteCodeConstants.POP: + case ByteCodeConstants.ARETURN: + // Duplicate 'DupLoad' instruction used by + // DotClass118BReconstructor + DupLoad dp = (DupLoad)instruction; + stack.push(new DupLoad( + dp.opcode, dp.offset, dp.lineNumber, dp.dupStore)); + } + } + } + } + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/ImplicitConvertInstructionFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/ImplicitConvertInstructionFactory.java new file mode 100644 index 00000000..1a0dc5d1 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/ImplicitConvertInstructionFactory.java @@ -0,0 +1,36 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.ImplicitConvertInstruction; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class ImplicitConvertInstructionFactory extends InstructionFactory +{ + private String signature; + + public ImplicitConvertInstructionFactory(String signature) + { + this.signature = signature; + } + + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + + stack.push(new ImplicitConvertInstruction( + ByteCodeConstants.IMPLICITCONVERT, offset, lineNumber, + stack.pop(), this.signature)); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/InstanceOfFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/InstanceOfFactory.java new file mode 100644 index 00000000..c35e9aa9 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/InstanceOfFactory.java @@ -0,0 +1,29 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.InstanceOf; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class InstanceOfFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + final int index = ((code[offset+1] & 255) << 8) | (code[offset+2] & 255); + + stack.push(new InstanceOf( + opcode, offset, lineNumber, index, stack.pop())); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/InstructionFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/InstructionFactory.java new file mode 100644 index 00000000..8066420f --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/InstructionFactory.java @@ -0,0 +1,23 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public abstract class InstructionFactory +{ + public abstract int create( + ClassFile classFile, + Method method, + List list, + List listForAnalyze, + Stack stack, + byte[] code, + int offset, + int lineNumber, + boolean[] jumps); +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/InstructionFactoryConstants.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/InstructionFactoryConstants.java new file mode 100644 index 00000000..1c24cecb --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/InstructionFactoryConstants.java @@ -0,0 +1,247 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import jd.core.model.instruction.bytecode.ByteCodeConstants; + +public class InstructionFactoryConstants +{ + public final static InstructionFactory[] FACTORIES; + + static + { + FACTORIES = new InstructionFactory[256]; + + FACTORIES[ByteCodeConstants.NOP] = new DummyFactory(); + FACTORIES[ByteCodeConstants.ACONST_NULL] = new AConstNullFactory(); + FACTORIES[ByteCodeConstants.ICONST_M1] = new IConstFactory(); + FACTORIES[ByteCodeConstants.ICONST_0] = FACTORIES[ByteCodeConstants.ICONST_M1]; + FACTORIES[ByteCodeConstants.ICONST_1] = FACTORIES[ByteCodeConstants.ICONST_M1]; + FACTORIES[ByteCodeConstants.ICONST_2] = FACTORIES[ByteCodeConstants.ICONST_M1]; + FACTORIES[ByteCodeConstants.ICONST_3] = FACTORIES[ByteCodeConstants.ICONST_M1]; + FACTORIES[ByteCodeConstants.ICONST_4] = FACTORIES[ByteCodeConstants.ICONST_M1]; + FACTORIES[ByteCodeConstants.ICONST_5] = FACTORIES[ByteCodeConstants.ICONST_M1]; + FACTORIES[ByteCodeConstants.LCONST_0] = new LConstFactory(); + FACTORIES[ByteCodeConstants.LCONST_1] = FACTORIES[ByteCodeConstants.LCONST_0]; + FACTORIES[ByteCodeConstants.FCONST_0] = new FConstFactory(); + FACTORIES[ByteCodeConstants.FCONST_1] = FACTORIES[ByteCodeConstants.FCONST_0]; + FACTORIES[ByteCodeConstants.FCONST_2] = FACTORIES[ByteCodeConstants.FCONST_0]; + FACTORIES[ByteCodeConstants.DCONST_0] = new DConstFactory(); + FACTORIES[ByteCodeConstants.DCONST_1] = FACTORIES[ByteCodeConstants.DCONST_0]; + FACTORIES[ByteCodeConstants.BIPUSH] = new BIPushFactory(); + FACTORIES[ByteCodeConstants.SIPUSH] = new SIPushFactory(); + FACTORIES[ByteCodeConstants.LDC] = new LdcFactory(); + FACTORIES[ByteCodeConstants.LDC_W] = new LdcWFactory(); + FACTORIES[ByteCodeConstants.LDC2_W] = new Ldc2WFactory(); + FACTORIES[ByteCodeConstants.ILOAD] = new ILoadFactory(); + FACTORIES[ByteCodeConstants.LLOAD] = new LLoadFactory(); + FACTORIES[ByteCodeConstants.FLOAD] = new FLoadFactory(); + FACTORIES[ByteCodeConstants.DLOAD] = new DLoadFactory(); + FACTORIES[ByteCodeConstants.ALOAD] = new ALoadFactory(); + FACTORIES[ByteCodeConstants.ILOAD_0] = FACTORIES[ByteCodeConstants.ILOAD]; + FACTORIES[ByteCodeConstants.ILOAD_1] = FACTORIES[ByteCodeConstants.ILOAD]; + FACTORIES[ByteCodeConstants.ILOAD_2] = FACTORIES[ByteCodeConstants.ILOAD]; + FACTORIES[ByteCodeConstants.ILOAD_3] = FACTORIES[ByteCodeConstants.ILOAD]; + FACTORIES[ByteCodeConstants.LLOAD_0] = FACTORIES[ByteCodeConstants.LLOAD]; + FACTORIES[ByteCodeConstants.LLOAD_1] = FACTORIES[ByteCodeConstants.LLOAD]; + FACTORIES[ByteCodeConstants.LLOAD_2] = FACTORIES[ByteCodeConstants.LLOAD]; + FACTORIES[ByteCodeConstants.LLOAD_3] = FACTORIES[ByteCodeConstants.LLOAD]; + FACTORIES[ByteCodeConstants.FLOAD_0] = FACTORIES[ByteCodeConstants.FLOAD]; + FACTORIES[ByteCodeConstants.FLOAD_1] = FACTORIES[ByteCodeConstants.FLOAD]; + FACTORIES[ByteCodeConstants.FLOAD_2] = FACTORIES[ByteCodeConstants.FLOAD]; + FACTORIES[ByteCodeConstants.FLOAD_3] = FACTORIES[ByteCodeConstants.FLOAD]; + FACTORIES[ByteCodeConstants.DLOAD_0] = FACTORIES[ByteCodeConstants.DLOAD]; + FACTORIES[ByteCodeConstants.DLOAD_1] = FACTORIES[ByteCodeConstants.DLOAD]; + FACTORIES[ByteCodeConstants.DLOAD_2] = FACTORIES[ByteCodeConstants.DLOAD]; + FACTORIES[ByteCodeConstants.DLOAD_3] = FACTORIES[ByteCodeConstants.DLOAD]; + FACTORIES[ByteCodeConstants.ALOAD_0] = FACTORIES[ByteCodeConstants.ALOAD]; + FACTORIES[ByteCodeConstants.ALOAD_1] = FACTORIES[ByteCodeConstants.ALOAD]; + FACTORIES[ByteCodeConstants.ALOAD_2] = FACTORIES[ByteCodeConstants.ALOAD]; + FACTORIES[ByteCodeConstants.ALOAD_3] = FACTORIES[ByteCodeConstants.ALOAD]; + FACTORIES[ByteCodeConstants.IALOAD] = new ArrayLoadInstructionFactory("I"); + FACTORIES[ByteCodeConstants.LALOAD] = new ArrayLoadInstructionFactory("J"); + FACTORIES[ByteCodeConstants.FALOAD] = new ArrayLoadInstructionFactory("F"); + FACTORIES[ByteCodeConstants.DALOAD] = new ArrayLoadInstructionFactory("D"); + FACTORIES[ByteCodeConstants.AALOAD] = new AALoadFactory(); + FACTORIES[ByteCodeConstants.BALOAD] = new ArrayLoadInstructionFactory("B"); + FACTORIES[ByteCodeConstants.CALOAD] = new ArrayLoadInstructionFactory("C"); + FACTORIES[ByteCodeConstants.SALOAD] = new ArrayLoadInstructionFactory("S"); + FACTORIES[ByteCodeConstants.ISTORE] = new IStoreFactory(); + FACTORIES[ByteCodeConstants.LSTORE] = new LStoreFactory(); + FACTORIES[ByteCodeConstants.FSTORE] = new FStoreFactory(); + FACTORIES[ByteCodeConstants.DSTORE] = new DStoreFactory(); + FACTORIES[ByteCodeConstants.ASTORE] = new AStoreFactory(); + FACTORIES[ByteCodeConstants.ISTORE_0] = FACTORIES[ByteCodeConstants.ISTORE]; + FACTORIES[ByteCodeConstants.ISTORE_1] = FACTORIES[ByteCodeConstants.ISTORE]; + FACTORIES[ByteCodeConstants.ISTORE_2] = FACTORIES[ByteCodeConstants.ISTORE]; + FACTORIES[ByteCodeConstants.ISTORE_3] = FACTORIES[ByteCodeConstants.ISTORE]; + FACTORIES[ByteCodeConstants.LSTORE_0] = FACTORIES[ByteCodeConstants.LSTORE]; + FACTORIES[ByteCodeConstants.LSTORE_1] = FACTORIES[ByteCodeConstants.LSTORE]; + FACTORIES[ByteCodeConstants.LSTORE_2] = FACTORIES[ByteCodeConstants.LSTORE]; + FACTORIES[ByteCodeConstants.LSTORE_3] = FACTORIES[ByteCodeConstants.LSTORE]; + FACTORIES[ByteCodeConstants.FSTORE_0] = FACTORIES[ByteCodeConstants.FSTORE]; + FACTORIES[ByteCodeConstants.FSTORE_1] = FACTORIES[ByteCodeConstants.FSTORE]; + FACTORIES[ByteCodeConstants.FSTORE_2] = FACTORIES[ByteCodeConstants.FSTORE]; + FACTORIES[ByteCodeConstants.FSTORE_3] = FACTORIES[ByteCodeConstants.FSTORE]; + FACTORIES[ByteCodeConstants.DSTORE_0] = FACTORIES[ByteCodeConstants.DSTORE]; + FACTORIES[ByteCodeConstants.DSTORE_1] = FACTORIES[ByteCodeConstants.DSTORE]; + FACTORIES[ByteCodeConstants.DSTORE_2] = FACTORIES[ByteCodeConstants.DSTORE]; + FACTORIES[ByteCodeConstants.DSTORE_3] = FACTORIES[ByteCodeConstants.DSTORE]; + FACTORIES[ByteCodeConstants.ASTORE_0] = FACTORIES[ByteCodeConstants.ASTORE]; + FACTORIES[ByteCodeConstants.ASTORE_1] = FACTORIES[ByteCodeConstants.ASTORE]; + FACTORIES[ByteCodeConstants.ASTORE_2] = FACTORIES[ByteCodeConstants.ASTORE]; + FACTORIES[ByteCodeConstants.ASTORE_3] = FACTORIES[ByteCodeConstants.ASTORE]; + FACTORIES[ByteCodeConstants.IASTORE] = new ArrayStoreInstructionFactory("I"); + FACTORIES[ByteCodeConstants.LASTORE] = new ArrayStoreInstructionFactory("J"); + FACTORIES[ByteCodeConstants.FASTORE] = new ArrayStoreInstructionFactory("F"); + FACTORIES[ByteCodeConstants.DASTORE] = new ArrayStoreInstructionFactory("D"); + FACTORIES[ByteCodeConstants.AASTORE] = new AAStoreFactory(); + FACTORIES[ByteCodeConstants.BASTORE] = new ArrayStoreInstructionFactory("B"); + FACTORIES[ByteCodeConstants.CASTORE] = new ArrayStoreInstructionFactory("C"); + FACTORIES[ByteCodeConstants.SASTORE] = new ArrayStoreInstructionFactory("S"); + FACTORIES[ByteCodeConstants.POP] = new PopFactory(); + FACTORIES[ByteCodeConstants.POP2] = new Pop2Factory(); + FACTORIES[ByteCodeConstants.DUP] = new DupFactory(); + FACTORIES[ByteCodeConstants.DUP_X1] = new DupX1Factory(); + FACTORIES[ByteCodeConstants.DUP_X2] = new DupX2Factory(); + FACTORIES[ByteCodeConstants.DUP2] = new Dup2Factory(); + FACTORIES[ByteCodeConstants.DUP2_X1] = new Dup2X1Factory(); + FACTORIES[ByteCodeConstants.DUP2_X2] = new Dup2X2Factory(); + FACTORIES[ByteCodeConstants.SWAP] = new SwapFactory(); + FACTORIES[ByteCodeConstants.IADD] = new BinaryOperatorFactory(4, "I", "+"); + FACTORIES[ByteCodeConstants.LADD] = new BinaryOperatorFactory(4, "J", "+"); + FACTORIES[ByteCodeConstants.FADD] = new BinaryOperatorFactory(4, "F", "+"); + FACTORIES[ByteCodeConstants.DADD] = new BinaryOperatorFactory(4, "D", "+"); + FACTORIES[ByteCodeConstants.ISUB] = new BinaryOperatorFactory(4, "I", "-"); + FACTORIES[ByteCodeConstants.LSUB] = new BinaryOperatorFactory(4, "J", "-"); + FACTORIES[ByteCodeConstants.FSUB] = new BinaryOperatorFactory(4, "F", "-"); + FACTORIES[ByteCodeConstants.DSUB] = new BinaryOperatorFactory(4, "D", "-"); + FACTORIES[ByteCodeConstants.IMUL] = new BinaryOperatorFactory(3, "I", "*"); + FACTORIES[ByteCodeConstants.LMUL] = new BinaryOperatorFactory(3, "J", "*"); + FACTORIES[ByteCodeConstants.FMUL] = new BinaryOperatorFactory(3, "F", "*"); + FACTORIES[ByteCodeConstants.DMUL] = new BinaryOperatorFactory(3, "D", "*"); + FACTORIES[ByteCodeConstants.IDIV] = new BinaryOperatorFactory(3, "I", "/"); + FACTORIES[ByteCodeConstants.LDIV] = new BinaryOperatorFactory(3, "J", "/"); + FACTORIES[ByteCodeConstants.FDIV] = new BinaryOperatorFactory(3, "F", "/"); + FACTORIES[ByteCodeConstants.DDIV] = new BinaryOperatorFactory(3, "D", "/"); + FACTORIES[ByteCodeConstants.IREM] = new BinaryOperatorFactory(3, "I", "%"); + FACTORIES[ByteCodeConstants.LREM] = new BinaryOperatorFactory(3, "J", "%"); + FACTORIES[ByteCodeConstants.FREM] = new BinaryOperatorFactory(3, "F", "%"); + FACTORIES[ByteCodeConstants.DREM] = new BinaryOperatorFactory(3, "D", "%"); + FACTORIES[ByteCodeConstants.INEG] = new UnaryOperatorFactory(2, "I", "-"); + FACTORIES[ByteCodeConstants.LNEG] = new UnaryOperatorFactory(2, "J", "-"); + FACTORIES[ByteCodeConstants.FNEG] = new UnaryOperatorFactory(2, "F", "-"); + FACTORIES[ByteCodeConstants.DNEG] = new UnaryOperatorFactory(2, "D", "-"); + FACTORIES[ByteCodeConstants.ISHL] = new BinaryOperatorFactory(5, "I", "<<"); + FACTORIES[ByteCodeConstants.LSHL] = new BinaryOperatorFactory(5, "J", "<<"); + FACTORIES[ByteCodeConstants.ISHR] = new BinaryOperatorFactory(5, "I", ">>"); + FACTORIES[ByteCodeConstants.LSHR] = new BinaryOperatorFactory(5, "J", ">>"); + FACTORIES[ByteCodeConstants.IUSHR] = new BinaryOperatorFactory(5, "I", ">>>"); + FACTORIES[ByteCodeConstants.LUSHR] = new BinaryOperatorFactory(5, "J", ">>>"); + FACTORIES[ByteCodeConstants.IAND] = new IBinaryOperatorFactory(8, "&"); + FACTORIES[ByteCodeConstants.LAND] = new BinaryOperatorFactory(8, "J", "&"); + FACTORIES[ByteCodeConstants.IOR] = new IBinaryOperatorFactory(10, "|"); + FACTORIES[ByteCodeConstants.LOR] = new BinaryOperatorFactory(10, "J", "|"); + FACTORIES[ByteCodeConstants.IXOR] = new IBinaryOperatorFactory(9, "^"); + FACTORIES[ByteCodeConstants.LXOR] = new BinaryOperatorFactory(9, "J", "^"); + FACTORIES[ByteCodeConstants.IINC] = new IIncFactory(); + FACTORIES[ByteCodeConstants.I2L] = new ImplicitConvertInstructionFactory("J"); + FACTORIES[ByteCodeConstants.I2F] = new ImplicitConvertInstructionFactory("F"); + FACTORIES[ByteCodeConstants.I2D] = new ImplicitConvertInstructionFactory("D"); + FACTORIES[ByteCodeConstants.L2I] = new ConvertInstructionFactory("I"); + FACTORIES[ByteCodeConstants.L2F] = new ConvertInstructionFactory("F"); + FACTORIES[ByteCodeConstants.L2D] = FACTORIES[ByteCodeConstants.I2D]; + FACTORIES[ByteCodeConstants.F2I] = FACTORIES[ByteCodeConstants.L2I]; + FACTORIES[ByteCodeConstants.F2L] = new ConvertInstructionFactory("J"); + FACTORIES[ByteCodeConstants.F2D] = FACTORIES[ByteCodeConstants.I2D]; + FACTORIES[ByteCodeConstants.D2I] = FACTORIES[ByteCodeConstants.L2I]; + FACTORIES[ByteCodeConstants.D2L] = FACTORIES[ByteCodeConstants.F2L]; + FACTORIES[ByteCodeConstants.D2F] = FACTORIES[ByteCodeConstants.L2F]; + FACTORIES[ByteCodeConstants.I2B] = new ConvertInstructionFactory("B"); + FACTORIES[ByteCodeConstants.I2C] = new ConvertInstructionFactory("C"); + FACTORIES[ByteCodeConstants.I2S] = new ConvertInstructionFactory("S"); + FACTORIES[ByteCodeConstants.LCMP] = new CmpFactory(6, "Z", "<"); + FACTORIES[ByteCodeConstants.FCMPL] = FACTORIES[ByteCodeConstants.LCMP]; + FACTORIES[ByteCodeConstants.FCMPG] = FACTORIES[ByteCodeConstants.LCMP]; + FACTORIES[ByteCodeConstants.DCMPL] = FACTORIES[ByteCodeConstants.LCMP]; + FACTORIES[ByteCodeConstants.DCMPG] = FACTORIES[ByteCodeConstants.LCMP]; + FACTORIES[ByteCodeConstants.IFEQ] = new IfFactory(ByteCodeConstants.CMP_EQ); + FACTORIES[ByteCodeConstants.IFNE] = new IfFactory(ByteCodeConstants.CMP_NE); + FACTORIES[ByteCodeConstants.IFLT] = new IfFactory(ByteCodeConstants.CMP_LT); + FACTORIES[ByteCodeConstants.IFGE] = new IfFactory(ByteCodeConstants.CMP_GE); + FACTORIES[ByteCodeConstants.IFGT] = new IfFactory(ByteCodeConstants.CMP_GT); + FACTORIES[ByteCodeConstants.IFLE] = new IfFactory(ByteCodeConstants.CMP_LE); + FACTORIES[ByteCodeConstants.IF_ICMPEQ] = new IfCmpFactory(ByteCodeConstants.CMP_EQ); + FACTORIES[ByteCodeConstants.IF_ICMPNE] = new IfCmpFactory(ByteCodeConstants.CMP_NE); + FACTORIES[ByteCodeConstants.IF_ICMPLT] = new IfCmpFactory(ByteCodeConstants.CMP_LT); + FACTORIES[ByteCodeConstants.IF_ICMPGE] = new IfCmpFactory(ByteCodeConstants.CMP_GE); + FACTORIES[ByteCodeConstants.IF_ICMPGT] = new IfCmpFactory(ByteCodeConstants.CMP_GT); + FACTORIES[ByteCodeConstants.IF_ICMPLE] = new IfCmpFactory(ByteCodeConstants.CMP_LE); + FACTORIES[ByteCodeConstants.IF_ACMPEQ] = FACTORIES[ByteCodeConstants.IF_ICMPEQ]; + FACTORIES[ByteCodeConstants.IF_ACMPNE] = FACTORIES[ByteCodeConstants.IF_ICMPNE]; + FACTORIES[ByteCodeConstants.GOTO] = new GotoFactory(); + FACTORIES[ByteCodeConstants.JSR] = new JsrFactory(); + FACTORIES[ByteCodeConstants.RET] = new RetFactory(); + FACTORIES[ByteCodeConstants.TABLESWITCH] = new TableSwitchFactory(); + FACTORIES[ByteCodeConstants.LOOKUPSWITCH] = new LookupSwitchFactory(); + FACTORIES[ByteCodeConstants.IRETURN] = new ReturnInstructionFactory(); + FACTORIES[ByteCodeConstants.LRETURN] = FACTORIES[ByteCodeConstants.IRETURN]; + FACTORIES[ByteCodeConstants.FRETURN] = FACTORIES[ByteCodeConstants.IRETURN]; + FACTORIES[ByteCodeConstants.DRETURN] = FACTORIES[ByteCodeConstants.IRETURN]; + FACTORIES[ByteCodeConstants.ARETURN] = FACTORIES[ByteCodeConstants.IRETURN]; + FACTORIES[ByteCodeConstants.RETURN] = new ReturnFactory(); + FACTORIES[ByteCodeConstants.GETSTATIC] = new GetStaticFactory(); + FACTORIES[ByteCodeConstants.PUTSTATIC] = new PutStaticFactory(); + FACTORIES[ByteCodeConstants.GETFIELD] = new GetFieldFactory(); + FACTORIES[ByteCodeConstants.PUTFIELD] = new PutFieldFactory(); + FACTORIES[ByteCodeConstants.INVOKEVIRTUAL] = new InvokevirtualFactory(); + FACTORIES[ByteCodeConstants.INVOKESPECIAL] = new InvokespecialFactory(); + FACTORIES[ByteCodeConstants.INVOKESTATIC ] = new InvokestaticFactory(); + FACTORIES[ByteCodeConstants.INVOKEINTERFACE] = new InvokeinterfaceFactory(); + FACTORIES[ByteCodeConstants.NEW] = new NewFactory(); + FACTORIES[ByteCodeConstants.NEWARRAY] = new NewArrayFactory(); + FACTORIES[ByteCodeConstants.ANEWARRAY] = new ANewArrayFactory(); + FACTORIES[ByteCodeConstants.ARRAYLENGTH] = new ArrayLengthFactory(); + FACTORIES[ByteCodeConstants.ATHROW] = new AThrowFactory(); + FACTORIES[ByteCodeConstants.CHECKCAST] = new CheckCastFactory(); + FACTORIES[ByteCodeConstants.INSTANCEOF] = new InstanceOfFactory(); + FACTORIES[ByteCodeConstants.MONITORENTER] = new MonitorEnterFactory(); + FACTORIES[ByteCodeConstants.MONITOREXIT] = new MonitorExitFactory(); + FACTORIES[ByteCodeConstants.WIDE] = new WideFactory(); + FACTORIES[ByteCodeConstants.MULTIANEWARRAY] = new MultiANewArrayFactory(); + FACTORIES[ByteCodeConstants.IFNULL] = new IfXNullFactory(ByteCodeConstants.CMP_EQ); + FACTORIES[ByteCodeConstants.IFNONNULL] = new IfXNullFactory(ByteCodeConstants.CMP_NE); + FACTORIES[ByteCodeConstants.GOTO_W] = new GotoWFactory(); + FACTORIES[ByteCodeConstants.JSR_W] = new JsrWFactory(); + + /** + * Non-legal opcodes, may be used by JVM internally. + */ +// public static final int BREAKPOINT = 202; +// public static final int LDC_QUICK = 203; +// public static final int LDC_W_QUICK = 204; +// public static final int LDC2_W_QUICK = 205; +// public static final int GETFIELD_QUICK = 206; +// public static final int PUTFIELD_QUICK = 207; +// public static final int GETFIELD2_QUICK = 208; +// public static final int PUTFIELD2_QUICK = 209; +// public static final int GETSTATIC_QUICK = 210; +// public static final int PUTSTATIC_QUICK = 211; +// public static final int GETSTATIC2_QUICK = 212; +// public static final int PUTSTATIC2_QUICK = 213; +// public static final int INVOKEVIRTUAL_QUICK = 214; +// public static final int INVOKENONVIRTUAL_QUICK = 215; +// public static final int INVOKESUPER_QUICK = 216; +// public static final int INVOKESTATIC_QUICK = 217; +// public static final int INVOKEINTERFACE_QUICK = 218; +// public static final int INVOKEVIRTUALOBJECT_QUICK = 219; +// public static final int NEW_QUICK = 221; +// public static final int ANEWARRAY_QUICK = 222; +// public static final int MULTIANEWARRAY_QUICK = 223; +// public static final int CHECKCAST_QUICK = 224; +// public static final int INSTANCEOF_QUICK = 225; +// public static final int INVOKEVIRTUAL_QUICK_W = 226; +// public static final int GETFIELD_QUICK_W = 227; +// public static final int PUTFIELD_QUICK_W = 228; +// public static final int IMPDEP1 = 254; +// public static final int IMPDEP2 = 255; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/InvokeinterfaceFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/InvokeinterfaceFactory.java new file mode 100644 index 00000000..5fc46b93 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/InvokeinterfaceFactory.java @@ -0,0 +1,57 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.classfile.constant.ConstantInterfaceMethodref; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.Invokeinterface; +import jd.core.util.InvalidParameterException; + + +public class InvokeinterfaceFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + final int index = ((code[offset+1] & 255) << 8) | (code[offset+2] & 255); + // Ignore final int count = code[offset+3] & 255; // + + ConstantInterfaceMethodref cimr = + classFile.getConstantPool().getConstantInterfaceMethodref(index); + if (cimr == null) + throw new InvalidParameterException( + "Invalid ConstantInterfaceMethodref index"); + + int nbrOfParameters = cimr.getNbrOfParameters(); + ArrayList args = new ArrayList(nbrOfParameters); + + for (int i=nbrOfParameters; i>0; --i) + args.add(stack.pop()); + + Collections.reverse(args); + + Instruction objectref = stack.pop(); + + final Instruction instruction = new Invokeinterface( + opcode, offset, lineNumber, index, objectref, args); + + if (cimr.returnAResult()) + stack.push(instruction); + else + list.add(instruction); + + listForAnalyze.add(instruction); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/InvokespecialFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/InvokespecialFactory.java new file mode 100644 index 00000000..ad40a3a0 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/InvokespecialFactory.java @@ -0,0 +1,56 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.classfile.constant.ConstantMethodref; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.Invokespecial; +import jd.core.util.InvalidParameterException; + + +public class InvokespecialFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + final int index = ((code[offset+1] & 255) << 8) | (code[offset+2] & 255); + + ConstantMethodref cmr = + classFile.getConstantPool().getConstantMethodref(index); + if (cmr == null) + throw new InvalidParameterException( + "Invalid ConstantMethodref index"); + + int nbrOfParameters = cmr.getNbrOfParameters(); + ArrayList args = new ArrayList(nbrOfParameters); + + for (int i=nbrOfParameters; i>0; --i) + args.add(stack.pop()); + + Collections.reverse(args); + + Instruction objectref = stack.pop(); + + final Instruction instruction = new Invokespecial( + opcode, offset, lineNumber, index, objectref, args); + + if (cmr.returnAResult()) + stack.push(instruction); + else + list.add(instruction); + + listForAnalyze.add(instruction); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/InvokestaticFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/InvokestaticFactory.java new file mode 100644 index 00000000..f7ff2d6a --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/InvokestaticFactory.java @@ -0,0 +1,54 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.classfile.constant.ConstantMethodref; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.Invokestatic; +import jd.core.util.InvalidParameterException; + + +public class InvokestaticFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + final int index = ((code[offset+1] & 255) << 8) | (code[offset+2] & 255); + + ConstantMethodref cmr = + classFile.getConstantPool().getConstantMethodref(index); + if (cmr == null) + throw new InvalidParameterException( + "Invalid ConstantMethodref index"); + + int nbrOfParameters = cmr.getNbrOfParameters(); + ArrayList args = new ArrayList(nbrOfParameters); + + for (int i=nbrOfParameters; i>0; --i) + args.add(stack.pop()); + + Collections.reverse(args); + + final Instruction instruction = new Invokestatic( + opcode, offset, lineNumber, index, args); + + if (cmr.returnAResult()) + stack.push(instruction); + else + list.add(instruction); + + listForAnalyze.add(instruction); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/InvokevirtualFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/InvokevirtualFactory.java new file mode 100644 index 00000000..688d3db3 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/InvokevirtualFactory.java @@ -0,0 +1,56 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.classfile.constant.ConstantMethodref; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.Invokevirtual; +import jd.core.util.InvalidParameterException; + + +public class InvokevirtualFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + final int index = ((code[offset+1] & 255) << 8) | (code[offset+2] & 255); + + ConstantMethodref cmr = + classFile.getConstantPool().getConstantMethodref(index); + if (cmr == null) + throw new InvalidParameterException( + "Invalid ConstantMethodref index"); + + int nbrOfParameters = cmr.getNbrOfParameters(); + ArrayList args = new ArrayList(nbrOfParameters); + + for (int i=nbrOfParameters; i>0; --i) + args.add(stack.pop()); + + Collections.reverse(args); + + Instruction objectref = stack.pop(); + + final Instruction instruction = new Invokevirtual( + opcode, offset, lineNumber, index, objectref, args); + + if (cmr.returnAResult()) + stack.push(instruction); + else + list.add(instruction); + + listForAnalyze.add(instruction); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/JsrFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/JsrFactory.java new file mode 100644 index 00000000..9708b7ea --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/JsrFactory.java @@ -0,0 +1,29 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.Jsr; + + +public class JsrFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + final int value = + (short)(((code[offset+1] & 255) << 8) | (code[offset+2] & 255)); + + list.add(new Jsr(opcode, offset, lineNumber, value)); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/JsrWFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/JsrWFactory.java new file mode 100644 index 00000000..3764aa39 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/JsrWFactory.java @@ -0,0 +1,30 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.Jsr; + + +public class JsrWFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + final int value = + ((code[offset+1] & 255) << 24) | ((code[offset+2] & 255) << 16) | + ((code[offset+3] & 255) << 8) | (code[offset+4] & 255); + + list.add(new Jsr(ByteCodeConstants.JSR, offset, lineNumber, value)); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/LConstFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/LConstFactory.java new file mode 100644 index 00000000..39dd444c --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/LConstFactory.java @@ -0,0 +1,29 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.LConst; + + +public class LConstFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + final int value = opcode - ByteCodeConstants.LCONST_0; + + stack.push(new LConst( + ByteCodeConstants.LCONST, offset, lineNumber, value)); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/LLoadFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/LLoadFactory.java new file mode 100644 index 00000000..bb5d3171 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/LLoadFactory.java @@ -0,0 +1,37 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.LoadInstruction; + + +public class LLoadFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + int index; + + if (opcode == ByteCodeConstants.LLOAD) + index = code[offset+1] & 255; + else + index = opcode - ByteCodeConstants.LLOAD_0; + + final Instruction instruction = new LoadInstruction( + ByteCodeConstants.LOAD, offset, lineNumber, index, "J"); + + stack.push(instruction); + listForAnalyze.add(instruction); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/LStoreFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/LStoreFactory.java new file mode 100644 index 00000000..052a68d7 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/LStoreFactory.java @@ -0,0 +1,38 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.StoreInstruction; + + +public class LStoreFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + int index; + + if (opcode == ByteCodeConstants.LSTORE) + index = code[offset+1] & 255; + else + index = opcode - ByteCodeConstants.LSTORE_0; + + final Instruction instruction = new StoreInstruction( + ByteCodeConstants.STORE, offset, lineNumber, + index, "J", stack.pop()); + + list.add(instruction); + listForAnalyze.add(instruction); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/Ldc2WFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/Ldc2WFactory.java new file mode 100644 index 00000000..618512c8 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/Ldc2WFactory.java @@ -0,0 +1,28 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.Ldc2W; + + +public class Ldc2WFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + final int index = ((code[offset+1] & 255) << 8) | (code[offset+2] & 255); + + stack.push(new Ldc2W(opcode, offset, lineNumber, index)); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/LdcFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/LdcFactory.java new file mode 100644 index 00000000..12243beb --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/LdcFactory.java @@ -0,0 +1,28 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.Ldc; + + +public class LdcFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + final int index = code[offset+1] & 255; + + stack.push(new Ldc(ByteCodeConstants.LDC, offset, lineNumber, index)); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/LdcWFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/LdcWFactory.java new file mode 100644 index 00000000..86da5efc --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/LdcWFactory.java @@ -0,0 +1,28 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.Ldc; + + +public class LdcWFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + final int index = ((code[offset+1] & 255) << 8) | (code[offset+2] & 255); + + stack.push(new Ldc(ByteCodeConstants.LDC, offset, lineNumber, index)); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/LookupSwitchFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/LookupSwitchFactory.java new file mode 100644 index 00000000..c7b8d9e0 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/LookupSwitchFactory.java @@ -0,0 +1,62 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.LookupSwitch; + + +public class LookupSwitchFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + + // Skip padding + int i = (offset+4) & 0xFFFC; + + final int defaultOffset = + ((code[i ] & 255) << 24) | ((code[i+1] & 255) << 16) | + ((code[i+2] & 255) << 8 ) | (code[i+3] & 255); + + i += 4; + + final int npairs = + ((code[i ] & 255) << 24) | ((code[i+1] & 255) << 16) | + ((code[i+2] & 255) << 8 ) | (code[i+3] & 255); + + i += 4; + + int[] keys = new int[npairs]; + int[] offsets = new int[npairs]; + + for (int j=0; j list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + + MonitorEnter me = new MonitorEnter(opcode, offset, lineNumber, stack.pop()); + list.add(me); + listForAnalyze.add(me); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/MonitorExitFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/MonitorExitFactory.java new file mode 100644 index 00000000..bee2d6c2 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/MonitorExitFactory.java @@ -0,0 +1,29 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.MonitorExit; + + +public class MonitorExitFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + + MonitorExit me = new MonitorExit(opcode, offset, lineNumber, stack.pop()); + list.add(me); + listForAnalyze.add(me); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/MultiANewArrayFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/MultiANewArrayFactory.java new file mode 100644 index 00000000..c2612627 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/MultiANewArrayFactory.java @@ -0,0 +1,37 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.MultiANewArray; + + +public class MultiANewArrayFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + final int index = ((code[offset+1] & 255) << 8) | (code[offset+2] & 255); + final int count = code[offset+3] & 255; + final Instruction[] dimensions = new Instruction[count]; + + for (int i=0; i list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + final Instruction instruction = new NewArray( + opcode, offset, lineNumber, code[offset+1] & 255, stack.pop()); + + stack.push(instruction); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/NewFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/NewFactory.java new file mode 100644 index 00000000..3bc6d16c --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/NewFactory.java @@ -0,0 +1,31 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.New; + + +public class NewFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + final int index = ((code[offset+1] & 255) << 8) | (code[offset+2] & 255); + final Instruction instruction = new New( + opcode, offset, lineNumber, index); + + stack.push(instruction); + listForAnalyze.add(instruction); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/Pop2Factory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/Pop2Factory.java new file mode 100644 index 00000000..671417a1 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/Pop2Factory.java @@ -0,0 +1,28 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.Pop; + + +public class Pop2Factory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + + list.add(new Pop( + ByteCodeConstants.POP, offset, lineNumber, stack.pop())); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/PopFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/PopFactory.java new file mode 100644 index 00000000..f2f80bf7 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/PopFactory.java @@ -0,0 +1,28 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.Pop; + + +public class PopFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + + list.add(new Pop( + ByteCodeConstants.POP, offset, lineNumber, stack.pop())); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/PutFieldFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/PutFieldFactory.java new file mode 100644 index 00000000..b850ab1f --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/PutFieldFactory.java @@ -0,0 +1,34 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.PutField; + + +public class PutFieldFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + final int index = ((code[offset+1] & 255) << 8) | (code[offset+2] & 255); + final Instruction value = stack.pop(); + final Instruction objectref = stack.pop(); + + final Instruction instruction = new PutField( + opcode, offset, lineNumber, index, objectref, value); + + list.add(instruction); + listForAnalyze.add(instruction); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/PutStaticFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/PutStaticFactory.java new file mode 100644 index 00000000..96147908 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/PutStaticFactory.java @@ -0,0 +1,33 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.PutStatic; + + +public class PutStaticFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + final int index = ((code[offset+1] & 255) << 8) | (code[offset+2] & 255); + final Instruction value = stack.pop(); + + final Instruction instruction = new PutStatic( + opcode, offset, lineNumber, index, value); + + list.add(instruction); + listForAnalyze.add(instruction); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/RetFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/RetFactory.java new file mode 100644 index 00000000..92612577 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/RetFactory.java @@ -0,0 +1,28 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.Ret; + + +public class RetFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + final int index = code[offset+1] & 255; + + list.add(new Ret(opcode, offset, lineNumber, index)); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/ReturnFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/ReturnFactory.java new file mode 100644 index 00000000..47c6585d --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/ReturnFactory.java @@ -0,0 +1,27 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.Return; + + +public class ReturnFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + + list.add(new Return(opcode, offset, lineNumber)); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/ReturnInstructionFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/ReturnInstructionFactory.java new file mode 100644 index 00000000..1d2a7d10 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/ReturnInstructionFactory.java @@ -0,0 +1,31 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.ReturnInstruction; + + +public class ReturnInstructionFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + + ReturnInstruction ri = new ReturnInstruction( + ByteCodeConstants.XRETURN, offset, lineNumber, stack.pop()); + + list.add(ri); + listForAnalyze.add(ri); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/SIPushFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/SIPushFactory.java new file mode 100644 index 00000000..ac7b31e1 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/SIPushFactory.java @@ -0,0 +1,28 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.SIPush; + + +public class SIPushFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + final int s = ((code[offset+1] & 0xFF) << 8) | (code[offset+2] & 0xFF); + + stack.push(new SIPush(opcode, offset, lineNumber, s)); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/SwapFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/SwapFactory.java new file mode 100644 index 00000000..27d30276 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/SwapFactory.java @@ -0,0 +1,30 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + +public class SwapFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + + Instruction i1 = stack.pop(); + Instruction i2 = stack.pop(); + + stack.push(i1); + stack.push(i2); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/TableSwitchFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/TableSwitchFactory.java new file mode 100644 index 00000000..b9671d94 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/TableSwitchFactory.java @@ -0,0 +1,63 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.TableSwitch; + + +public class TableSwitchFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + + // Skip padding + int i = (offset+4) & 0xFFFC; + + final int defaultOffset = + ((code[i ] & 255) << 24) | ((code[i+1] & 255) << 16) | + ((code[i+2] & 255) << 8 ) | (code[i+3] & 255); + + i += 4; + + final int low = + ((code[i ] & 255) << 24) | ((code[i+1] & 255) << 16) | + ((code[i+2] & 255) << 8 ) | (code[i+3] & 255); + + i += 4; + + final int high = + ((code[i ] & 255) << 24) | ((code[i+1] & 255) << 16) | + ((code[i+2] & 255) << 8 ) | (code[i+3] & 255); + + i += 4; + + int length = high - low + 1; + int[] offsets = new int[length]; + + for (int j=0; j list, + List listForAnalyze, Stack stack, + byte[] code, int offset, int lineNumber, boolean[] jumps) + { + final int opcode = code[offset] & 255; + final Instruction i = stack.pop(); + + stack.push(new UnaryOperatorInstruction( + ByteCodeConstants.UNARYOP, offset, lineNumber, this.priority, + this.signature, this.operator, i)); + + return ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/UnexpectedOpcodeException.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/UnexpectedOpcodeException.java new file mode 100644 index 00000000..21133da0 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/UnexpectedOpcodeException.java @@ -0,0 +1,12 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + + +public class UnexpectedOpcodeException extends RuntimeException +{ + private static final long serialVersionUID = -3407799517256621265L; + + public UnexpectedOpcodeException(int opcode) + { + super(String.valueOf(opcode)); + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/factory/WideFactory.java b/src/jd/core/process/analyzer/instruction/bytecode/factory/WideFactory.java new file mode 100644 index 00000000..50823cdb --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/factory/WideFactory.java @@ -0,0 +1,118 @@ +package jd.core.process.analyzer.instruction.bytecode.factory; + +import java.util.List; +import java.util.Stack; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.ALoad; +import jd.core.model.instruction.bytecode.instruction.AStore; +import jd.core.model.instruction.bytecode.instruction.IInc; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.LoadInstruction; +import jd.core.model.instruction.bytecode.instruction.Ret; +import jd.core.model.instruction.bytecode.instruction.StoreInstruction; + + +public class WideFactory extends InstructionFactory +{ + public int create( + ClassFile classFile, Method method, List list, + List listForAnalyze, + Stack stack, byte[] code, int offset, + int lineNumber, boolean[] jumps) + { + final int opcode = code[offset+1] & 255; + final int index = ((code[offset+2] & 255) << 8) | (code[offset+3] & 255); + + if (opcode == ByteCodeConstants.IINC) + { + final int count = + (short)(((code[offset+4] & 255) << 8) | (code[offset+5] & 255)); + Instruction instruction = new IInc( + opcode, offset, lineNumber, index, count); + + list.add(instruction); + listForAnalyze.add(instruction); + + return 5; + } + else + { + if (opcode == ByteCodeConstants.RET) + { + list.add(new Ret(opcode, offset, lineNumber, index)); + } + else + { + Instruction instruction = null; + + switch (opcode) + { + case ByteCodeConstants.ILOAD: + instruction = new LoadInstruction( + ByteCodeConstants.ILOAD, offset, lineNumber, index, "I"); + stack.push(instruction); + break; + case ByteCodeConstants.FLOAD: + instruction = new LoadInstruction( + ByteCodeConstants.LOAD, offset, lineNumber, index, "F"); + stack.push(instruction); + break; + case ByteCodeConstants.ALOAD: + instruction = new ALoad( + ByteCodeConstants.ALOAD, offset, lineNumber, index); + stack.push(instruction); + break; + case ByteCodeConstants.LLOAD: + instruction = new LoadInstruction( + ByteCodeConstants.LOAD, offset, lineNumber, index, "J"); + stack.push(instruction); + break; + case ByteCodeConstants.DLOAD: + instruction = new LoadInstruction( + ByteCodeConstants.LOAD, offset, lineNumber, index, "D"); + stack.push(instruction); + break; + case ByteCodeConstants.ISTORE: + instruction = new StoreInstruction( + ByteCodeConstants.ISTORE, offset, lineNumber, + index, "I", stack.pop()); + list.add(instruction); + break; + case ByteCodeConstants.FSTORE: + instruction = new StoreInstruction( + ByteCodeConstants.STORE, offset, lineNumber, + index, "F", stack.pop()); + list.add(instruction); + break; + case ByteCodeConstants.ASTORE: + instruction = new AStore( + ByteCodeConstants.ASTORE, offset, lineNumber, + index, stack.pop()); + list.add(instruction); + break; + case ByteCodeConstants.LSTORE: + instruction = new StoreInstruction( + ByteCodeConstants.STORE, offset, lineNumber, + index, "J", stack.pop()); + list.add(instruction); + break; + case ByteCodeConstants.DSTORE: + instruction = new StoreInstruction( + ByteCodeConstants.STORE, offset, lineNumber, + index, "D", stack.pop()); + list.add(instruction); + break; + default: + throw new UnexpectedOpcodeException(opcode); + } + + listForAnalyze.add(instruction); + } + + return 2; + } + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/reconstructor/AssertInstructionReconstructor.java b/src/jd/core/process/analyzer/instruction/bytecode/reconstructor/AssertInstructionReconstructor.java new file mode 100644 index 00000000..5ce0fab4 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/reconstructor/AssertInstructionReconstructor.java @@ -0,0 +1,104 @@ +package jd.core.process.analyzer.instruction.bytecode.reconstructor; + +import java.util.List; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.constant.ConstantFieldref; +import jd.core.model.classfile.constant.ConstantMethodref; +import jd.core.model.classfile.constant.ConstantNameAndType; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.AThrow; +import jd.core.model.instruction.bytecode.instruction.AssertInstruction; +import jd.core.model.instruction.bytecode.instruction.ComplexConditionalBranchInstruction; +import jd.core.model.instruction.bytecode.instruction.GetStatic; +import jd.core.model.instruction.bytecode.instruction.IfInstruction; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.InvokeNew; + + +/* + * Recontruction des des instructions 'assert' depuis le motif : + * ... + * complexif( (!($assertionsDisabled)) && (test) ) + * athrow( newinvoke( classindex="AssertionError", args=["msg"] )); + * ... + */ +public class AssertInstructionReconstructor +{ + public static void Reconstruct(ClassFile classFile, List list) + { + int index = list.size(); + if (index-- == 0) + return; + + while (index-- > 1) + { + Instruction instruction = list.get(index); + + if (instruction.opcode != ByteCodeConstants.ATHROW) + continue; + + // AThrow trouve + AThrow athrow = (AThrow)instruction; + if (athrow.value.opcode != ByteCodeConstants.INVOKENEW) + continue; + + instruction = list.get(index-1); + if (instruction.opcode != ByteCodeConstants.COMPLEXIF) + continue; + + // ComplexConditionalBranchInstruction trouve + ComplexConditionalBranchInstruction cbl = + (ComplexConditionalBranchInstruction)instruction; + int jumpOffset = cbl.GetJumpOffset(); + int lastOffset = list.get(index+1).offset; + + if ((athrow.offset >= jumpOffset) || (jumpOffset > lastOffset)) + continue; + + if ((cbl.cmp != 2) || (cbl.instructions.size() < 1)) + continue; + + instruction = cbl.instructions.get(0); + if (instruction.opcode != ByteCodeConstants.IF) + continue; + + IfInstruction if1 = (IfInstruction)instruction; + if ((if1.cmp != 7) || (if1.value.opcode != ByteCodeConstants.GETSTATIC)) + continue; + + GetStatic gs = (GetStatic)if1.value; + ConstantPool constants = classFile.getConstantPool(); + ConstantFieldref cfr = constants.getConstantFieldref(gs.index); + + if (cfr.class_index != classFile.getThisClassIndex()) + continue; + + ConstantNameAndType cnat = + constants.getConstantNameAndType(cfr.name_and_type_index); + String fieldName = constants.getConstantUtf8(cnat.name_index); + + if (! fieldName.equals("$assertionsDisabled")) + continue; + + InvokeNew in = (InvokeNew)athrow.value; + ConstantMethodref cmr = + constants.getConstantMethodref(in.index); + String className = constants.getConstantClassName(cmr.class_index); + + if (! className.equals("java/lang/AssertionError")) + continue; + + // Remove first condition "!($assertionsDisabled)" + cbl.instructions.remove(0); + + Instruction msg = (in.args.size() == 0) ? null : in.args.get(0); + list.remove(index--); + + list.set(index, new AssertInstruction( + ByteCodeConstants.ASSERT, athrow.offset, + cbl.lineNumber, cbl, msg)); + } + } +} diff --git a/src/jd/core/process/analyzer/instruction/bytecode/util/ByteCodeUtil.java b/src/jd/core/process/analyzer/instruction/bytecode/util/ByteCodeUtil.java new file mode 100644 index 00000000..656b9373 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/bytecode/util/ByteCodeUtil.java @@ -0,0 +1,103 @@ +package jd.core.process.analyzer.instruction.bytecode.util; + +import jd.core.model.instruction.bytecode.ByteCodeConstants; + + +public class ByteCodeUtil +{ + public static int NextTableSwitchOffset(byte[] code, int index) + { + // Skip padding + int i = (index+4) & 0xFFFC; + + i += 4; + + final int low = + ((code[i ] & 255) << 24) | ((code[i+1] & 255) << 16) | + ((code[i+2] & 255) << 8 ) | (code[i+3] & 255); + + i += 4; + + final int high = + ((code[i ] & 255) << 24) | ((code[i+1] & 255) << 16) | + ((code[i+2] & 255) << 8 ) | (code[i+3] & 255); + + i += 4; + i += 4 * (high - low + 1); + + return i - 1; + } + + public static int NextLookupSwitchOffset(byte[] code, int index) + { + // Skip padding + int i = (index+4) & 0xFFFC; + + i += 4; + + final int npairs = + ((code[i ] & 255) << 24) | ((code[i+1] & 255) << 16) | + ((code[i+2] & 255) << 8 ) | (code[i+3] & 255); + + i += 4; + i += 8*npairs; + + return i - 1; + } + + public static int NextWideOffset(byte[] code, int index) + { + final int opcode = code[index+1] & 255; + + return index + ((opcode == ByteCodeConstants.IINC) ? 5 : 3); + } + + public static int NextInstructionOffset(byte[] code, int index) + { + final int opcode = code[index] & 255; + + switch (opcode) + { + case ByteCodeConstants.TABLESWITCH: + return NextTableSwitchOffset(code, index); + + case ByteCodeConstants.LOOKUPSWITCH: + return NextLookupSwitchOffset(code, index); + + case ByteCodeConstants.WIDE: + return NextWideOffset(code, index); + + default: + return index + 1 + ByteCodeConstants.NO_OF_OPERANDS[opcode]; + } + } + + public static boolean JumpTo(byte[] code, int offset, int targetOffset) { + if (offset != -1) { + int codeLength = code.length; + + for (int i = 0; i < 10; i++) { + if (offset == targetOffset) { + return true; + } else { + if (offset >= codeLength) + break; + + int opcode = code[offset] & 255; + + if (opcode == ByteCodeConstants.GOTO) { + offset += (short) (((code[offset + 1] & 255) << 8) | (code[offset + 2] & 255)); + } else if (opcode == ByteCodeConstants.GOTO_W) { + + offset += ((code[offset + 1] & 255) << 24) | ((code[offset + 2] & 255) << 16) + | ((code[offset + 3] & 255) << 8) | (code[offset + 4] & 255); + } else { + break; + } + } + } + } + + return false; + } +} diff --git a/src/jd/core/process/analyzer/instruction/fast/DupLocalVariableAnalyzer.java b/src/jd/core/process/analyzer/instruction/fast/DupLocalVariableAnalyzer.java new file mode 100644 index 00000000..9d5572ac --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/fast/DupLocalVariableAnalyzer.java @@ -0,0 +1,141 @@ +package jd.core.process.analyzer.instruction.fast; + +import java.util.List; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariable; +import jd.core.model.classfile.LocalVariables; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.DupStore; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.fast.FastConstants; +import jd.core.model.instruction.fast.instruction.FastDeclaration; +import jd.core.model.instruction.fast.instruction.FastList; +import jd.core.model.instruction.fast.instruction.FastSwitch; +import jd.core.model.instruction.fast.instruction.FastTest2Lists; +import jd.core.model.instruction.fast.instruction.FastTry; +import jd.core.util.StringConstants; + + + +public class DupLocalVariableAnalyzer +{ + public static void Declare( + ClassFile classFile, Method method, List list) + { + RecursiveDeclare( + classFile.getConstantPool(), method.getLocalVariables(), + method.getCode().length, list); + } + + private static void RecursiveDeclare( + ConstantPool constants, + LocalVariables localVariables, + int codeLength, + List list) + { + int length = list.size(); + + // Appels recursifs + for (int index=0; index instructions = + ((FastList)instruction).instructions; + if (instructions != null) + RecursiveDeclare( + constants, localVariables, codeLength, instructions); + } + break; + + case FastConstants.IF_ELSE: + { + FastTest2Lists ft2l = (FastTest2Lists)instruction; + RecursiveDeclare( + constants, localVariables, codeLength, ft2l.instructions); + RecursiveDeclare( + constants, localVariables, codeLength, ft2l.instructions2); + } + break; + + case FastConstants.SWITCH: + case FastConstants.SWITCH_ENUM: + case FastConstants.SWITCH_STRING: + { + FastSwitch.Pair[] pairs = ((FastSwitch)instruction).pairs; + if (pairs != null) + for (int i=pairs.length-1; i>=0; --i) + { + List instructions = pairs[i].getInstructions(); + if (instructions != null) + RecursiveDeclare( + constants, localVariables, codeLength, instructions); + } + } + break; + + case FastConstants.TRY: + { + FastTry ft = (FastTry)instruction; + RecursiveDeclare( + constants, localVariables, codeLength, ft.instructions); + + if (ft.catches != null) + for (int i=ft.catches.size()-1; i>=0; --i) + RecursiveDeclare( + constants, localVariables, + codeLength, ft.catches.get(i).instructions); + + if (ft.finallyInstructions != null) + RecursiveDeclare( + constants, localVariables, + codeLength, ft.finallyInstructions); + } + } + } + + // Declaration des variables locales temporaires + for (int i=0; i AggregateCodeExceptions( + Method method, List list) + { + CodeException[] arrayOfCodeException = method.getCodeExceptions(); + + if ((arrayOfCodeException == null) || (arrayOfCodeException.length == 0)) + return null; + + // Aggregation des 'finally' et des 'catch' executant le meme bloc + List fastAggregatedCodeExceptions = + new ArrayList( + arrayOfCodeException.length); + PopulateListOfFastAggregatedCodeException( + method, list, fastAggregatedCodeExceptions); + + int length = fastAggregatedCodeExceptions.size(); + ArrayList fastCodeExceptions = + new ArrayList(length); + + // Aggregation des blocs 'finally' aux blocs 'catch' + // Add first + fastCodeExceptions.add(NewFastCodeException( + list, fastAggregatedCodeExceptions.get(0))); + + // Add or update + for (int i=1; i Add new entry + fastCodeExceptions.add(NewFastCodeException( + list, fastAggregatedCodeException)); + } + + // Sort by 1)tryFromOffset 2)maxOffset 3)tryToOffset + // Necessaire pour le calcul de 'afterOffset' des structures try-catch + // par 'ComputeAfterOffset' + Collections.sort(fastCodeExceptions); + + // Aggregation des blocs 'catch' + // Reduce of FastCodeException after UpdateFastCodeException(...) + for (int i=fastCodeExceptions.size()-1; i>=1; --i) + { + FastCodeException fce1 = fastCodeExceptions.get(i); + FastCodeException fce2 = fastCodeExceptions.get(i-1); + + if ((fce1.tryFromOffset == fce2.tryFromOffset) && + (fce1.tryToOffset == fce2.tryToOffset) && + (fce1.synchronizedFlag == fce2.synchronizedFlag) && + ((fce1.afterOffset == UtilConstants.INVALID_OFFSET) || (fce1.afterOffset > fce2.maxOffset)) && + ((fce2.afterOffset == UtilConstants.INVALID_OFFSET) || (fce2.afterOffset > fce1.maxOffset))) + { + // Append catches + fce2.catches.addAll(fce1.catches); + Collections.sort(fce2.catches); + // Append finally + if (fce2.nbrFinally == 0) + { + fce2.finallyFromOffset = fce1.finallyFromOffset; + fce2.nbrFinally = fce1.nbrFinally; + } + // Update 'maxOffset' + if (fce2.maxOffset < fce1.maxOffset) + fce2.maxOffset = fce1.maxOffset; + // Update 'afterOffset' + if ((fce2.afterOffset == UtilConstants.INVALID_OFFSET) || + ((fce1.afterOffset != UtilConstants.INVALID_OFFSET) && + (fce1.afterOffset < fce2.afterOffset))) + fce2.afterOffset = fce1.afterOffset; + // Remove last FastCodeException + fastCodeExceptions.remove(i); + } + } + + // Search 'switch' instructions, sort case offset + ArrayList switchCaseOffsets = SearchSwitchCaseOffsets(list); + + for (int i=fastCodeExceptions.size()-1; i>=0; --i) + { + FastCodeException fce = fastCodeExceptions.get(i); + + // Determine type + DefineType(list, fce); + + if (fce.type == FastConstants.TYPE_UNDEFINED) + System.err.println("Undefined type catch"); + + // Compute afterOffset + ComputeAfterOffset( + method, list, switchCaseOffsets, fastCodeExceptions, fce, i); + + length = list.size(); + if ((fce.afterOffset == UtilConstants.INVALID_OFFSET) && (length > 0)) + { + Instruction lastInstruction = list.get(length-1); + fce.afterOffset = lastInstruction.offset; + + if ((lastInstruction.opcode != ByteCodeConstants.RETURN) && + (lastInstruction.opcode != ByteCodeConstants.XRETURN)) + // Set afterOffset to a virtual instruction after list. + fce.afterOffset++; + } + } + + // Sort by 1)tryFromOffset 2)maxOffset 3)tryToOffset + Collections.sort(fastCodeExceptions); + + return fastCodeExceptions; + } + + private static void PopulateListOfFastAggregatedCodeException( + Method method, List list, + List fastAggregatedCodeExceptions) + { + int length = method.getCode().length; + if (length == 0) + return; + + FastAggregatedCodeException[] array = + new FastAggregatedCodeException[length]; + + CodeException[] arrayOfCodeException = method.getCodeExceptions(); + length = arrayOfCodeException.length; + for (int i=0; i 0) + { + FastAggregatedCodeException face = + fastAggregatedCodeExceptions.get(i); + + if ((face.catch_type == 0) && IsASynchronizedBlock(list, face)) + { + face.synchronizedFlag = true; + } + } + } + + private static boolean IsNotAlreadyStored( + FastAggregatedCodeException face, int catch_type) + { + if (face.catch_type == catch_type) + return false; + + if (face.otherCatchTypes != null) + { + int i = face.otherCatchTypes.length; + + while (i-- > 0) + { + if (face.otherCatchTypes[i] == catch_type) + return false; + } + } + + return true; + } + + private static boolean IsASynchronizedBlock( + List list, FastAggregatedCodeException face) + { + int index = InstructionUtil.getIndexForOffset(list, face.start_pc); + + if (index == -1) + return false; + + if (list.get(index).opcode == ByteCodeConstants.MONITOREXIT) + { + // Cas particulier Jikes 1.2.2 + return true; + } + + if (index < 1) + return false; + + /* Recherche si le bloc finally contient une instruction + * monitorexit ayant le meme index que l'instruction + * monitorenter avant le bloc try. + * Byte code++: + * 5: System.out.println("start"); + * 8: localTestSynchronize = this + * 11: monitorenter (localTestSynchronize); <---- + * 17: System.out.println("in synchronized"); + * 21: monitorexit localTestSynchronize; + * 22: goto 30; + * 25: localObject2 = finally; + * 27: monitorexit localTestSynchronize; <==== + * 29: throw localObject1; + * 35: System.out.println("end"); + * 38: return; + */ + Instruction instruction = list.get(index-1); + + if (instruction.opcode != ByteCodeConstants.MONITORENTER) + return false; + + int varMonitorIndex; + MonitorEnter monitorEnter = (MonitorEnter)instruction; + + switch (monitorEnter.objectref.opcode) + { + case ByteCodeConstants.ALOAD: + { + if (index < 2) + return false; + instruction = list.get(index-2); + if (instruction.opcode != ByteCodeConstants.ASTORE) + return false; + AStore astore = (AStore)instruction; + varMonitorIndex = astore.index; + } + break; + case ByteCodeConstants.ASSIGNMENT: + { + AssignmentInstruction ai = + (AssignmentInstruction)monitorEnter.objectref; + if (ai.value1.opcode != ByteCodeConstants.ALOAD) + return false; + ALoad aload = (ALoad)ai.value1; + varMonitorIndex = aload.index; + } + break; + default: + return false; + } + + boolean checkMonitorExit = false; + int length = list.size(); + index = InstructionUtil.getIndexForOffset(list, face.handler_pc); + + while (index < length) + { + instruction = list.get(index++); + + switch (instruction.opcode) + { + case ByteCodeConstants.MONITOREXIT: + checkMonitorExit = true; + MonitorExit monitorExit = (MonitorExit)instruction; + + if ((monitorExit.objectref.opcode == ByteCodeConstants.ALOAD) && + (((ALoad)monitorExit.objectref).index == varMonitorIndex)) + return true; + break; + case ByteCodeConstants.RETURN: + case ByteCodeConstants.XRETURN: + case ByteCodeConstants.ATHROW: + return false; + } + } + + if ((checkMonitorExit == false) && (index == length)) + { + // Aucune instruction 'MonitorExit' n'a ete trouv�e. Cas de la + // double instruction 'synchronized' imbriqu�e pour le JDK 1.1.8 + return true; + } + + return false; + } + + private static boolean UpdateFastCodeException( + List fastCodeExceptions, + FastAggregatedCodeException fastAggregatedCodeException) + { + int length = fastCodeExceptions.size(); + + if (fastAggregatedCodeException.catch_type == 0) + { + // Finally + + // Same start and end offsets + for (int i=0; i fce.maxOffset) && + (fastAggregatedCodeException.synchronizedFlag == false)) + { + if ((fce.afterOffset == UtilConstants.INVALID_OFFSET) || + ((fastAggregatedCodeException.end_pc < fce.afterOffset) && + (fastAggregatedCodeException.handler_pc < fce.afterOffset))) + { + fce.maxOffset = fastAggregatedCodeException.handler_pc; + fce.finallyFromOffset = fastAggregatedCodeException.handler_pc; + fce.nbrFinally += fastAggregatedCodeException.nbrFinally; + return true; + } + } + } + + // Old algo + for (int i=0; i= fce.tryToOffset) && + (fastAggregatedCodeException.handler_pc > fce.maxOffset) && + (fastAggregatedCodeException.synchronizedFlag == false)) + { + if ((fce.afterOffset == UtilConstants.INVALID_OFFSET) || + ((fastAggregatedCodeException.end_pc < fce.afterOffset) && + (fastAggregatedCodeException.handler_pc < fce.afterOffset))) + { + fce.maxOffset = fastAggregatedCodeException.handler_pc; + fce.finallyFromOffset = fastAggregatedCodeException.handler_pc; + fce.nbrFinally += fastAggregatedCodeException.nbrFinally; + return true; + } + /* Mis en commentaire a cause d'erreurs pour le jdk1.5.0 dans + * TryCatchFinallyClass.complexMethodTryCatchCatchFinally() + * + * else if ((fce.catches != null) && + (fce.afterOffset == fastAggregatedCodeException.end_pc)) + { + fce.finallyFromOffset = fastAggregatedCodeException.handler_pc; + fce.nbrFinally += fastAggregatedCodeException.nbrFinally; + return true; + } */ + } + } + } + + return false; + } + + private static FastCodeException NewFastCodeException( + List list, FastAggregatedCodeException fastCodeException) + { + FastCodeException fce = new FastCodeException( + fastCodeException.start_pc, + fastCodeException.end_pc, + fastCodeException.handler_pc, + fastCodeException.synchronizedFlag); + + if (fastCodeException.catch_type == 0) + { + fce.finallyFromOffset = fastCodeException.handler_pc; + fce.nbrFinally += fastCodeException.nbrFinally; + } + else + { + fce.catches.add(new FastCodeExceptionCatch( + fastCodeException.catch_type, + fastCodeException.otherCatchTypes, + fastCodeException.handler_pc)); + } + + // Approximation a affin�e par la methode 'ComputeAfterOffset' + fce.afterOffset = SearchAfterOffset(list, fastCodeException.handler_pc); + + return fce; + } + + /* + * Recherche l'offset apres le bloc try-catch-finally + */ + private static int SearchAfterOffset(List list, int offset) + { + // Search instruction at 'offset' + int index = InstructionUtil.getIndexForOffset(list, offset); + + if (index <= 0) + return offset; + + // Search previous 'goto' instruction + Instruction i = list.get(--index); + + switch (i.opcode) + { + case ByteCodeConstants.GOTO: + int branch = ((Goto)i).branch; + if (branch < 0) + return UtilConstants.INVALID_OFFSET; + int jumpOffset = i.offset + branch; + index = InstructionUtil.getIndexForOffset(list, jumpOffset); + if (index <= 0) + return UtilConstants.INVALID_OFFSET; + i = list.get(index); + if (i.opcode != ByteCodeConstants.JSR) + return jumpOffset; + branch = ((Jsr)i).branch; + if (branch > 0) + return i.offset + branch; + return jumpOffset+1; + + case ByteCodeConstants.RET: + // Particularite de la structure try-catch-finally du JDK 1.1.8: + // une sous routine termine le bloc precedent 'offset'. + // Strategie : recheche de l'instruction goto, sautant apres + // 'offset', et suivie par le sequence d'instructions suivante : + // 30: goto +105 -> 135 + // 33: astore_3 + // 34: jsr +5 -> 39 + // 37: aload_3 + // 38: athrow + // 39: astore 4 + // 41: ... + // 45: ret 4 + while (--index >= 3) + { + if ((list.get(index).opcode == ByteCodeConstants.ATHROW) && + (list.get(index-1).opcode == ByteCodeConstants.JSR) && + (list.get(index-2).opcode == ByteCodeConstants.ASTORE) && + (list.get(index-3).opcode == ByteCodeConstants.GOTO)) + { + Goto g = (Goto)list.get(index-3); + return g.GetJumpOffset(); + } + } + + default: + return UtilConstants.INVALID_OFFSET; + } + } + + private static ArrayList SearchSwitchCaseOffsets( + List list) + { + ArrayList switchCaseOffsets = new ArrayList(); + + int i = list.size(); + while (i-- > 0) + { + Instruction instruction = list.get(i); + + switch (instruction.opcode) + { + case ByteCodeConstants.TABLESWITCH: + case ByteCodeConstants.LOOKUPSWITCH: + Switch s = (Switch)instruction; + int j = s.offsets.length; + int[] offsets = new int[j+1]; + + offsets[j] = s.offset + s.defaultOffset; + while (j-- > 0) + offsets[j] = s.offset + s.offsets[j]; + + Arrays.sort(offsets); + switchCaseOffsets.add(offsets); + break; + } + } + + return switchCaseOffsets; + } + + private static void DefineType( + List list, FastCodeException fastCodeException) + { + // Contains finally ? + switch (fastCodeException.nbrFinally) + { + case 0: + // No + fastCodeException.type = FastConstants.TYPE_CATCH; + break; + case 1: + // 1.1.8, 1.3.1, 1.4.2 or eclipse 677 + // Yes, contains catch ? + if ((fastCodeException.catches == null) || + (fastCodeException.catches.size() == 0)) + { + // No + int index = InstructionUtil.getIndexForOffset( + list, fastCodeException.finallyFromOffset); + if (index < 0) + return; + + // Search 'goto' instruction + Instruction instruction = list.get(index-1); + switch (instruction.opcode) + { + case ByteCodeConstants.GOTO: + if (TryBlockContainsJsr(list, fastCodeException)) + { + fastCodeException.type = FastConstants.TYPE_118_FINALLY; + } + else + { + // Search previous 'goto' instruction + switch (list.get(index-2).opcode) + { + case ByteCodeConstants.MONITOREXIT: + fastCodeException.type = FastConstants.TYPE_118_SYNCHRONIZED; + break; + default: + // TYPE_ECLIPSE_677_FINALLY or TYPE_118_FINALLY_2 ? + int jumpOffset = ((Goto)instruction).GetJumpOffset(); + instruction = + InstructionUtil.getInstructionAt(list, jumpOffset); + + if (instruction.opcode == ByteCodeConstants.JSR) + fastCodeException.type = + FastConstants.TYPE_118_FINALLY_2; + else + fastCodeException.type = + FastConstants.TYPE_ECLIPSE_677_FINALLY; + } + } + break; + case ByteCodeConstants.RETURN: + case ByteCodeConstants.XRETURN: + if (TryBlockContainsJsr(list, fastCodeException)) + { + fastCodeException.type = FastConstants.TYPE_118_FINALLY; + } + else + { + // Search previous 'return' instruction + switch (list.get(index-2).opcode) + { + case ByteCodeConstants.MONITOREXIT: + fastCodeException.type = FastConstants.TYPE_118_SYNCHRONIZED; + break; + default: + // TYPE_ECLIPSE_677_FINALLY or TYPE_142 ? + Instruction firstFinallyInstruction = list.get(index+1); + int exceptionIndex = ((AStore)list.get(index)).index; + int lenght = list.size(); + + // Search throw instruction + while (++index < lenght) + { + instruction = list.get(index); + if (instruction.opcode == ByteCodeConstants.ATHROW) + { + AThrow athrow = (AThrow)instruction; + if ((athrow.value.opcode == ByteCodeConstants.ALOAD) && + ( ((ALoad)athrow.value).index == exceptionIndex )) + break; + } + } + + if (++index >= lenght) + { + fastCodeException.type = FastConstants.TYPE_142; + } + else + { + instruction = list.get(index); + + fastCodeException.type = + ((instruction.opcode != firstFinallyInstruction.opcode) || + (firstFinallyInstruction.lineNumber == Instruction.UNKNOWN_LINE_NUMBER) || + (firstFinallyInstruction.lineNumber != instruction.lineNumber)) ? + FastConstants.TYPE_142 : + FastConstants.TYPE_ECLIPSE_677_FINALLY; + } + } + } + break; + case ByteCodeConstants.ATHROW: + // Search 'jsr' instruction after 'astore' instruction + switch (list.get(index+1).opcode) + { + case ByteCodeConstants.JSR: + fastCodeException.type = + FastConstants.TYPE_118_FINALLY_THROW; + break; + default: + if (list.get(index).opcode == + ByteCodeConstants.MONITOREXIT) + fastCodeException.type = + FastConstants.TYPE_118_FINALLY; + else + fastCodeException.type = + FastConstants.TYPE_142_FINALLY_THROW; + } + break; + case ByteCodeConstants.RET: + // Double synchronized blocks compiled with the JDK 1.1.8 + fastCodeException.type = + FastConstants.TYPE_118_SYNCHRONIZED_DOUBLE; + break; + } + } + else + { + // Yes, contains catch(s) & finally + int index = InstructionUtil.getIndexForOffset( + list, fastCodeException.catches.get(0).fromOffset); + if (index < 0) + return; + + // Search 'goto' instruction in try block + Instruction instruction = list.get(--index); + if (instruction.opcode == ByteCodeConstants.GOTO) + { + Goto g = (Goto)instruction; + + // Search previous 'goto' instruction + instruction = list.get(--index); + if (instruction.opcode == ByteCodeConstants.JSR) + { + fastCodeException.type = FastConstants.TYPE_131_CATCH_FINALLY; + } + else + { + // Search jump 'goto' instruction + index = InstructionUtil.getIndexForOffset( + list, g.GetJumpOffset()); + instruction = list.get(index); + + if (instruction.opcode == ByteCodeConstants.JSR) + { + fastCodeException.type = + FastConstants.TYPE_118_CATCH_FINALLY; + } + else + { + instruction = list.get(index - 1); + + if (instruction.opcode == ByteCodeConstants.ATHROW) + fastCodeException.type = + FastConstants.TYPE_ECLIPSE_677_CATCH_FINALLY; + else + fastCodeException.type = + FastConstants.TYPE_118_CATCH_FINALLY_2; + } + } + } + else + { + if (instruction.opcode == ByteCodeConstants.RET) + { + fastCodeException.type = + FastConstants.TYPE_118_CATCH_FINALLY; + } + else + { + // Search previous instruction + instruction = list.get(--index); + if (instruction.opcode == ByteCodeConstants.JSR) + { + fastCodeException.type = + FastConstants.TYPE_131_CATCH_FINALLY; + } + } + } + } + break; + default: + // 1.3.1, 1.4.2, 1.5.0, jikes 1.2.2 or eclipse 677 + // Yes, contains catch ? + if ((fastCodeException.catches == null) || + (fastCodeException.catches.size() == 0)) + { + // No, 1.4.2 or jikes 1.2.2 ? + int index = InstructionUtil.getIndexForOffset( + list, fastCodeException.tryToOffset); + if (index < 0) + return; + + Instruction instruction = list.get(index); + + switch (instruction.opcode) + { + case ByteCodeConstants.JSR: + fastCodeException.type = FastConstants.TYPE_131_CATCH_FINALLY; + break; + case ByteCodeConstants.ATHROW: + fastCodeException.type = FastConstants.TYPE_JIKES_122; + break; + case ByteCodeConstants.GOTO: + Goto g = (Goto)instruction; + + // Search previous 'goto' instruction + instruction = InstructionUtil.getInstructionAt( + list, g.GetJumpOffset()); + if (instruction == null) + return; + + if ((instruction.opcode == ByteCodeConstants.JSR) && + (((Jsr)instruction).branch < 0)) + { + fastCodeException.type = FastConstants.TYPE_JIKES_122; + } + else + { + if ((index > 0) && (list.get(index-1).opcode == ByteCodeConstants.JSR)) + fastCodeException.type = FastConstants.TYPE_131_CATCH_FINALLY; + else + fastCodeException.type = FastConstants.TYPE_142; + } + break; + case ByteCodeConstants.POP: + DefineTypeJikes122Or142( + list, fastCodeException, ((Pop)instruction).objectref, index); + break; + case ByteCodeConstants.ASTORE: + DefineTypeJikes122Or142( + list, fastCodeException, ((AStore)instruction).valueref, index); + break; + case ByteCodeConstants.RETURN: + case ByteCodeConstants.XRETURN: + // 1.3.1, 1.4.2 or jikes 1.2.2 ? + if ((index > 0) && (list.get(index-1).opcode == ByteCodeConstants.JSR)) + fastCodeException.type = FastConstants.TYPE_131_CATCH_FINALLY; + else + fastCodeException.type = FastConstants.TYPE_142; + break; + default: + fastCodeException.type = FastConstants.TYPE_142; + } + } + else + { + // Yes, contains catch(s) & multiple finally + // Control que toutes les instructions 'goto' sautent sur la + // meme instruction. + boolean uniqueJumpAddressFlag = true; + int uniqueJumpAddress = -1; + + if (fastCodeException.catches != null) + { + for (int i=fastCodeException.catches.size()-1; i>=0; --i) + { + FastCodeExceptionCatch fcec = + fastCodeException.catches.get(i); + int index = InstructionUtil.getIndexForOffset( + list, fcec.fromOffset); + if (index != -1) + { + Instruction instruction = list.get(index-1); + if (instruction.opcode == ByteCodeConstants.GOTO) + { + int branch = ((Goto)instruction).branch; + if (branch > 0) + { + int jumpAddress = instruction.offset + branch; + if (uniqueJumpAddress == -1) + { + uniqueJumpAddress = jumpAddress; + } + else if (uniqueJumpAddress != jumpAddress) + { + uniqueJumpAddressFlag = false; + break; + } + } + } + } + } + } + + int index = InstructionUtil.getIndexForOffset( + list, fastCodeException.finallyFromOffset); + if (index < 0) + return; + + Instruction instruction = list.get(--index); + + if ((uniqueJumpAddressFlag) && + (instruction.opcode == ByteCodeConstants.GOTO)) + { + int branch = ((Goto)instruction).branch; + if (branch > 0) + { + int jumpAddress = instruction.offset + branch; + if (uniqueJumpAddress == -1) + uniqueJumpAddress = jumpAddress; + else if (uniqueJumpAddress != jumpAddress) + uniqueJumpAddressFlag = false; + } + } + + if (!uniqueJumpAddressFlag) + { + fastCodeException.type = FastConstants.TYPE_ECLIPSE_677_CATCH_FINALLY; + return; + } + + index = InstructionUtil.getIndexForOffset( + list, fastCodeException.tryToOffset); + if (index < 0) + return; + + instruction = list.get(index); + + switch (instruction.opcode) + { + case ByteCodeConstants.JSR: + fastCodeException.type = FastConstants.TYPE_131_CATCH_FINALLY; + break; + case ByteCodeConstants.ATHROW: + fastCodeException.type = FastConstants.TYPE_JIKES_122; + break; + case ByteCodeConstants.GOTO: + Goto g = (Goto)instruction; + + // Search previous 'goto' instruction + instruction = InstructionUtil.getInstructionAt( + list, g.GetJumpOffset()); + if (instruction == null) + return; + + if ((instruction.opcode == ByteCodeConstants.JSR) && + (((Jsr)instruction).branch < 0)) + { + fastCodeException.type = FastConstants.TYPE_JIKES_122; + } + else + { + if ((index > 0) && (list.get(index-1).opcode == ByteCodeConstants.JSR)) + fastCodeException.type = FastConstants.TYPE_131_CATCH_FINALLY; + else + fastCodeException.type = FastConstants.TYPE_142; + } + break; + case ByteCodeConstants.POP: + DefineTypeJikes122Or142( + list, fastCodeException, ((Pop)instruction).objectref, index); + break; + case ByteCodeConstants.ASTORE: + DefineTypeJikes122Or142( + list, fastCodeException, ((AStore)instruction).valueref, index); + break; + case ByteCodeConstants.RETURN: + case ByteCodeConstants.XRETURN: + // 1.3.1, 1.4.2 or jikes 1.2.2 ? + instruction = InstructionUtil.getInstructionAt( + list, uniqueJumpAddress); + if ((instruction != null) && + (instruction.opcode == ByteCodeConstants.JSR) && + ( ((Jsr)instruction).branch < 0 )) + fastCodeException.type = FastConstants.TYPE_JIKES_122; + else if ((index > 0) && (list.get(index-1).opcode == ByteCodeConstants.JSR)) + fastCodeException.type = FastConstants.TYPE_131_CATCH_FINALLY; + else + fastCodeException.type = FastConstants.TYPE_142; + break; + default: + // TYPE_ECLIPSE_677_FINALLY or TYPE_142 ? + index = InstructionUtil.getIndexForOffset( + list, fastCodeException.finallyFromOffset); + Instruction firstFinallyInstruction = list.get(index+1); + + if (firstFinallyInstruction.opcode != ByteCodeConstants.ASTORE) + { + fastCodeException.type = FastConstants.TYPE_142; + } + else + { + int exceptionIndex = ((AStore)list.get(index)).index; + int lenght = list.size(); + + // Search throw instruction + while (++index < lenght) + { + instruction = list.get(index); + if (instruction.opcode == ByteCodeConstants.ATHROW) + { + AThrow athrow = (AThrow)instruction; + if ((athrow.value.opcode == ByteCodeConstants.ALOAD) && + ( ((ALoad)athrow.value).index == exceptionIndex )) + break; + } + } + + if (++index >= lenght) + { + fastCodeException.type = FastConstants.TYPE_142; + } + else + { + instruction = list.get(index); + + fastCodeException.type = + ((instruction.opcode != firstFinallyInstruction.opcode) || + (firstFinallyInstruction.lineNumber == Instruction.UNKNOWN_LINE_NUMBER) || + (firstFinallyInstruction.lineNumber != instruction.lineNumber)) ? + FastConstants.TYPE_142 : + FastConstants.TYPE_ECLIPSE_677_CATCH_FINALLY; + } + } + } + } + } + } + + private static boolean TryBlockContainsJsr( + List list, FastCodeException fastCodeException) + { + int index = InstructionUtil.getIndexForOffset( + list, fastCodeException.tryToOffset); + + if (index != -1) + { + int tryFromOffset = fastCodeException.tryFromOffset; + + for (;;) + { + Instruction instruction = list.get(index); + + if (instruction.offset <= tryFromOffset) + { + break; + } + + if (instruction.opcode == ByteCodeConstants.JSR) + { + if (((Jsr)instruction).GetJumpOffset() > + fastCodeException.finallyFromOffset) + { + return true; + } + } + + if (index == 0) + { + break; + } + + index--; + } + } + + return false; + } + + private static void DefineTypeJikes122Or142( + List list, FastCodeException fastCodeException, + Instruction instruction, int index) + { + if (instruction.opcode == ByteCodeConstants.EXCEPTIONLOAD) + { + instruction = list.get(--index); + + if (instruction.opcode == ByteCodeConstants.GOTO) + { + int jumpAddress = ((Goto)instruction).GetJumpOffset(); + + instruction = InstructionUtil.getInstructionAt(list, jumpAddress); + + if ((instruction != null) && + (instruction.opcode == ByteCodeConstants.JSR)) + { + fastCodeException.type = FastConstants.TYPE_JIKES_122; + return; + } + } + } + + fastCodeException.type = FastConstants.TYPE_142; + } + + private static void ComputeAfterOffset( + Method method, List list, + ArrayList switchCaseOffsets, + ArrayList fastCodeExceptions, + FastCodeException fastCodeException, int fastCodeExceptionIndex) + { + switch (fastCodeException.type) + { + case FastConstants.TYPE_118_CATCH_FINALLY: + { + // Strategie : Trouver l'instruction suivant 'ret' de la sous + // routine 'finally'. + int index = InstructionUtil.getIndexForOffset( + list, fastCodeException.afterOffset); + if ((index < 0) || (index >= list.size())) + return; + + int length = list.size(); + IntSet offsetSet = new IntSet(); + int retCounter = 0; + + // Search 'ret' instruction + // Permet de prendre en compte les sous routines imbriqu�es + while (++index < length) + { + Instruction i = list.get(index); + + switch (i.opcode) + { + case ByteCodeConstants.JSR: + offsetSet.add(((Jsr)i).GetJumpOffset()); + break; + + case ByteCodeConstants.RET: + if (offsetSet.size() == retCounter) + { + fastCodeException.afterOffset = i.offset + 1; + return; + } + retCounter++; + break; + } + } + } + break; + case FastConstants.TYPE_118_CATCH_FINALLY_2: + { + Instruction instruction = InstructionUtil.getInstructionAt( + list, fastCodeException.afterOffset); + if (instruction == null) + return; + + fastCodeException.afterOffset = instruction.offset + 1; + } + break; + case FastConstants.TYPE_118_FINALLY_2: + { + int index = InstructionUtil.getIndexForOffset( + list, fastCodeException.afterOffset); + if ((index < 0) || (index >= list.size())) + return; + + Instruction i = list.get(++index); + if (i.opcode != ByteCodeConstants.GOTO) + return; + + fastCodeException.afterOffset = ((Goto)i).GetJumpOffset(); + } + break; + case FastConstants.TYPE_JIKES_122: + // Le traitement suivant etait faux pour reconstruire la methode + // "basic.data.TestTryCatchFinally .methodTryFinally1()" compile + // par "Eclipse Java Compiler v_677_R32x, 3.2.1 release". +// { +// int index = InstructionUtil.getIndexForOffset( +// list, fastCodeException.afterOffset); +// if ((index < 0) || (index >= list.size())) +// return; +// +// Instruction i = list.get(++index); +// +// fastCodeException.afterOffset = i.offset; +// } + break; + case FastConstants.TYPE_ECLIPSE_677_FINALLY: + { + int index = InstructionUtil.getIndexForOffset( + list, fastCodeException.finallyFromOffset); + if (index < 0) + return; + + int lenght = list.size(); + Instruction instruction = list.get(index); + + switch (instruction.opcode) + { + case ByteCodeConstants.POP: + { + // Search the first throw instruction + while (++index < lenght) + { + instruction = list.get(index); + if (instruction.opcode == ByteCodeConstants.ATHROW) + { + fastCodeException.afterOffset = + instruction.offset + 1; + break; + } + } + } + break; + case ByteCodeConstants.ASTORE: + { + // L'un des deux cas les plus complexes : + // - le bloc 'finally' est dupliqu� deux fois. + // - aucun 'goto' ne saute apres le dernier bloc finally. + // Methode de calcul de 'afterOffset' : + // - compter le nombre d'instructions entre le d�but du 1er bloc + // 'finally' et le saut du goto en fin de bloc 'try'. + // - Ajouter ce nombre � l'index de l'instruction vers laquelle + // saute le 'goto' precedent le 1er bloc 'finally'. + int finallyStartIndex = index+1; + int exceptionIndex = ((AStore)instruction).index; + + // Search throw instruction + while (++index < lenght) + { + instruction = list.get(index); + if (instruction.opcode == ByteCodeConstants.ATHROW) + { + AThrow athrow = (AThrow)instruction; + if ((athrow.value.opcode == ByteCodeConstants.ALOAD) && + ( ((ALoad)athrow.value).index == exceptionIndex )) + break; + } + } + + index += (index - finallyStartIndex + 1); + + if (index < lenght) + fastCodeException.afterOffset = list.get(index).offset; + } + break; + } + } + break; + case FastConstants.TYPE_ECLIPSE_677_CATCH_FINALLY: + { + // L'un des deux cas les plus complexes : + // - le bloc 'finally' est dupliqu� deux ou trois fois. + // - aucun 'goto' ne saute apres le dernier bloc finally. + // Methode de calcul de 'afterOffset' : + // - compter le nombre d'instructions entre le d�but du 1er bloc + // 'finally' et le saut du goto en fin de bloc 'try'. + // - Ajouter ce nombre � l'index de l'instruction vers laquelle + // saute le 'goto' precedent le 1er bloc 'finally'. + int index = InstructionUtil.getIndexForOffset( + list, fastCodeException.finallyFromOffset); + if (index < 0) + return; + + Instruction instruction = list.get(index); + + if (instruction.opcode != ByteCodeConstants.ASTORE) + return; + + int finallyStartIndex = index+1; + int exceptionIndex = ((AStore)instruction).index; + int lenght = list.size(); + + // Search throw instruction + while (++index < lenght) + { + instruction = list.get(index); + if (instruction.opcode == ByteCodeConstants.ATHROW) + { + AThrow athrow = (AThrow)instruction; + if ((athrow.value.opcode == ByteCodeConstants.ALOAD) && + ( ((ALoad)athrow.value).index == exceptionIndex )) + break; + } + } + + int delta = index - finallyStartIndex; + index += delta + 1; + int afterOffset = list.get(index).offset; + + // Verification de la presence d'un bloc 'finally' pour les blocs + // 'catch'. + if ((index < lenght) && + (list.get(index).opcode == ByteCodeConstants.GOTO)) + { + Goto g = (Goto)list.get(index); + int jumpOffset = g.GetJumpOffset(); + int indexTmp = index + delta + 1; + + if ((indexTmp < lenght) && + (list.get(indexTmp-1).offset < jumpOffset) && + (jumpOffset <= list.get(indexTmp).offset)) + { + // Reduction de 'afterOffset' a l'aide des 'Branch Instructions' + afterOffset = ReduceAfterOffsetWithBranchInstructions( + list, fastCodeException, + fastCodeException.finallyFromOffset, + list.get(indexTmp).offset); + + // Reduction de 'afterOffset' a l'aide des numeros de ligne + if (! fastCodeException.synchronizedFlag) + { + afterOffset = ReduceAfterOffsetWithLineNumbers( + list, fastCodeException, afterOffset); + } + + // Reduction de 'afterOffset' a l'aide des instructions de + // gestion des exceptions englobantes + afterOffset = ReduceAfterOffsetWithExceptions( + fastCodeExceptions, fastCodeException.tryFromOffset, + fastCodeException.finallyFromOffset, afterOffset); + } + } + + fastCodeException.afterOffset = afterOffset; + } + break; + case FastConstants.TYPE_118_FINALLY: + { + // Re-estimation de la valeur de l'attribut 'afterOffset'. + // Strategie : le bon offset, apres le bloc 'try-finally', se + // trouve apres l'instruction 'ret' de la sous procedure du + // bloc 'finally'. + int index = InstructionUtil.getIndexForOffset( + list, fastCodeException.finallyFromOffset); + if (index <= 0) + return; + + int length = list.size(); + + // Gestion des instructions JSR imbriquees + int offsetOfJsrsLength = list.get(length-1).offset + 1; + boolean[] offsetOfJsrs = new boolean[offsetOfJsrsLength]; + int level = 0; + + while (++index < length) + { + Instruction i = list.get(index); + + if (offsetOfJsrs[i.offset]) + level++; + + if (i.opcode == ByteCodeConstants.JSR) + { + int jumpOffset = ((Jsr)i).GetJumpOffset(); + if (jumpOffset < offsetOfJsrsLength) + offsetOfJsrs[jumpOffset] = true; + } + else if (i.opcode == ByteCodeConstants.RET) + { + if (level <= 1) + { + fastCodeException.afterOffset = i.offset+1; + break; + } + else + { + level--; + } + } + } + } + break; + case FastConstants.TYPE_118_FINALLY_THROW: + case FastConstants.TYPE_131_CATCH_FINALLY: + { + int index = InstructionUtil.getIndexForOffset( + list, fastCodeException.finallyFromOffset); + if (index <= 0) + return; + + // Search last 'ret' instruction of the finally block + int length = list.size(); + + while (++index < length) + { + Instruction i = list.get(index); + if (i.opcode == ByteCodeConstants.RET) + { + fastCodeException.afterOffset = (++index < length) ? + list.get(index).offset : + i.offset+1; + break; + } + } + } + break; + default: + { + int length = list.size(); + + // Re-estimation de la valeur de l'attribut 'afterOffset'. + // Strategie : parcours du bytecode jusqu'a trouver une + // instruction de saut vers la derniere instruction 'return', + // ou une instruction 'athrow' ou une instruction de saut + // n�gatif allant en deca du debut du dernier block. Le parcours + // du bytecode doit prendre en compte les sauts positifs. + + // Calcul de l'offset apres la structure try-catch + int afterOffset = fastCodeException.afterOffset; + if (afterOffset == -1) + afterOffset = list.get(length-1).offset + 1; + + // Reduction de 'afterOffset' a l'aide des 'Branch Instructions' + afterOffset = ReduceAfterOffsetWithBranchInstructions( + list, fastCodeException, fastCodeException.maxOffset, + afterOffset); + + // Reduction de 'afterOffset' a l'aide des numeros de ligne + if (! fastCodeException.synchronizedFlag) + { + afterOffset = ReduceAfterOffsetWithLineNumbers( + list, fastCodeException, afterOffset); + } + + // Reduction de 'afterOffset' a l'aide des instructions 'switch' + afterOffset = ReduceAfterOffsetWithSwitchInstructions( + switchCaseOffsets, fastCodeException.tryFromOffset, + fastCodeException.maxOffset, afterOffset); + + // Reduction de 'afterOffset' a l'aide des instructions de gestion + // des exceptions englobantes + fastCodeException.afterOffset = afterOffset = + ReduceAfterOffsetWithExceptions( + fastCodeExceptions, fastCodeException.tryFromOffset, + fastCodeException.maxOffset, afterOffset); + + // Recherche de la 1ere exception d�butant apres 'maxOffset' + int tryFromOffset = Integer.MAX_VALUE; + int tryIndex = fastCodeExceptionIndex + 1; + while (tryIndex < fastCodeExceptions.size()) + { + int tryFromOffsetTmp = + fastCodeExceptions.get(tryIndex).tryFromOffset; + if (tryFromOffsetTmp > fastCodeException.maxOffset) + { + tryFromOffset = tryFromOffsetTmp; + break; + } + tryIndex++; + } + + // Parcours + int maxIndex = InstructionUtil.getIndexForOffset( + list, fastCodeException.maxOffset); + int index = maxIndex; + while (index < length) + { + Instruction instruction = list.get(index); + + if (instruction.offset >= afterOffset) + break; + + if (instruction.offset > tryFromOffset) + { + // Saut des blocs try-catch-finally + FastCodeException fce = + fastCodeExceptions.get(tryIndex); + int afterOffsetTmp = fce.afterOffset; + + // Recherche du plus grand offset de fin parmi toutes + // les exceptions d�butant � l'offset 'tryFromOffset' + for (;;) + { + if (++tryIndex >= fastCodeExceptions.size()) + { + tryFromOffset = Integer.MAX_VALUE; + break; + } + int tryFromOffsetTmp = + fastCodeExceptions.get(tryIndex).tryFromOffset; + if (fce.tryFromOffset != tryFromOffsetTmp) + { + tryFromOffset = tryFromOffsetTmp; + break; + } + FastCodeException fceTmp = + fastCodeExceptions.get(tryIndex); + if (afterOffsetTmp < fceTmp.afterOffset) + afterOffsetTmp = fceTmp.afterOffset; + } + + while ((index < length) && + (list.get(index).offset < afterOffsetTmp)) + index++; + } + else + { + switch (instruction.opcode) + { + case ByteCodeConstants.ATHROW: + case ByteCodeConstants.RETURN: + case ByteCodeConstants.XRETURN: + // Verification que toutes les variables + // locales utilisees sont definie dans le + // bloc du dernier catch ou de finally + if (CheckLocalVariableUsedVisitor.Visit( + method.getLocalVariables(), + fastCodeException.maxOffset, + instruction)) + { + // => Instruction incluse au bloc + fastCodeException.afterOffset = instruction.offset+1; + } + // Verification que l'instruction participe a un + // operateur ternaire + else if (CheckTernaryOperator(list, index)) + { + // => Instruction incluse au bloc + fastCodeException.afterOffset = instruction.offset+1; + } + else + { + if (index+1 >= length) + { + // Derniere instruction de la liste + if (instruction.opcode == ByteCodeConstants.ATHROW) + { + // Dernier 'throw' + // => Instruction incluse au bloc + fastCodeException.afterOffset = instruction.offset+1; + } + else + { + // Dernier 'return' + // => Instruction placee apres le bloc + fastCodeException.afterOffset = instruction.offset; + } + } + else + { + // Une instruction du bloc 'try-catch-finally' + // saute-t-elle vers l'instuction qui suit + // cette instruction ? + int tryFromIndex = + InstructionUtil.getIndexForOffset( + list, fastCodeException.tryFromOffset); + int beforeInstructionOffset = (index==0) ? + 0 : list.get(index-1).offset; + + if (InstructionUtil.CheckNoJumpToInterval( + list, tryFromIndex, maxIndex, + beforeInstructionOffset, instruction.offset)) + { + // Aucune instruction du bloc + // 'try-catch-finally' ne saute vers + // cette instruction. + // => Instruction incluse au bloc + fastCodeException.afterOffset = instruction.offset+1; + } + else + { + // Une instruction du bloc + // 'try-catch-finally' saute vers + // cette instruction. + // => Instruction placee apres le bloc + fastCodeException.afterOffset = instruction.offset; + } + } + } + return; + case ByteCodeConstants.GOTO: + case ByteCodeConstants.IFCMP: + case ByteCodeConstants.IF: + case ByteCodeConstants.IFXNULL: + int jumpOffsetTmp; + + if (instruction.opcode == ByteCodeConstants.GOTO) + { + jumpOffsetTmp = + ((BranchInstruction)instruction).GetJumpOffset(); + } + else + { + // L'aggregation des instructions 'if' n'a pas + // encore ete executee. Recherche du plus petit + // offset de saut parmi toutes les instructions + // 'if' qui suivent. + index = ComparisonInstructionAnalyzer.GetLastIndex( + list, index); + BranchInstruction lastBi = + (BranchInstruction)list.get(index); + jumpOffsetTmp = lastBi.GetJumpOffset(); + } + + if (jumpOffsetTmp > instruction.offset) + { + // Saut positif + if (jumpOffsetTmp < afterOffset) + { + while (++index < length) + { + if (list.get(index).offset >= jumpOffsetTmp) + { + --index; + break; + } + } + } + else + { + if ((instruction.opcode == ByteCodeConstants.GOTO) || + (jumpOffsetTmp != afterOffset)) + { + // Une instruction du bloc 'try-catch-finally' + // saute-t-elle vers cett instuction ? + int tryFromIndex = + InstructionUtil.getIndexForOffset( + list, fastCodeException.tryFromOffset); + int beforeInstructionOffset = (index==0) ? + 0 : list.get(index-1).offset; + + if (InstructionUtil.CheckNoJumpToInterval( + list, tryFromIndex, maxIndex, + beforeInstructionOffset, instruction.offset)) + { + // Aucune instruction du bloc + // 'try-catch-finally' ne saute vers + // cette instuction + // => Instruction incluse au bloc + fastCodeException.afterOffset = instruction.offset+1; + } + else + { + // Une instruction du bloc + // 'try-catch-finally' saute vers + // cette instuction + // => Instruction plac�e apres le bloc + fastCodeException.afterOffset = instruction.offset; + } + } + //else + //{ + // Si l'instruction est un saut conditionnel + // et si l'offset de saut est le meme que 'afterOffset', + // alors l'instruction fait partie du dernier bloc. + //} + return; + } + } + else if (jumpOffsetTmp <= fastCodeException.tryFromOffset) + { + // Saut negatif + if ((index > 0) && + (instruction.lineNumber != Instruction.UNKNOWN_LINE_NUMBER)) + { + Instruction beforeInstruction = list.get(index-1); + if (instruction.lineNumber == + beforeInstruction.lineNumber) + { + // For instruction ? + if ((beforeInstruction.opcode == + ByteCodeConstants.ASTORE) && + ((AStore)beforeInstruction).valueref.opcode == + ByteCodeConstants.EXCEPTIONLOAD) + { + // Non + fastCodeException.afterOffset = + instruction.offset; + } + else if ((beforeInstruction.opcode == + ByteCodeConstants.POP) && + ((Pop)beforeInstruction).objectref.opcode == + ByteCodeConstants.EXCEPTIONLOAD) + { + // Non + fastCodeException.afterOffset = + instruction.offset; + } + else + { + // Oui + fastCodeException.afterOffset = + beforeInstruction.offset; + } + return; + } + } + fastCodeException.afterOffset = + instruction.offset; + return; + } + break; + case FastConstants.LOOKUPSWITCH: + case FastConstants.TABLESWITCH: + Switch s = (Switch)instruction; + + // Search max offset + int maxOffset = s.defaultOffset; + int i = s.offsets.length; + while (i-- > 0) + { + int offset = s.offsets[i]; + if (maxOffset < offset) + maxOffset = offset; + } + + if (maxOffset < afterOffset) + { + while (++index < length) + { + if (list.get(index).offset >= maxOffset) + { + --index; + break; + } + } + } + break; + } + index++; + } + } + } + } + } + + private static boolean CheckTernaryOperator(List list, int index) + { + // Motif des operateurs ternaires : + // index-3) If instruction (IF || IFCMP || IFXNULL || COMPLEXIF) + // index-2) TernaryOpStore + // index-1) Goto + // index) (X)Return + if ((index > 2) && + (list.get(index-1).opcode == FastConstants.GOTO) && + (list.get(index-2).opcode == FastConstants.TERNARYOPSTORE)) + { + Goto g = (Goto)list.get(index-1); + int jumpOffset = g.GetJumpOffset(); + int returnOffset = list.get(index).offset; + if ((g.offset < jumpOffset) && (jumpOffset < returnOffset)) + { + return true; + } + } + + return false; + } + + private static int ReduceAfterOffsetWithBranchInstructions( + List list, FastCodeException fastCodeException, + int firstOffset, int afterOffset) + { + Instruction instruction; + + // Check previous instructions + int index = InstructionUtil.getIndexForOffset( + list, fastCodeException.tryFromOffset); + + if (index != -1) + { + while (index-- > 0) + { + instruction = list.get(index); + + switch (instruction.opcode) + { + case ByteCodeConstants.IF: + case ByteCodeConstants.IFCMP: + case ByteCodeConstants.IFXNULL: + case ByteCodeConstants.GOTO: + int jumpOffset = ((BranchInstruction)instruction).GetJumpOffset(); + if ((firstOffset < jumpOffset) && (jumpOffset < afterOffset)) + afterOffset = jumpOffset; + } + } + } + + // Check next instructions + index = list.size(); + do + { + instruction = list.get(--index); + + switch (instruction.opcode) + { + case ByteCodeConstants.IF: + case ByteCodeConstants.IFCMP: + case ByteCodeConstants.IFXNULL: + case ByteCodeConstants.GOTO: + int jumpOffset = ((BranchInstruction)instruction).GetJumpOffset(); + if ((firstOffset < jumpOffset) && (jumpOffset < afterOffset)) + afterOffset = jumpOffset; + } + } + while (instruction.offset > afterOffset); + + return afterOffset; + } + + private static int ReduceAfterOffsetWithLineNumbers( + List list, FastCodeException fastCodeException, + int afterOffset) + { + int fromIndex = InstructionUtil.getIndexForOffset( + list, fastCodeException.tryFromOffset); + int index = fromIndex; + + if (index != -1) + { + // Search first line number + int lenght = list.size(); + int firstLineNumber = Instruction.UNKNOWN_LINE_NUMBER; + Instruction instruction; + + do + { + instruction = list.get(index++); + + if (instruction.lineNumber != Instruction.UNKNOWN_LINE_NUMBER) + { + firstLineNumber = instruction.lineNumber; + break; + } + } + while ((instruction.offset < afterOffset) && (index < lenght)); + + if (firstLineNumber != Instruction.UNKNOWN_LINE_NUMBER) + { + // Exclude instruction with a smaller line number + int maxOffset = fastCodeException.maxOffset; + index = InstructionUtil.getIndexForOffset(list, afterOffset); + + if (index != -1) + { + while (index-- > 0) + { + instruction = list.get(index); + + if ((instruction.offset <= maxOffset)) + { + break; + } + + if ((instruction.lineNumber != Instruction.UNKNOWN_LINE_NUMBER) && + (instruction.lineNumber >= firstLineNumber)) + { + break; + } + + // L'instruction a un numero de ligne inferieur aux + // instructions du bloc 'try'. A priori, elle doit etre + // place apres le bloc 'catch'. + + // Est-ce une instruction de saut ? Si oui, est-ce que + // la placer hors du bloc 'catch' genererait deux points + // de sortie du bloc ? + if (instruction.opcode == ByteCodeConstants.GOTO) + { + int jumpOffset = ((Goto)instruction).GetJumpOffset(); + + if (! InstructionUtil.CheckNoJumpToInterval( + list, + fromIndex, index, + jumpOffset-1, jumpOffset)) + { + break; + } + } + + // Est-ce une instruction 'return' ? Si oui, est-ce que + // la placer hors du bloc 'catch' genererait deux points + // de sortie du bloc ? + if (instruction.opcode == ByteCodeConstants.RETURN) + { + int maxIndex = InstructionUtil.getIndexForOffset( + list, maxOffset); + + if (list.get(maxIndex-1).opcode == instruction.opcode) + { + break; + } + } + + /* + * A QUOI SERT CE BLOC ? A QUEL CAS D'UTILISATION + * CORRESPOND T IL ? + * / + if (instruction.opcode != ByteCodeConstants.IINC) + { + if (// Check previous instructions + InstructionUtil.CheckNoJumpToInterval( + list, + 0, index, + maxOffset, instruction.offset) && + // Check next instructions + InstructionUtil.CheckNoJumpToInterval( + list, + index+1, lenght, + maxOffset, instruction.offset)) + { + break; + } + } + / * */ + + afterOffset = instruction.offset; + } + } + } + } + + return afterOffset; + } + + private static int ReduceAfterOffsetWithSwitchInstructions( + ArrayList switchCaseOffsets, + int firstOffset, int lastOffset, int afterOffset) + { + int i = switchCaseOffsets.size(); + while (i-- > 0) + { + int[] offsets = switchCaseOffsets.get(i); + + int j = offsets.length; + if (j > 1) + { + int offset2 = offsets[--j]; + + while (j-- > 0) + { + int offset1 = offsets[j]; + + if ((offset1 != -1) && + (offset1 <= firstOffset) && (lastOffset < offset2)) + { + if ((afterOffset == -1) || (afterOffset > offset2)) + afterOffset = offset2; + } + + offset2 = offset1; + } + } + } + + return afterOffset; + } + + private static int ReduceAfterOffsetWithExceptions( + ArrayList fastCodeExceptions, + int fromOffset, int maxOffset, int afterOffset) + { + int i = fastCodeExceptions.size(); + while (i-- > 0) + { + FastCodeException fastCodeException = fastCodeExceptions.get(i); + + int toOffset = fastCodeException.finallyFromOffset; + + if (fastCodeException.catches != null) + { + int j = fastCodeException.catches.size(); + while (j-- > 0) + { + FastCodeExceptionCatch fcec = fastCodeException.catches.get(j); + + if ((toOffset != -1) && + (fcec.fromOffset <= fromOffset) && + (maxOffset < toOffset)) + { + if ((afterOffset == -1) || (afterOffset > toOffset)) + afterOffset = toOffset; + } + + toOffset = fcec.fromOffset; + } + } + + if ((fastCodeException.tryFromOffset <= fromOffset) && + (maxOffset < toOffset)) + { + if ((afterOffset == -1) || (afterOffset > toOffset)) + afterOffset = toOffset; + } + } + + return afterOffset; + } + + public static void FormatFastTry( + LocalVariables localVariables, FastCodeException fce, + FastTry fastTry, int returnOffset) + { + switch (fce.type) + { + case FastConstants.TYPE_CATCH: + FormatCatch(localVariables, fce, fastTry); + break; + case FastConstants.TYPE_118_FINALLY: + Format118Finally(localVariables, fce, fastTry); + break; + case FastConstants.TYPE_118_FINALLY_2: + Format118Finally2(fce, fastTry); + break; + case FastConstants.TYPE_118_FINALLY_THROW: + Format118FinallyThrow(fastTry); + break; + case FastConstants.TYPE_118_CATCH_FINALLY: + Format118CatchFinally(fce, fastTry); + break; + case FastConstants.TYPE_118_CATCH_FINALLY_2: + Format118CatchFinally2(fce, fastTry); + break; + case FastConstants.TYPE_131_CATCH_FINALLY: + Format131CatchFinally(localVariables, fce, fastTry); + break; + case FastConstants.TYPE_142: + Format142(localVariables, fce, fastTry); + break; + case FastConstants.TYPE_142_FINALLY_THROW: + Format142FinallyThrow(fastTry); + break; + case FastConstants.TYPE_JIKES_122: + FormatJikes122(localVariables, fce, fastTry, returnOffset); + break; + case FastConstants.TYPE_ECLIPSE_677_FINALLY: + FormatEclipse677Finally(fce, fastTry); + break; + case FastConstants.TYPE_ECLIPSE_677_CATCH_FINALLY: + FormatEclipse677CatchFinally(fce, fastTry, returnOffset); + } + } + + private static void FormatCatch( + LocalVariables localVariables, FastCodeException fce, FastTry fastTry) + { + List tryInstructions = fastTry.instructions; + int jumpOffset = -1; + + // Remove last 'goto' instruction in try block + if (tryInstructions.size() > 0) + { + int lastIndex = tryInstructions.size() - 1; + Instruction instruction = tryInstructions.get(lastIndex); + + if (instruction.opcode == ByteCodeConstants.GOTO) + { + int tmpJumpOffset = ((Goto)instruction).GetJumpOffset(); + + if ((tmpJumpOffset < fce.tryFromOffset) || + (instruction.offset < tmpJumpOffset)) + { + jumpOffset = tmpJumpOffset; + fce.tryToOffset = instruction.offset; + tryInstructions.remove(lastIndex); + } + } + } + + // Remove JSR instruction in try block before 'return' instruction + FormatFastTry_RemoveJsrInstructionAndCompactStoreReturn( + tryInstructions, localVariables, Instruction.UNKNOWN_LINE_NUMBER); + + int i = fastTry.catches.size(); + while (i-- > 0) + { + List catchInstructions = + fastTry.catches.get(i).instructions; + + // Remove first catch instruction in each catch block + if (FormatCatch_RemoveFirstCatchInstruction(catchInstructions.get(0))) + catchInstructions.remove(0); + + // Remove last 'goto' instruction + if (catchInstructions.size() > 0) + { + int lastIndex = catchInstructions.size() - 1; + Instruction instruction = catchInstructions.get(lastIndex); + + if (instruction.opcode == ByteCodeConstants.GOTO) + { + int tmpJumpOffset = ((Goto)instruction).GetJumpOffset(); + + if ((tmpJumpOffset < fce.tryFromOffset) || + (instruction.offset < tmpJumpOffset)) + { + if (jumpOffset == -1) + { + jumpOffset = tmpJumpOffset; + fce.catches.get(i).toOffset = instruction.offset; + catchInstructions.remove(lastIndex); + } + else if (jumpOffset == tmpJumpOffset) + { + fce.catches.get(i).toOffset = instruction.offset; + catchInstructions.remove(lastIndex); + } + } + } + + // Remove JSR instruction in try block before 'return' instruction + FormatFastTry_RemoveJsrInstructionAndCompactStoreReturn( + catchInstructions, localVariables, + Instruction.UNKNOWN_LINE_NUMBER); + } + } + } + + private static boolean FormatCatch_RemoveFirstCatchInstruction( + Instruction instruction) + { + switch (instruction.opcode) + { + case ByteCodeConstants.POP: + return + ((Pop)instruction).objectref.opcode == + ByteCodeConstants.EXCEPTIONLOAD; + + case ByteCodeConstants.ASTORE: + return + ((AStore)instruction).valueref.opcode == + ByteCodeConstants.EXCEPTIONLOAD; + + default: + return false; + } + } + + private static void Format118Finally( + LocalVariables localVariables, FastCodeException fce, FastTry fastTry) + { + List tryInstructions = fastTry.instructions; + int length = tryInstructions.size(); + + // Remove last 'goto' instruction in try block + if (tryInstructions.get(--length).opcode == ByteCodeConstants.GOTO) + { + Goto g = (Goto)tryInstructions.remove(length); + fce.tryToOffset = g.offset; + } + // Remove last 'jsr' instruction in try block + if (tryInstructions.get(--length).opcode != ByteCodeConstants.JSR) + throw new UnexpectedInstructionException(); + tryInstructions.remove(length); + + // Remove JSR instruction in try block before 'return' instruction + int finallyInstructitonsLineNumber = + fastTry.finallyInstructions.get(0).lineNumber; + FormatFastTry_RemoveJsrInstructionAndCompactStoreReturn( + tryInstructions, localVariables, finallyInstructitonsLineNumber); + + Format118FinallyThrow(fastTry); + } + + private static void Format118Finally2( + FastCodeException fce, FastTry fastTry) + { + List tryInstructions = fastTry.instructions; + int tryInstructionsLength = tryInstructions.size(); + + // Remove last 'goto' instruction in try block + if (tryInstructions.get(tryInstructionsLength-1).opcode == + ByteCodeConstants.GOTO) + { + Goto g = (Goto)tryInstructions.remove(--tryInstructionsLength); + fce.tryToOffset = g.offset; + } + + List finallyInstructions = fastTry.finallyInstructions; + int finallyInstructionsLength = finallyInstructions.size(); + + // Update all offset of instructions 'goto' and 'ifxxx' if + // (finallyInstructions.gt(0).offset) < (jump offset) && + // (jump offset) < (finallyInstructions.gt(5).offset) + if (finallyInstructionsLength > 5) + { + int firstFinallyOffset = finallyInstructions.get(0).offset; + int lastFinallyOffset = finallyInstructions.get(5).offset; + + while (tryInstructionsLength-- > 0) + { + Instruction instruction = + tryInstructions.get(tryInstructionsLength); + int jumpOffset; + + switch (instruction.opcode) + { + case ByteCodeConstants.IFCMP: + { + jumpOffset = ((IfCmp)instruction).GetJumpOffset(); + + if ((firstFinallyOffset < jumpOffset) && + (jumpOffset <= lastFinallyOffset)) + ((IfCmp)instruction).branch = + firstFinallyOffset - instruction.offset; + } + break; + case ByteCodeConstants.IF: + case ByteCodeConstants.IFXNULL: + { + jumpOffset = + ((IfInstruction)instruction).GetJumpOffset(); + + if ((firstFinallyOffset < jumpOffset) && + (jumpOffset <= lastFinallyOffset)) + ((IfInstruction)instruction).branch = + firstFinallyOffset - instruction.offset; + } + break; + case ByteCodeConstants.COMPLEXIF: + { + jumpOffset = + ((BranchInstruction)instruction).GetJumpOffset(); + + if ((firstFinallyOffset < jumpOffset) && + (jumpOffset <= lastFinallyOffset)) + ((ComplexConditionalBranchInstruction)instruction).branch = + firstFinallyOffset - instruction.offset; + } + break; + case ByteCodeConstants.GOTO: + { + jumpOffset = ((Goto)instruction).GetJumpOffset(); + + if ((firstFinallyOffset < jumpOffset) && + (jumpOffset <= lastFinallyOffset)) + ((Goto)instruction).branch = + firstFinallyOffset - instruction.offset; + } + break; + } + } + } + + // Remove last 'ret' instruction in finally block + finallyInstructions.remove(finallyInstructionsLength - 1); + // Remove 'AStore ExceptionLoad' instruction in finally block + finallyInstructions.remove(0); + // Remove 'jsr' instruction in finally block + finallyInstructions.remove(0); + // Remove 'athrow' instruction in finally block + finallyInstructions.remove(0); + // Remove 'jsr' instruction in finally block + finallyInstructions.remove(0); + // Remove 'goto' instruction in finally block + finallyInstructions.remove(0); + // Remove 'AStore ReturnAddressLoad' instruction in finally block + finallyInstructions.remove(0); + } + + private static void Format118FinallyThrow(FastTry fastTry) + { + List finallyInstructions = fastTry.finallyInstructions; + int length = finallyInstructions.size(); + + // Remove last 'ret' instruction in finally block + Instruction i = finallyInstructions.get(--length); + if (i.opcode != ByteCodeConstants.RET) + throw new UnexpectedInstructionException(); + finallyInstructions.remove(length); + // Remove 'AStore ExceptionLoad' instruction in finally block + finallyInstructions.remove(0); + // Remove 'jsr' instruction in finally block + finallyInstructions.remove(0); + // Remove 'athrow' instruction in finally block + finallyInstructions.remove(0); + // Remove 'astore' instruction (returnAddress) in finally block + finallyInstructions.remove(0); + } + + private static void Format118CatchFinally( + FastCodeException fce, FastTry fastTry) + { + List tryInstructions = fastTry.instructions; + int tryInstructionsLength = tryInstructions.size(); + + // Remove last 'goto' instruction in try block + if (tryInstructions.get(--tryInstructionsLength).opcode == + ByteCodeConstants.GOTO) + { + Goto g = (Goto)tryInstructions.remove(tryInstructionsLength); + fce.tryToOffset = g.offset; + } + + // Format catch blockes + int i = fastTry.catches.size()-1; + if (i >= 0) + { + List catchInstructions = + fastTry.catches.get(i).instructions; + int catchInstructionsLength = catchInstructions.size(); + + switch (catchInstructions.get(--catchInstructionsLength).opcode) + { + case ByteCodeConstants.GOTO: + // Remove 'goto' instruction in catch block + catchInstructions.remove(catchInstructionsLength); + // Remove 'jsr' instruction in catch block + catchInstructions.remove(--catchInstructionsLength); + break; + case ByteCodeConstants.RETURN: + case ByteCodeConstants.XRETURN: + // Remove 'jsr' instruction in catch block + catchInstructions.remove(--catchInstructionsLength); + + if ((catchInstructionsLength > 0) && + (catchInstructions.get(catchInstructionsLength-1).opcode == ByteCodeConstants.ATHROW)) + { + // Remove 'return' instruction after a 'throw' instruction + catchInstructions.remove(catchInstructionsLength); + } + + break; + } + + // Remove first catch instruction in each catch block + catchInstructions.remove(0); + + while (i-- > 0) + { + catchInstructions = fastTry.catches.get(i).instructions; + catchInstructionsLength = catchInstructions.size(); + + switch (catchInstructions.get(--catchInstructionsLength).opcode) + { + case ByteCodeConstants.GOTO: + // Remove 'goto' instruction in catch block + Instruction in = + catchInstructions.remove(catchInstructionsLength); + fce.catches.get(i).toOffset = in.offset; + break; + case ByteCodeConstants.RETURN: + case ByteCodeConstants.XRETURN: + // Remove 'jsr' instruction in catch block + catchInstructions.remove(--catchInstructionsLength); + break; + } + + // Remove first catch instruction in each catch block + catchInstructions.remove(0); + } + } + + List finallyInstructions = fastTry.finallyInstructions; + int finallyInstructionsLength = finallyInstructions.size(); + + // Remove last 'ret' instruction in finally block + finallyInstructions.remove(--finallyInstructionsLength); + // Remove 'AStore ExceptionLoad' instruction in finally block + finallyInstructions.remove(0); + // Remove 'jsr' instruction in finally block + finallyInstructions.remove(0); + // Remove 'athrow' instruction in finally block + finallyInstructions.remove(0); + // Remove 'AStore ExceptionLoad' instruction in finally block + finallyInstructions.remove(0); + } + + private static void Format118CatchFinally2( + FastCodeException fce, FastTry fastTry) + { + List tryInstructions = fastTry.instructions; + int tryInstructionsLength = tryInstructions.size(); + + // Remove last 'goto' instruction in try block + if (tryInstructions.get(--tryInstructionsLength).opcode == + ByteCodeConstants.GOTO) + { + Goto g = (Goto)tryInstructions.remove(tryInstructionsLength); + fce.tryToOffset = g.offset; + } + + // Format catch blockes + int i = fastTry.catches.size(); + while (i-- > 0) + { + List catchInstructions = fastTry.catches.get(i).instructions; + int catchInstructionsLength = catchInstructions.size(); + // Remove 'goto' instruction in catch block + Instruction in = + catchInstructions.remove(catchInstructionsLength - 1); + fce.catches.get(i).toOffset = in.offset; + // Remove first catch instruction in each catch block + catchInstructions.remove(0); + } + + // Remove 'Pop ExceptionLoad' instruction in finally block + List finallyInstructions = fastTry.finallyInstructions; + finallyInstructions.remove(0); + } + + /* Deux variantes existes. La sous procedure [finally] ne se trouve pas + * toujours dans le block 'finally'. + */ + private static void Format131CatchFinally( + LocalVariables localVariables, FastCodeException fce, FastTry fastTry) + { + List tryInstructions = fastTry.instructions; + int length = tryInstructions.size(); + + // Remove last 'goto' instruction in try block + if (tryInstructions.get(--length).opcode == ByteCodeConstants.GOTO) + { + Goto g = (Goto)tryInstructions.remove(length); + fce.tryToOffset = g.offset; + } + // Remove JSR instruction in try block before 'return' instruction + int finallyInstructitonsLineNumber = + fastTry.finallyInstructions.get(0).lineNumber; + int jumpOffset = FormatFastTry_RemoveJsrInstructionAndCompactStoreReturn( + tryInstructions, localVariables, finallyInstructitonsLineNumber); + // Remove last 'jsr' instruction in try block + length = tryInstructions.size(); + if (tryInstructions.get(--length).opcode == ByteCodeConstants.JSR) + { + Jsr jsr = (Jsr)tryInstructions.remove(length); + jumpOffset = jsr.GetJumpOffset(); + } + if (jumpOffset == -1) + throw new UnexpectedInstructionException(); + + List finallyInstructions = fastTry.finallyInstructions; + + if (jumpOffset < finallyInstructions.get(0).offset) + { + // La sous procedure [finally] se trouve dans l'un des blocs 'catch'. + + // Recherche et extraction de la sous procedure + int i = fastTry.catches.size(); + while (i-- > 0) + { + List catchInstructions = + fastTry.catches.get(i).instructions; + + if ((catchInstructions.size() == 0) || + (catchInstructions.get(0).offset > jumpOffset)) + continue; + + // Extract + int index = + InstructionUtil.getIndexForOffset(catchInstructions, jumpOffset); + finallyInstructions.clear(); + + while (catchInstructions.get(index).opcode != ByteCodeConstants.RET) + finallyInstructions.add(catchInstructions.remove(index)); + if (catchInstructions.get(index).opcode == ByteCodeConstants.RET) + finallyInstructions.add(catchInstructions.remove(index)); + + break; + } + + // Format catch blockes + i = fastTry.catches.size(); + while (i-- > 0) + { + List catchInstructions = + fastTry.catches.get(i).instructions; + length = catchInstructions.size(); + + // Remove last 'goto' instruction + if (catchInstructions.get(--length).opcode == ByteCodeConstants.GOTO) + { + Goto g = (Goto)catchInstructions.remove(length); + fce.catches.get(i).toOffset = g.offset; + } + // Remove last 'jsr' instruction + if (catchInstructions.get(--length).opcode == ByteCodeConstants.JSR) + catchInstructions.remove(length); + // Remove JSR instruction in try block before 'return' instruction + FormatFastTry_RemoveJsrInstructionAndCompactStoreReturn( + catchInstructions, localVariables, + finallyInstructitonsLineNumber); + // Remove first catch instruction in each catch block + catchInstructions.remove(0); + } + + // Format finally block + length = finallyInstructions.size(); + + // Remove last 'ret' instruction in finally block + finallyInstructions.remove(--length); + // Remove 'AStore ReturnAddressLoad' instruction in finally block + finallyInstructions.remove(0); + } + else + { + // La sous procedure [finally] se trouve dans le bloc 'finally'. + + // Format catch blockes + int i = fastTry.catches.size(); + while (i-- > 0) + { + List catchInstructions = + fastTry.catches.get(i).instructions; + length = catchInstructions.size(); + + // Remove last 'goto' instruction + if (catchInstructions.get(--length).opcode == ByteCodeConstants.GOTO) + { + Goto g = (Goto)catchInstructions.remove(length); + fce.catches.get(i).toOffset = g.offset; + } + // Remove last 'jsr' instruction + if (catchInstructions.get(--length).opcode == ByteCodeConstants.JSR) + catchInstructions.remove(length); + // Remove JSR instruction in try block before 'return' instruction + FormatFastTry_RemoveJsrInstructionAndCompactStoreReturn( + catchInstructions, localVariables, + finallyInstructitonsLineNumber); + // Remove first catch instruction in each catch block + catchInstructions.remove(0); + } + + // Format finally block + length = finallyInstructions.size(); + + // Remove last 'ret' instruction in finally block + finallyInstructions.remove(--length); + // Remove 'AStore ExceptionLoad' instruction in finally block + finallyInstructions.remove(0); + // Remove 'jsr' instruction in finally block + finallyInstructions.remove(0); + // Remove 'athrow' instruction in finally block + finallyInstructions.remove(0); + // Remove 'astore' instruction in finally block + finallyInstructions.remove(0); + } + } + + private static void Format142( + LocalVariables localVariables, FastCodeException fce, FastTry fastTry) + { + List finallyInstructions = fastTry.finallyInstructions; + int finallyInstructitonsSize = finallyInstructions.size(); + + // Remove last 'athrow' instruction in finally block + if (finallyInstructions.get(finallyInstructitonsSize-1).opcode == + ByteCodeConstants.ATHROW) + { + finallyInstructions.remove(finallyInstructitonsSize-1); + } + // Remove 'astore' or 'monitorexit' instruction in finally block + switch (finallyInstructions.get(0).opcode) + { + case ByteCodeConstants.ASTORE: + case ByteCodeConstants.POP: + finallyInstructions.remove(0); + } + finallyInstructitonsSize = finallyInstructions.size(); + + if (finallyInstructitonsSize > 0) + { + FastCompareInstructionVisitor visitor = + new FastCompareInstructionVisitor(); + + List tryInstructions = fastTry.instructions; + int length = tryInstructions.size(); + + switch (tryInstructions.get(length-1).opcode) + { + case ByteCodeConstants.GOTO: + // Remove last 'goto' instruction in try block + Goto g = (Goto)tryInstructions.get(--length); + if (g.branch > 0) + { + tryInstructions.remove(length); + fce.tryToOffset = g.offset; + } + break; + } + + // Remove finally instructions in try block before 'return' instruction + Format142_RemoveFinallyInstructionsBeforeReturnAndCompactStoreReturn( + localVariables, visitor, tryInstructions, finallyInstructions); + + if (fastTry.catches != null) + { + // Format catch blockes + int i = fastTry.catches.size(); + while (i-- > 0) + { + List catchInstructions = + fastTry.catches.get(i).instructions; + length = catchInstructions.size(); + + switch (catchInstructions.get(length-1).opcode) + { + case ByteCodeConstants.GOTO: + // Remove last 'goto' instruction in try block + Goto g = (Goto)catchInstructions.get(--length); + if (g.branch > 0) + { + catchInstructions.remove(length); + fce.catches.get(i).toOffset = g.offset; + } + break; + } + + // Remove finally instructions before 'return' instruction + Format142_RemoveFinallyInstructionsBeforeReturnAndCompactStoreReturn( + localVariables, visitor, catchInstructions, finallyInstructions); + // Remove first catch instruction in each catch block + if (catchInstructions.size() > 0) + catchInstructions.remove(0); + } + } + } + } + + private static void Format142_RemoveFinallyInstructionsBeforeReturnAndCompactStoreReturn( + LocalVariables localVariables, + FastCompareInstructionVisitor visitor, + List instructions, + List finallyInstructions) + { + int index = instructions.size(); + int finallyInstructitonsSize = finallyInstructions.size(); + int finallyInstructitonsLineNumber = finallyInstructions.get(0).lineNumber; + + boolean match = (index >= finallyInstructitonsSize) && visitor.visit( + instructions, finallyInstructions, + index-finallyInstructitonsSize, 0, finallyInstructitonsSize); + + // Remove last finally instructions + if (match) + { + for (int j=0; j0; ++j) + instructions.remove(--index); + } + + while (index-- > 0) + { + Instruction instruction = instructions.get(index); + + switch (instruction.opcode) + { + case ByteCodeConstants.RETURN: + case ByteCodeConstants.ATHROW: + { + match = (index >= finallyInstructitonsSize) && visitor.visit( + instructions, finallyInstructions, + index-finallyInstructitonsSize, 0, finallyInstructitonsSize); + + if (match) + { + // Remove finally instructions + for (int j=0; j0; ++j) + instructions.remove(--index); + } + + if ((instruction.lineNumber != Instruction.UNKNOWN_LINE_NUMBER) && + (instruction.lineNumber >= finallyInstructitonsLineNumber)) + { + instruction.lineNumber = Instruction.UNKNOWN_LINE_NUMBER; + } + } + break; + case ByteCodeConstants.XRETURN: + { + match = (index >= finallyInstructitonsSize) && visitor.visit( + instructions, finallyInstructions, + index-finallyInstructitonsSize, 0, finallyInstructitonsSize); + + if (match) + { + // Remove finally instructions + for (int j=0; j0; ++j) + instructions.remove(--index); + } + + // Compact AStore + Return + ReturnInstruction ri = (ReturnInstruction)instruction; + + if (ri.lineNumber != Instruction.UNKNOWN_LINE_NUMBER) + { + switch (ri.valueref.opcode) + { + case ByteCodeConstants.ALOAD: + if (instructions.get(index-1).opcode == ByteCodeConstants.ASTORE) + index = CompactStoreReturn( + instructions, localVariables, ri, + index, finallyInstructitonsLineNumber); + break; + case ByteCodeConstants.LOAD: + if (instructions.get(index-1).opcode == ByteCodeConstants.STORE) + index = CompactStoreReturn( + instructions, localVariables, ri, + index, finallyInstructitonsLineNumber); + break; + case ByteCodeConstants.ILOAD: + if (instructions.get(index-1).opcode == ByteCodeConstants.ISTORE) + index = CompactStoreReturn( + instructions, localVariables, ri, + index, finallyInstructitonsLineNumber); + break; + } + } + } + break; + case FastConstants.TRY: + { + // Recursive calls + FastTry ft = (FastTry)instruction; + + Format142_RemoveFinallyInstructionsBeforeReturnAndCompactStoreReturn( + localVariables, visitor, + ft.instructions, finallyInstructions); + + if (ft.catches != null) + { + int i = ft.catches.size(); + while (i-- > 0) + { + Format142_RemoveFinallyInstructionsBeforeReturnAndCompactStoreReturn( + localVariables, visitor, + ft.catches.get(i).instructions, finallyInstructions); + } + } + + if (ft.finallyInstructions != null) + { + Format142_RemoveFinallyInstructionsBeforeReturnAndCompactStoreReturn( + localVariables, visitor, + ft.finallyInstructions, finallyInstructions); + } + } + break; + case FastConstants.SYNCHRONIZED: + { + // Recursive calls + FastSynchronized fs = (FastSynchronized)instruction; + + Format142_RemoveFinallyInstructionsBeforeReturnAndCompactStoreReturn( + localVariables, visitor, + fs.instructions, finallyInstructions); + } + break; + } + } + } + + private static int CompactStoreReturn( + List instructions, LocalVariables localVariables, + ReturnInstruction ri, int index, int finallyInstructitonsLineNumber) + { + IndexInstruction load = (IndexInstruction)ri.valueref; + StoreInstruction store = (StoreInstruction)instructions.get(index-1); + + if ((load.index == store.index) && + ((load.lineNumber <= store.lineNumber) || + (load.lineNumber >= finallyInstructitonsLineNumber))) + { + // TODO A ameliorer !! + // Remove local variable + LocalVariable lv = localVariables. + getLocalVariableWithIndexAndOffset( + store.index, store.offset); + + if ((lv != null) && (lv.start_pc == store.offset) && + (lv.start_pc + lv.length <= ri.offset)) + localVariables. + removeLocalVariableWithIndexAndOffset( + store.index, store.offset); + // Replace returned instruction + ri.valueref = store.valueref; + if (ri.lineNumber > store.lineNumber) + ri.lineNumber = store.lineNumber; + // Remove 'store' instruction + instructions.remove(--index); + } + + return index; + } + + private static void Format142FinallyThrow(FastTry fastTry) + { + // Remove last 'athrow' instruction in finally block + fastTry.finallyInstructions.remove(fastTry.finallyInstructions.size()-1); + // Remove 'astore' instruction in finally block + fastTry.finallyInstructions.remove(0); + } + + private static void FormatJikes122( + LocalVariables localVariables, FastCodeException fce, + FastTry fastTry, int returnOffset) + { + List tryInstructions = fastTry.instructions; + int lastIndex = tryInstructions.size()-1; + Instruction lastTryInstruction = tryInstructions.get(lastIndex); + int lastTryInstructionOffset = lastTryInstruction.offset; + + // Remove last 'goto' instruction in try block + if (tryInstructions.get(lastIndex).opcode == ByteCodeConstants.GOTO) + { + Goto g = (Goto)tryInstructions.remove(lastIndex); + fce.tryToOffset = g.offset; + } + // Remove Jsr instruction before return instructions + int finallyInstructitonsLineNumber = + fastTry.finallyInstructions.get(0).lineNumber; + FormatFastTry_RemoveJsrInstructionAndCompactStoreReturn( + tryInstructions, localVariables, finallyInstructitonsLineNumber); + + // Format catch blockes + int i = fastTry.catches.size(); + while (i-- > 0) + { + List catchInstructions = + fastTry.catches.get(i).instructions; + lastIndex = catchInstructions.size()-1; + + // Remove last 'goto' instruction in try block + if (catchInstructions.get(lastIndex).opcode == ByteCodeConstants.GOTO) + { + Goto g = (Goto)catchInstructions.remove(lastIndex); + fce.catches.get(i).toOffset = g.offset; + } + // Remove Jsr instruction before return instructions + FormatFastTry_RemoveJsrInstructionAndCompactStoreReturn( + catchInstructions, localVariables, + finallyInstructitonsLineNumber); + // Change negative jump goto to return offset + FormatFastTry_FormatNegativeJumpOffset( + catchInstructions, lastTryInstructionOffset, returnOffset); + // Remove first catch instruction in each catch block + catchInstructions.remove(0); + } + + List finallyInstructions = fastTry.finallyInstructions; + int length = finallyInstructions.size(); + + // Remove last 'jsr' instruction in finally block + finallyInstructions.remove(--length); + // Remove last 'ret' or 'athrow' instruction in finally block + finallyInstructions.remove(--length); + // Remove 'AStore ExceptionLoad' instruction in finally block + finallyInstructions.remove(0); + // Remove 'jsr' instruction in finally block + if (finallyInstructions.get(0).opcode == ByteCodeConstants.JSR) + finallyInstructions.remove(0); + // Remove 'athrow' instruction in finally block + if (finallyInstructions.get(0).opcode == ByteCodeConstants.ATHROW) + finallyInstructions.remove(0); + // Remove 'astore' instruction in finally block + if (finallyInstructions.get(0).opcode == ByteCodeConstants.ASTORE) + finallyInstructions.remove(0); + } + + private static int FormatFastTry_RemoveJsrInstructionAndCompactStoreReturn( + List instructions, LocalVariables localVariables, + int finallyInstructitonsLineNumber) + { + int jumpOffset = UtilConstants.INVALID_OFFSET; + int index = instructions.size(); + + while (index-- > 1) + { + if (instructions.get(index).opcode == ByteCodeConstants.JSR) + { + // Remove Jsr instruction + Jsr jsr = (Jsr)instructions.remove(index); + jumpOffset = jsr.GetJumpOffset(); + } + } + + index = instructions.size(); + + while (index-- > 1) + { + Instruction instruction = instructions.get(index); + + if (instruction.opcode == ByteCodeConstants.XRETURN) + { + // Compact AStore + Return + ReturnInstruction ri = (ReturnInstruction)instruction; + + if (ri.lineNumber != Instruction.UNKNOWN_LINE_NUMBER) + { + switch (ri.valueref.opcode) + { + case ByteCodeConstants.ALOAD: + if (instructions.get(index-1).opcode == ByteCodeConstants.ASTORE) + index = CompactStoreReturn( + instructions, localVariables, ri, + index, finallyInstructitonsLineNumber); + break; + case ByteCodeConstants.LOAD: + if (instructions.get(index-1).opcode == ByteCodeConstants.STORE) + index = CompactStoreReturn( + instructions, localVariables, ri, + index, finallyInstructitonsLineNumber); + break; + case ByteCodeConstants.ILOAD: + if (instructions.get(index-1).opcode == ByteCodeConstants.ISTORE) + index = CompactStoreReturn( + instructions, localVariables, ri, + index, finallyInstructitonsLineNumber); + break; + } + } + } + } + + return jumpOffset; + } + + private static void FormatFastTry_FormatNegativeJumpOffset( + List instructions, + int lastTryInstructionOffset, int returnOffset) + { + int i = instructions.size(); + + while (i-- > 0) + { + Instruction instruction = instructions.get(i); + + switch (instruction.opcode) + { + case ByteCodeConstants.GOTO: + Goto g = (Goto)instruction; + int jumpOffset = g.GetJumpOffset(); + + if (jumpOffset < lastTryInstructionOffset) + { + // Change jump offset + g.branch = returnOffset - g.offset; + } + break; + } + } + } + + private static void FormatEclipse677Finally( + FastCodeException fce, FastTry fastTry) + { + // Remove instructions in finally block + List finallyInstructions = fastTry.finallyInstructions; + + Instruction instruction = finallyInstructions.get(0); + + switch (instruction.opcode) + { + case ByteCodeConstants.POP: + { + // Remove 'pop' instruction in finally block + finallyInstructions.remove(0); + + List tryInstructions = fastTry.instructions; + int lastIndex = tryInstructions.size()-1; + + // Remove last 'goto' instruction in try block + if (tryInstructions.get(lastIndex).opcode == ByteCodeConstants.GOTO) + { + Goto g = (Goto)tryInstructions.remove(lastIndex); + fce.tryToOffset = g.offset; + } + } + break; + + case ByteCodeConstants.ASTORE: + { + int exceptionIndex = ((AStore)instruction).index; + int index = finallyInstructions.size(); + int athrowOffset = -1; + int afterAthrowOffset = -1; + + // Search throw instruction + while (index-- > 0) + { + instruction = finallyInstructions.get(index); + if (instruction.opcode == ByteCodeConstants.ATHROW) + { + AThrow athrow = (AThrow)instruction; + if ((athrow.value.opcode == ByteCodeConstants.ALOAD) && + ( ((ALoad)athrow.value).index == exceptionIndex )) + { + // Remove last 'athrow' instruction in finally block + athrowOffset = instruction.offset; + finallyInstructions.remove(index); + break; + } + } + afterAthrowOffset = instruction.offset; + finallyInstructions.remove(index); + } + + // Remove 'astore' instruction in finally block + Instruction astore = finallyInstructions.remove(0); + + List tryInstructions = fastTry.instructions; + int lastIndex = tryInstructions.size()-1; + + // Remove last 'goto' instruction in try block + if (tryInstructions.get(lastIndex).opcode == ByteCodeConstants.GOTO) + { + Goto g = (Goto)tryInstructions.remove(lastIndex); + fce.tryToOffset = g.offset; + } + + // Remove finally instructions before 'return' instruction + int finallyInstructitonsSize = finallyInstructions.size(); + FormatEclipse677Finally_RemoveFinallyInstructionsBeforeReturn( + tryInstructions, finallyInstructitonsSize); + + // Format 'ifxxx' instruction jumping to finally block + FormatEclipse677Finally_FormatIfInstruction( + tryInstructions, athrowOffset, afterAthrowOffset, astore.offset); + } + break; + } + } + + private static void FormatEclipse677Finally_FormatIfInstruction( + List instructions, int athrowOffset, + int afterAthrowOffset, int afterTryOffset) + { + int i = instructions.size(); + + while (i-- > 0) + { + Instruction instruction = instructions.get(i); + + switch (instruction.opcode) + { + case ByteCodeConstants.IF: + case ByteCodeConstants.IFXNULL: + case ByteCodeConstants.COMPLEXIF: + IfInstruction ifi = (IfInstruction)instruction; + int jumpOffset = ifi.GetJumpOffset(); + + if ((athrowOffset < jumpOffset) && (jumpOffset <= afterAthrowOffset)) + { + // Change jump offset + ifi.branch = afterTryOffset - ifi.offset; + } + break; + } + } + } + + private static void FormatEclipse677Finally_RemoveFinallyInstructionsBeforeReturn( + List instructions, int finallyInstructitonsSize) + { + int i = instructions.size(); + + while (i-- > 0) + { + switch (instructions.get(i).opcode) + { + case ByteCodeConstants.RETURN: + case ByteCodeConstants.XRETURN: + // Remove finally instructions + for (int j=0; j0; ++j) + instructions.remove(--i); + break; + } + } + } + + private static void FormatEclipse677CatchFinally( + FastCodeException fce, FastTry fastTry, int returnOffset) + { + // Remove instructions in finally block + List finallyInstructions = fastTry.finallyInstructions; + + int exceptionIndex = ((AStore)finallyInstructions.get(0)).index; + int index = finallyInstructions.size(); + int athrowOffset = -1; + int afterAthrowOffset = -1; + + // Search throw instruction + while (index-- > 0) + { + Instruction instruction = finallyInstructions.get(index); + if (instruction.opcode == ByteCodeConstants.ATHROW) + { + AThrow athrow = (AThrow)instruction; + if ((athrow.value.opcode == ByteCodeConstants.ALOAD) && + ( ((ALoad)athrow.value).index == exceptionIndex )) + { + // Remove last 'athrow' instruction in finally block + athrowOffset = finallyInstructions.remove(index).offset; + break; + } + } + afterAthrowOffset = instruction.offset; + finallyInstructions.remove(index); + } + + // Remove 'astore' instruction in finally block + finallyInstructions.remove(0); + + List tryInstructions = fastTry.instructions; + int lastIndex = tryInstructions.size()-1; + Instruction lastTryInstruction = tryInstructions.get(lastIndex); + int lastTryInstructionOffset = lastTryInstruction.offset; + + // Remove last 'goto' instruction in try block + if (lastTryInstruction.opcode == ByteCodeConstants.GOTO) + { + Goto g = (Goto)tryInstructions.remove(lastIndex); + fce.tryToOffset = g.offset; + } + + // Remove finally instructions before 'return' instruction + int finallyInstructitonsSize = finallyInstructions.size(); + FormatEclipse677Finally_RemoveFinallyInstructionsBeforeReturn( + tryInstructions, finallyInstructitonsSize); + + // Format 'ifxxx' instruction jumping to finally block + FormatEclipse677Finally_FormatIfInstruction( + tryInstructions, athrowOffset, + afterAthrowOffset, lastTryInstructionOffset+1); + + // Format catch blockes + int i = fastTry.catches.size(); + while (i-- > 0) + { + FastCatch fastCatch = fastTry.catches.get(i); + List catchInstructions = fastCatch.instructions; + index = catchInstructions.size(); + + Instruction lastInstruction = catchInstructions.get(index-1); + int lastInstructionOffset = lastInstruction.offset; + + if (lastInstruction.opcode == ByteCodeConstants.GOTO) + { + // Remove last 'goto' instruction + Goto g = (Goto)catchInstructions.remove(--index); + fce.catches.get(i).toOffset = g.offset; + int jumpOffset = g.GetJumpOffset(); + + if (jumpOffset > fastTry.offset) + { + // Remove finally block instructions + for (int j=finallyInstructitonsSize; j>0; --j) + catchInstructions.remove(--index); + } + } + + // Remove finally instructions before 'return' instruction + FormatEclipse677Finally_RemoveFinallyInstructionsBeforeReturn( + catchInstructions, finallyInstructitonsSize); + + // Format 'ifxxx' instruction jumping to finally block + FormatEclipse677Finally_FormatIfInstruction( + catchInstructions, athrowOffset, + afterAthrowOffset, lastInstructionOffset+1); + + // Change negative jump goto to return offset + FormatFastTry_FormatNegativeJumpOffset( + catchInstructions, lastTryInstructionOffset, returnOffset); + + // Remove first catch instruction in each catch block + catchInstructions.remove(0); + } + } + + public static class FastCodeException + implements Comparable + { + public int tryFromOffset; + public int tryToOffset; + public List catches; + public int finallyFromOffset; + public int nbrFinally; + public int maxOffset; + public int afterOffset; + public int type; + public boolean synchronizedFlag; + + FastCodeException( + int tryFromOffset, int tryToOffset, + int maxOffset, boolean synchronizedFlag) + { + this.tryFromOffset = tryFromOffset; + this.tryToOffset = tryToOffset; + this.catches = new ArrayList(); + this.finallyFromOffset = UtilConstants.INVALID_OFFSET; + this.nbrFinally = 0; + this.maxOffset = maxOffset; + this.afterOffset = UtilConstants.INVALID_OFFSET; + this.type = FastConstants.TYPE_UNDEFINED; + this.synchronizedFlag = synchronizedFlag; + } + + public int compareTo(FastCodeException other) + { + // Sort by 1)tryFromOffset 2)maxOffset 3)tryToOffset + if (this.tryFromOffset != other.tryFromOffset) + return this.tryFromOffset - other.tryFromOffset; + + if (this.maxOffset != other.maxOffset) + return other.maxOffset - this.maxOffset; + + return other.tryToOffset - this.tryToOffset; + } + } + + public static class FastCodeExceptionCatch + implements Comparable + { + public int type; + public int otherTypes[]; + public int fromOffset; + public int toOffset; + + public FastCodeExceptionCatch( + int type, int otherCatchTypes[], int fromOffset) + { + this.type = type; + this.otherTypes = otherCatchTypes; + this.fromOffset = fromOffset; + this.toOffset = UtilConstants.INVALID_OFFSET; + } + + public int compareTo(FastCodeExceptionCatch other) + { + return this.fromOffset - other.fromOffset; + } + } + + public static class FastAggregatedCodeException extends CodeException + { + public int otherCatchTypes[]; + public int nbrFinally; + public boolean synchronizedFlag = false; + + public FastAggregatedCodeException( + int index, int start_pc, int end_pc, int handler_pc, int catch_type) + { + super(index, start_pc, end_pc, handler_pc, catch_type); + this.otherCatchTypes = null; + this.nbrFinally = (catch_type == 0) ? 1 : 0; + } + } + + public static int ComputeTryToIndex( + List instructions, FastCodeException fce, + int lastIndex, int maxOffset) + { + // Parcours + int beforeMaxOffset = fce.tryFromOffset; + int index = InstructionUtil.getIndexForOffset( + instructions, fce.tryFromOffset); + + while (index <= lastIndex) + { + Instruction instruction = instructions.get(index); + + if (instruction.offset > maxOffset) + return index-1; + + switch (instruction.opcode) + { + case ByteCodeConstants.ATHROW: + case ByteCodeConstants.RETURN: + case ByteCodeConstants.XRETURN: + { + if (instruction.offset >= beforeMaxOffset) + return index; // Inclus au bloc 'try' + } + break; + case ByteCodeConstants.GOTO: + { + int jumpOffset = ((BranchInstruction)instruction).GetJumpOffset(); + + if (jumpOffset > instruction.offset) + { + // Saut positif + if (jumpOffset < maxOffset) + { + // Saut dans les limites + if (beforeMaxOffset < jumpOffset) + beforeMaxOffset = jumpOffset; + } + else + { + // Saut au del� des limites + if (instruction.offset >= beforeMaxOffset) + return index; // Inclus au bloc 'try' + } + } + else + { + // Saut negatif + if (jumpOffset < fce.tryFromOffset) + { + // Saut au del� des limites + if (instruction.offset >= beforeMaxOffset) + return index; // Inclus au bloc 'try' + } + } + } + break; + case ByteCodeConstants.IFCMP: + case ByteCodeConstants.IF: + case ByteCodeConstants.IFXNULL: + { + // L'aggregation des instructions 'if' n'a pas + // encore ete executee. Recherche du plus petit + // offset de saut parmi toutes les instructions + // 'if' qui suivent. + index = ComparisonInstructionAnalyzer.GetLastIndex(instructions, index); + BranchInstruction lastBi = (BranchInstruction)instructions.get(index); + int jumpOffset = lastBi.GetJumpOffset(); + + if (jumpOffset > instruction.offset) + { + // Saut positif + if (jumpOffset < maxOffset) + { + // Saut dans les limites + if (beforeMaxOffset < jumpOffset) + beforeMaxOffset = jumpOffset; + } + // else + // { + // // Saut au del� des limites, 'break' ? + // } + } + // else + // { + // // Saut negatif, 'continue' ? + //} + } + break; + case FastConstants.LOOKUPSWITCH: + case FastConstants.TABLESWITCH: + { + Switch s = (Switch)instruction; + + // Search max offset + int maxSitchOffset = s.defaultOffset; + int i = s.offsets.length; + while (i-- > 0) + { + int offset = s.offsets[i]; + if (maxSitchOffset < offset) + maxSitchOffset = offset; + } + maxSitchOffset += s.offset; + + if (maxSitchOffset > instruction.offset) + { + // Saut positif + if (maxSitchOffset < maxOffset) + { + // Saut dans les limites + if (beforeMaxOffset < maxSitchOffset) + beforeMaxOffset = maxSitchOffset; + } + // else + // { + // // Saut au del� des limites, 'break' ? + // } + } + // else + // { + // // Saut negatif, 'continue' ? + //} + break; + } + } + + index++; + } + + return index; + } +} \ No newline at end of file diff --git a/src/jd/core/process/analyzer/instruction/fast/FastInstructionListBuilder.java b/src/jd/core/process/analyzer/instruction/fast/FastInstructionListBuilder.java new file mode 100644 index 00000000..ad153c2f --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/fast/FastInstructionListBuilder.java @@ -0,0 +1,4364 @@ +package jd.core.process.analyzer.instruction.fast; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariable; +import jd.core.model.classfile.LocalVariables; +import jd.core.model.classfile.Method; +import jd.core.model.classfile.attribute.AttributeSignature; +import jd.core.model.classfile.constant.ConstantFieldref; +import jd.core.model.classfile.constant.ConstantMethodref; +import jd.core.model.classfile.constant.ConstantNameAndType; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.ALoad; +import jd.core.model.instruction.bytecode.instruction.AStore; +import jd.core.model.instruction.bytecode.instruction.AThrow; +import jd.core.model.instruction.bytecode.instruction.ArrayLength; +import jd.core.model.instruction.bytecode.instruction.ArrayLoadInstruction; +import jd.core.model.instruction.bytecode.instruction.AssignmentInstruction; +import jd.core.model.instruction.bytecode.instruction.BIPush; +import jd.core.model.instruction.bytecode.instruction.BranchInstruction; +import jd.core.model.instruction.bytecode.instruction.CheckCast; +import jd.core.model.instruction.bytecode.instruction.ConditionalBranchInstruction; +import jd.core.model.instruction.bytecode.instruction.DupStore; +import jd.core.model.instruction.bytecode.instruction.ExceptionLoad; +import jd.core.model.instruction.bytecode.instruction.GetStatic; +import jd.core.model.instruction.bytecode.instruction.Goto; +import jd.core.model.instruction.bytecode.instruction.IConst; +import jd.core.model.instruction.bytecode.instruction.IInc; +import jd.core.model.instruction.bytecode.instruction.ILoad; +import jd.core.model.instruction.bytecode.instruction.IStore; +import jd.core.model.instruction.bytecode.instruction.IfCmp; +import jd.core.model.instruction.bytecode.instruction.IfInstruction; +import jd.core.model.instruction.bytecode.instruction.IndexInstruction; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.InvokeNoStaticInstruction; +import jd.core.model.instruction.bytecode.instruction.Invokestatic; +import jd.core.model.instruction.bytecode.instruction.Invokevirtual; +import jd.core.model.instruction.bytecode.instruction.Jsr; +import jd.core.model.instruction.bytecode.instruction.Ldc; +import jd.core.model.instruction.bytecode.instruction.LoadInstruction; +import jd.core.model.instruction.bytecode.instruction.LookupSwitch; +import jd.core.model.instruction.bytecode.instruction.MonitorEnter; +import jd.core.model.instruction.bytecode.instruction.MonitorExit; +import jd.core.model.instruction.bytecode.instruction.Return; +import jd.core.model.instruction.bytecode.instruction.ReturnInstruction; +import jd.core.model.instruction.bytecode.instruction.StoreInstruction; +import jd.core.model.instruction.bytecode.instruction.Switch; +import jd.core.model.instruction.bytecode.instruction.TableSwitch; +import jd.core.model.instruction.fast.FastConstants; +import jd.core.model.instruction.fast.instruction.FastDeclaration; +import jd.core.model.instruction.fast.instruction.FastFor; +import jd.core.model.instruction.fast.instruction.FastForEach; +import jd.core.model.instruction.fast.instruction.FastInstruction; +import jd.core.model.instruction.fast.instruction.FastLabel; +import jd.core.model.instruction.fast.instruction.FastList; +import jd.core.model.instruction.fast.instruction.FastSwitch; +import jd.core.model.instruction.fast.instruction.FastSwitch.Pair; +import jd.core.model.instruction.fast.instruction.FastSynchronized; +import jd.core.model.instruction.fast.instruction.FastTest2Lists; +import jd.core.model.instruction.fast.instruction.FastTestList; +import jd.core.model.instruction.fast.instruction.FastTry; +import jd.core.model.instruction.fast.instruction.FastTry.FastCatch; +import jd.core.model.reference.ReferenceMap; +import jd.core.process.analyzer.classfile.reconstructor.AssignmentOperatorReconstructor; +import jd.core.process.analyzer.classfile.visitor.SearchInstructionByOpcodeVisitor; +import jd.core.process.analyzer.instruction.bytecode.ComparisonInstructionAnalyzer; +import jd.core.process.analyzer.instruction.bytecode.reconstructor.AssertInstructionReconstructor; +import jd.core.process.analyzer.instruction.bytecode.util.ByteCodeUtil; +import jd.core.process.analyzer.instruction.fast.FastCodeExceptionAnalyzer.FastCodeException; +import jd.core.process.analyzer.instruction.fast.FastCodeExceptionAnalyzer.FastCodeExceptionCatch; +import jd.core.process.analyzer.instruction.fast.reconstructor.DotClass118BReconstructor; +import jd.core.process.analyzer.instruction.fast.reconstructor.DotClassEclipseReconstructor; +import jd.core.process.analyzer.instruction.fast.reconstructor.EmptySynchronizedBlockReconstructor; +import jd.core.process.analyzer.instruction.fast.reconstructor.IfGotoToIfReconstructor; +import jd.core.process.analyzer.instruction.fast.reconstructor.InitArrayInstructionReconstructor; +import jd.core.process.analyzer.instruction.fast.reconstructor.RemoveDupConstantsAttributes; +import jd.core.process.analyzer.instruction.fast.reconstructor.TernaryOpInReturnReconstructor; +import jd.core.process.analyzer.instruction.fast.reconstructor.TernaryOpReconstructor; +import jd.core.process.analyzer.util.InstructionUtil; +import jd.core.util.IntSet; +import jd.core.util.SignatureUtil; +import jd.core.util.StringConstants; + +/* + * Analyze + * | + * v + * AnalyzeList <-----------------+ <-----------------------------+ <--+ + * | | | | | | | + * | | | v | 1)Remove continue inst. | | + * | | | AnalyzeBackIf -->AnalyzeLoop 2)Call AnalyzeList | | + * | | v | 3)Remove break & | | + * | | AnalyzeBackGoto --------+ labeled break | | + * | v | | + * | AnalyzeIfAndIfElse ----------------------------------------+ | + * v | + * AnalyzeXXXXSwitch -------------------------------------------------+ + */ +public class FastInstructionListBuilder { + // Declaration constants + private static final boolean DECLARED = true; + private static final boolean NOT_DECLARED = false; + + /* + * debut de liste fin de liste | | Liste ... + * --|----|---|==0===1===2===3===4===5===6==7=...=n---|--| ... + */ + public static void Build(ReferenceMap referenceMap, ClassFile classFile, Method method, List list) + throws Exception { + if ((list == null) || list.isEmpty()) + return; + + // Agregation des declarations CodeException + List lfce = FastCodeExceptionAnalyzer.AggregateCodeExceptions(method, list); + + // Initialyze delaclation flags + LocalVariables localVariables = method.getLocalVariables(); + InitDelcarationFlags(localVariables); + + // Initialisation de l'ensemle des offsets d'etiquette + IntSet offsetLabelSet = new IntSet(); + + // Initialisation de 'returnOffset' ... + int returnOffset = -1; + if (list.size() > 0) { + Instruction instruction = list.get(list.size() - 1); + if (instruction.opcode == ByteCodeConstants.RETURN) + returnOffset = instruction.offset; + } + + // Recursive call + if (lfce != null) + for (int i = lfce.size() - 1; i >= 0; --i) { + FastCodeException fce = lfce.get(i); + if (fce.synchronizedFlag) + CreateSynchronizedBlock(referenceMap, classFile, list, localVariables, fce); + else + CreateFastTry(referenceMap, classFile, method, list, localVariables, fce, returnOffset); + } + + ExecuteReconstructors(referenceMap, classFile, list, localVariables); + + AnalyzeList(classFile, method, list, localVariables, offsetLabelSet, -1, -1, -1, -1, -1, -1, returnOffset); + + // Add labels + if (offsetLabelSet.size() > 0) + AddLabels(list, offsetLabelSet); + } + + private static void InitDelcarationFlags(LocalVariables localVariables) { + int nbrOfLocalVariables = localVariables.size(); + int indexOfFirstLocalVariable = localVariables.getIndexOfFirstLocalVariable(); + + for (int i = 0; i < indexOfFirstLocalVariable && i < nbrOfLocalVariables; ++i) + localVariables.getLocalVariableAt(i).declarationFlag = DECLARED; + + for (int i = indexOfFirstLocalVariable; i < nbrOfLocalVariables; ++i) { + LocalVariable lv = localVariables.getLocalVariableAt(i); + lv.declarationFlag = lv.exceptionOrReturnAddress ? DECLARED : NOT_DECLARED; + } + } + + private static void CreateSynchronizedBlock(ReferenceMap referenceMap, ClassFile classFile, List list, + LocalVariables localVariables, FastCodeException fce) { + int index = InstructionUtil.getIndexForOffset(list, fce.tryFromOffset); + Instruction instruction = list.get(index); + int synchronizedBlockJumpOffset = -1; + + if (fce.type == FastConstants.TYPE_118_FINALLY) { + // Retrait de la sous proc�dure allant de "monitorexit" � "ret" + // Byte code: + // 0: aload_1 + // 1: astore_3 + // 2: aload_3 + // 3: monitorenter <----- tryFromIndex + // 4: aload_0 + // 5: invokevirtual 6 TryCatchFinallyClassForTest:inTry ()V + // 8: iconst_2 + // 9: istore_2 + // 10: jsr +8 -> 18 + // 13: iload_2 + // 14: ireturn + // 15: aload_3 <===== finallyFromOffset + // 16: monitorexit + // 17: athrow + // 18: astore 4 <~~~~~ Entr�e de la sous procecure ('jsr') + // 20: aload_3 + // 21: monitorexit + // 22: ret 4 <----- + + // Save 'index' + int tryFromIndex = index; + + // Search offset of sub procedure entry + index = InstructionUtil.getIndexForOffset(list, fce.finallyFromOffset); + int subProcedureOffset = list.get(index + 2).offset; + + // Remove 'jsr' instructions + while (index-- > tryFromIndex) { + instruction = list.get(index); + if (instruction.opcode != ByteCodeConstants.JSR) + continue; + + int jumpOffset = ((Jsr) instruction).GetJumpOffset(); + list.remove(index); + + if (jumpOffset == subProcedureOffset) + break; + } + + // Remove instructions of finally block + int finallyFromOffset = fce.finallyFromOffset; + index = InstructionUtil.getIndexForOffset(list, fce.afterOffset); + if (index == -1) { + index = list.size() - 1; + while (list.get(index).offset >= finallyFromOffset) + list.remove(index--); + } else if (index > 0) { + index--; + while (list.get(index).offset >= finallyFromOffset) + list.remove(index--); + } + + // Extract try blockes + List instructions = new ArrayList(); + if (index > 0) { + int tryFromOffset = fce.tryFromOffset; + + while (list.get(index).offset >= tryFromOffset) + instructions.add(list.remove(index--)); + } + + int fastSynchronizedOffset; + + if (instructions.size() > 0) { + Instruction lastInstruction = instructions.get(0); + fastSynchronizedOffset = lastInstruction.offset; + } else { + fastSynchronizedOffset = -1; + } + + synchronizedBlockJumpOffset = SearchMinusJumpOffset(instructions, 0, instructions.size(), + fce.tryFromOffset, fce.afterOffset); + Collections.reverse(instructions); + + // Analyze lists of instructions + ExecuteReconstructors(referenceMap, classFile, instructions, localVariables); + + // Remove 'monitorenter (localTestSynchronize1 = xxx)' + MonitorEnter menter = (MonitorEnter) list.remove(index--); + int fastSynchronizedLineNumber = menter.lineNumber; + + // Remove local variable for monitor + if (menter.objectref.opcode != ByteCodeConstants.ALOAD) + throw new UnexpectedInstructionException(); + int varMonitorIndex = ((IndexInstruction) menter.objectref).index; + localVariables.removeLocalVariableWithIndexAndOffset(varMonitorIndex, menter.offset); + + // Search monitor + AStore astore = (AStore) list.get(index); + Instruction monitor = astore.valueref; + + // + int branch = 1; + if ((fastSynchronizedOffset != -1) && (synchronizedBlockJumpOffset != -1)) + branch = synchronizedBlockJumpOffset - fastSynchronizedOffset; + + FastSynchronized fastSynchronized = new FastSynchronized(FastConstants.SYNCHRONIZED, + fastSynchronizedOffset, fastSynchronizedLineNumber, branch, instructions); + fastSynchronized.monitor = monitor; + + // Replace 'astore localTestSynchronize1' + list.set(index, fastSynchronized); + } else if (fce.type == FastConstants.TYPE_118_SYNCHRONIZED_DOUBLE) { + // Byte code: + // 0: getstatic 10 java/lang/System:out Ljava/io/PrintStream; + // 3: ldc 1 + // 5: invokevirtual 11 java/io/PrintStream:println + // (Ljava/lang/String;)V + // 8: aload_0 + // 9: astore_1 + // 10: aload_1 + // 11: monitorenter + // 12: aload_0 + // 13: invokespecial 8 TestSynchronize:getMonitor + // ()Ljava/lang/Object; + // 16: astore 4 + // 18: aload 4 + // 20: monitorenter + // 21: getstatic 10 java/lang/System:out Ljava/io/PrintStream; + // 24: ldc 2 + // 26: invokevirtual 11 java/io/PrintStream:println + // (Ljava/lang/String;)V + // 29: iconst_1 + // 30: istore_3 + // 31: jsr +12 -> 43 + // 34: jsr +19 -> 53 + // 37: iload_3 + // 38: ireturn + // 39: aload 4 + // 41: monitorexit + // 42: athrow + // 43: astore 5 + // 45: aload 4 + // 47: monitorexit + // 48: ret 5 + // 50: aload_1 + // 51: monitorexit + // 52: athrow + // 53: astore_2 + // 54: aload_1 + // 55: monitorexit + // 56: ret 2 + + // Extract try blockes + List instructions = new ArrayList(); + instruction = list.remove(index); + int fastSynchronizedOffset = instruction.offset; + instructions.add(instruction); + + synchronizedBlockJumpOffset = SearchMinusJumpOffset(instructions, 0, instructions.size(), + fce.tryFromOffset, fce.afterOffset); + + // Remove 'monitorenter' + MonitorEnter menter = (MonitorEnter) list.remove(index - 1); + + // Search monitor + AStore astore = (AStore) list.get(index - 2); + Instruction monitor = astore.valueref; + + // Remove local variable for monitor + int varMonitorIndex = astore.index; + localVariables.removeLocalVariableWithIndexAndOffset(varMonitorIndex, menter.offset); + + // + int branch = 1; + if (synchronizedBlockJumpOffset != -1) + branch = synchronizedBlockJumpOffset - fastSynchronizedOffset; + + FastSynchronized fastSynchronized = new FastSynchronized(FastConstants.SYNCHRONIZED, + fastSynchronizedOffset, menter.lineNumber, branch, instructions); + fastSynchronized.monitor = monitor; + + // Replace 'astore localTestSynchronize1' + list.set(index - 2, fastSynchronized); + } else if (instruction.opcode == ByteCodeConstants.MONITOREXIT) { + if (list.get(--index).opcode == ByteCodeConstants.MONITORENTER) { + // Cas particulier des blocks synchronises vides avec le + // jdk 1.1.8. + // Byte code++: + // 3: monitorenter; + // 10: monitorexit; + // 11: return contentEquals(paramStringBuffer); + // 12: localObject = finally; + // 14: monitorexit; + // 16: throw localObject; + // ou + // 5: System.out.println("start"); + // 9: localTestSynchronize = this; + // 11: monitorenter; + // 14: monitorexit; + // 15: goto 21; + // 19: monitorexit; + // 20: throw finally; + // 26: System.out.println("end"); + // Remove previous 'monitorenter' instruction + Instruction monitor; + MonitorEnter me = (MonitorEnter) list.remove(index); + if (me.objectref.opcode == ByteCodeConstants.ASSIGNMENT) { + AssignmentInstruction ai = (AssignmentInstruction) me.objectref; + AStore astore = (AStore) ai.value1; + monitor = ai.value2; + // Remove local variable for monitor + localVariables.removeLocalVariableWithIndexAndOffset(astore.index, astore.offset); + // Remove 'monitorexit' instruction + list.remove(index); + } else { + // Remove 'monitorexit' instruction + list.remove(index); + // Remove 'astore' + AStore astore = (AStore) list.remove(--index); + monitor = astore.valueref; + // Remove local variable for monitor + localVariables.removeLocalVariableWithIndexAndOffset(astore.index, astore.offset); + } + + List instructions = new ArrayList(); + Instruction gi = list.remove(index); + + if ((gi.opcode != ByteCodeConstants.GOTO) || (((Goto) gi).GetJumpOffset() != fce.afterOffset)) + instructions.add(gi); + + // Remove 'localObject = finally' instruction + if (list.get(index).opcode == ByteCodeConstants.ASTORE) + list.remove(index); + // Remove 'monitorexit' instruction + Instruction monitorexit = list.remove(index); + + // Analyze lists of instructions + ExecuteReconstructors(referenceMap, classFile, instructions, localVariables); + + // + FastSynchronized fastSynchronized = new FastSynchronized(FastConstants.SYNCHRONIZED, + monitorexit.offset, instruction.lineNumber, 1, instructions); + fastSynchronized.monitor = monitor; + + // Replace 'throw localObject' instruction + list.set(index, fastSynchronized); + } else { + // Cas particulier Jikes 1.2.2 + // Remove previous goto instruction + list.remove(index); + // Remove 'monitorexit' + list.remove(index); + // Remove 'throw finally' + list.remove(index); + // Remove localTestSynchronize1 = xxx + + MonitorEnter menter; + Instruction monitor; + int varMonitorIndex; + + instruction = list.remove(index); + + switch (instruction.opcode) { + case ByteCodeConstants.ASTORE: + menter = (MonitorEnter) list.remove(index); + AStore astore = (AStore) instruction; + varMonitorIndex = astore.index; + monitor = astore.valueref; + break; + case ByteCodeConstants.MONITORENTER: + menter = (MonitorEnter) instruction; + AssignmentInstruction ai = (AssignmentInstruction) menter.objectref; + astore = (AStore) ai.value1; + varMonitorIndex = astore.index; + monitor = ai.value2; + break; + default: + throw new UnexpectedInstructionException(); + } + + // Remove local variable for monitor + localVariables.removeLocalVariableWithIndexAndOffset(varMonitorIndex, menter.offset); + + List instructions = new ArrayList(); + while (true) { + instruction = list.get(index); + + if (instruction.opcode == ByteCodeConstants.MONITOREXIT) { + MonitorExit mexit = (MonitorExit) instruction; + if (mexit.objectref.opcode == ByteCodeConstants.ALOAD) { + LoadInstruction li = (LoadInstruction) mexit.objectref; + if (li.index == varMonitorIndex) + break; + } + } + + instructions.add(list.remove(index)); + } + + if ((index + 1 < list.size()) && (list.get(index + 1).opcode == ByteCodeConstants.XRETURN)) { + // Si l'instruction retourn�e poss�de un offset inferieur a + // celui de l'instruction 'monitorexit', l'instruction + // 'return' est ajoute au bloc synchronise. + Instruction monitorexit = list.get(index); + Instruction value = ((ReturnInstruction) list.get(index + 1)).valueref; + + if (monitorexit.offset > value.offset) + instructions.add(list.remove(index + 1)); + } + + // Analyze lists of instructions + ExecuteReconstructors(referenceMap, classFile, instructions, localVariables); + + synchronizedBlockJumpOffset = SearchMinusJumpOffset(instructions, 0, instructions.size(), + fce.tryFromOffset, fce.afterOffset); + + // + int branch = 1; + if (synchronizedBlockJumpOffset != -1) + branch = synchronizedBlockJumpOffset - instruction.offset; + + FastSynchronized fastSynchronized = new FastSynchronized(FastConstants.SYNCHRONIZED, + instruction.offset, menter.lineNumber, branch, instructions); + fastSynchronized.monitor = monitor; + + // Replace 'monitorexit localTestSynchronize1' + list.set(index, fastSynchronized); + } + } else { + // Cas g�n�ral + if (fce.afterOffset > list.get(list.size() - 1).offset) + index = list.size(); + else + index = InstructionUtil.getIndexForOffset(list, fce.afterOffset); + int lastOffset = list.get(--index).offset; + + // Remove instructions of finally block + Instruction i = null; + int finallyFromOffset = fce.finallyFromOffset; + while (list.get(index).offset >= finallyFromOffset) + i = list.remove(index--); + + // Store last 'AStore' to delete last "throw' instruction later + int exceptionLoadIndex = -1; + if ((i != null) && (i.opcode == ByteCodeConstants.ASTORE)) { + AStore astore = (AStore) i; + if (astore.valueref.opcode == ByteCodeConstants.EXCEPTIONLOAD) + exceptionLoadIndex = astore.index; + } + + // Extract try blockes + List instructions = new ArrayList(); + i = null; + if (index > 0) { + int tryFromOffset = fce.tryFromOffset; + i = list.get(index); + + if (i.offset >= tryFromOffset) { + instructions.add(i); + + while (index-- > 0) { + i = list.get(index); + if (i.offset < tryFromOffset) + break; + list.remove(index + 1); + instructions.add(i); + } + list.set(index + 1, null); + } + } + + Instruction lastInstruction = instructions.get(0); + + synchronizedBlockJumpOffset = SearchMinusJumpOffset(instructions, 0, instructions.size(), + fce.tryFromOffset, fce.afterOffset); + Collections.reverse(instructions); + + int lineNumber; + + if (i == null) { + lineNumber = Instruction.UNKNOWN_LINE_NUMBER; + } else { + lineNumber = i.lineNumber; + } + + // Reduce lists of instructions + int lenght = instructions.size(); + + // Get local variable index for monitor + int monitorLocalVariableIndex = GetMonitorLocalVariableIndex(list, index); + + if (lenght > 0) { + // Remove 'Goto' or jump 'return' & set 'afterListOffset' + lastInstruction = instructions.get(lenght - 1); + switch (lastInstruction.opcode) { + case ByteCodeConstants.GOTO: + instructions.remove(--lenght); + if (lenght > 0) + lastInstruction = instructions.get(lenght - 1); + break; + case ByteCodeConstants.XRETURN: + --lenght; + if (lenght > 0) + lastInstruction = instructions.get(lenght - 1); + break; + } + + // Remove all MonitorExit instructions + RemoveAllMonitorExitInstructions(instructions, lenght, monitorLocalVariableIndex); + + // Remove last "throw finally" instructions + int lastIndex = list.size() - 1; + i = list.get(lastIndex); + if ((i != null) && (i.opcode == ByteCodeConstants.ATHROW)) { + AThrow at = (AThrow) list.get(lastIndex); + switch (at.value.opcode) { + case ByteCodeConstants.EXCEPTIONLOAD: { + ExceptionLoad el = (ExceptionLoad) at.value; + if (el.exceptionNameIndex == 0) + list.remove(lastIndex); + } + break; + case ByteCodeConstants.ALOAD: { + ALoad aload = (ALoad) at.value; + if (aload.index == exceptionLoadIndex) + list.remove(lastIndex); + } + break; + } + } + } + + // Remove local variable for monitor + if (monitorLocalVariableIndex != -1) { + MonitorEnter menter = (MonitorEnter) list.get(index); + localVariables.removeLocalVariableWithIndexAndOffset(monitorLocalVariableIndex, menter.offset); + } + + int branch = 1; + if (synchronizedBlockJumpOffset != -1) + branch = synchronizedBlockJumpOffset - lastOffset; + + FastSynchronized fastSynchronized = new FastSynchronized(FastConstants.SYNCHRONIZED, lastOffset, + lineNumber, branch, instructions); + + // Analyze lists of instructions + ExecuteReconstructors(referenceMap, classFile, instructions, localVariables); + + // Store new FastTry instruction + list.set(index + 1, fastSynchronized); + + // Extract monitor + fastSynchronized.monitor = FormatAndExtractMonitor(list, index); + } + } + + private static Instruction FormatAndExtractMonitor(List list, int index) { + // Remove "monitorenter localTestSynchronize1" + MonitorEnter menter = (MonitorEnter) list.remove(index--); + + switch (menter.objectref.opcode) { + case ByteCodeConstants.ASSIGNMENT: + return ((AssignmentInstruction) menter.objectref).value2; + case ByteCodeConstants.DUPLOAD: + // Remove Astore(DupLoad) + list.remove(index--); + // Remove DupStore(...) + DupStore dupstore = (DupStore) list.remove(index); + return dupstore.objectref; + case ByteCodeConstants.ALOAD: + AStore astore = (AStore) list.remove(index); + return astore.valueref; + default: + return null; + } + } + + private static void RemoveAllMonitorExitInstructions(List instructions, int lenght, + int monitorLocalVariableIndex) { + int index = lenght; + + while (index-- > 0) { + Instruction instruction = instructions.get(index); + + if (instruction.opcode == ByteCodeConstants.MONITOREXIT) { + MonitorExit mexit = (MonitorExit) instruction; + + if (mexit.objectref.opcode == ByteCodeConstants.ALOAD) { + int aloadIndex = ((ALoad) mexit.objectref).index; + if (aloadIndex == monitorLocalVariableIndex) + instructions.remove(index); + } + } else if (instruction.opcode == FastConstants.TRY) { + FastTry ft = (FastTry) instruction; + + RemoveAllMonitorExitInstructions(ft.instructions, ft.instructions.size(), monitorLocalVariableIndex); + + int i = ft.catches.size(); + + while (i-- > 0) { + FastCatch fc = ft.catches.get(i); + RemoveAllMonitorExitInstructions(fc.instructions, fc.instructions.size(), monitorLocalVariableIndex); + } + + if (ft.finallyInstructions != null) + RemoveAllMonitorExitInstructions(ft.finallyInstructions, ft.finallyInstructions.size(), + monitorLocalVariableIndex); + } else if (instruction.opcode == FastConstants.SYNCHRONIZED) { + FastSynchronized fsy = (FastSynchronized) instruction; + + RemoveAllMonitorExitInstructions(fsy.instructions, fsy.instructions.size(), monitorLocalVariableIndex); + } + } + } + + private static int GetMonitorLocalVariableIndex(List list, int index) { + MonitorEnter menter = (MonitorEnter) list.get(index); + + switch (menter.objectref.opcode) { + case ByteCodeConstants.DUPLOAD: + return ((AStore) list.get(index - 1)).index; + case ByteCodeConstants.ALOAD: + return ((ALoad) menter.objectref).index; + case ByteCodeConstants.ASSIGNMENT: + Instruction i = ((AssignmentInstruction) menter.objectref).value1; + if (i.opcode == ByteCodeConstants.ALOAD) + return ((ALoad) i).index; + default: + return -1; + } + } + + private static void CreateFastTry(ReferenceMap referenceMap, ClassFile classFile, Method method, + List list, LocalVariables localVariables, FastCodeException fce, int returnOffset) + throws Exception { + int afterListOffset = fce.afterOffset; + int tryJumpOffset = -1; + int lastIndex = list.size() - 1; + int index; + + if ((afterListOffset == -1) || (afterListOffset > list.get(lastIndex).offset)) { + index = lastIndex; + } else { + index = InstructionUtil.getIndexForOffset(list, afterListOffset); + assert (index != -1); + --index; + } + + int lastOffset = list.get(index).offset; + // /30-12-2012///int lastOffset = fce.tryToOffset; + + // Extract finally block + List finallyInstructions = null; + if (fce.finallyFromOffset > 0) { + int finallyFromOffset = fce.finallyFromOffset; + finallyInstructions = new ArrayList(); + + while (list.get(index).offset >= finallyFromOffset) + finallyInstructions.add(list.remove(index--)); + + if (finallyInstructions.size() == 0) + throw new RuntimeException("Unexpected structure for finally block"); + + Collections.reverse(finallyInstructions); + //////////////////////////////////afterListOffset = finallyInstructions.get(0).offset; + + // Calcul de l'offset le plus haut pour le block 'try' + int firstOffset = finallyInstructions.get(0).offset; + int minimalJumpOffset = SearchMinusJumpOffset( + finallyInstructions, 0, finallyInstructions.size(), + firstOffset, afterListOffset); + + afterListOffset = firstOffset; + + if ((minimalJumpOffset != -1) && (afterListOffset > minimalJumpOffset)) + afterListOffset = minimalJumpOffset; + } + + // Extract catch blockes + List catches = null; + if (fce.catches != null) + { + int i = fce.catches.size(); + catches = new ArrayList(i); + + while (i-- > 0) { + FastCodeExceptionCatch fcec = fce.catches.get(i); + fcec.toOffset = afterListOffset; + int fromOffset = fcec.fromOffset; + List instructions = new ArrayList(); + + while (list.get(index).offset >= fromOffset) { + instructions.add(list.remove(index)); + if (index == 0) + break; + index--; + } + + int instructionsLength = instructions.size(); + + if (instructionsLength > 0) { + Instruction lastInstruction = instructions.get(0); + + int tryJumpOffsetTmp = SearchMinusJumpOffset(instructions, 0, instructionsLength, + fce.tryFromOffset, fce.afterOffset); + if (tryJumpOffsetTmp != -1) { + if (tryJumpOffset == -1) + tryJumpOffset = tryJumpOffsetTmp; + else if (tryJumpOffset > tryJumpOffsetTmp) + tryJumpOffset = tryJumpOffsetTmp; + } + + Collections.reverse(instructions); + + // Search exception type and local variables index + ExceptionLoad el = SearchExceptionLoadInstruction(instructions); + if (el != null) + { + int offset = lastInstruction.offset; + + catches.add(0, new FastCatch( + offset, el.offset, fcec.type, fcec.otherTypes, + el.index, instructions)); + + ////////////////////afterListOffset = instructions.get(0).offset; + + // Calcul de l'offset le plus haut pour le block 'try' + int firstOffset = instructions.get(0).offset; + int minimalJumpOffset = SearchMinusJumpOffset( + instructions, 0, instructions.size(), + firstOffset, offset); + + if (afterListOffset > firstOffset) + afterListOffset = firstOffset; + + if ((minimalJumpOffset != -1) && (afterListOffset > minimalJumpOffset)) + afterListOffset = minimalJumpOffset; + } else { + throw new UnexpectedInstructionException(); + } + } else { + throw new RuntimeException("Empty catch block"); + } + } + } + + // Extract try blockes + List tryInstructions = new ArrayList(); + + if (fce.tryToOffset < afterListOffset) { + index = FastCodeExceptionAnalyzer.ComputeTryToIndex(list, fce, index, afterListOffset); + } + + int tryFromOffset = fce.tryFromOffset; + Instruction i = list.get(index); + + if (i.offset >= tryFromOffset) { + tryInstructions.add(i); + + while (index-- > 0) { + i = list.get(index); + if (i.offset < tryFromOffset) + break; + list.remove(index + 1); + tryInstructions.add(i); + } + list.set(index + 1, null); + } + + int tryJumpOffsetTmp = SearchMinusJumpOffset(tryInstructions, 0, tryInstructions.size(), fce.tryFromOffset, + fce.tryToOffset); + if (tryJumpOffsetTmp != -1) { + if (tryJumpOffset == -1) + tryJumpOffset = tryJumpOffsetTmp; + else if (tryJumpOffset > tryJumpOffsetTmp) + tryJumpOffset = tryJumpOffsetTmp; + } + + Collections.reverse(tryInstructions); + + int lineNumber = tryInstructions.get(0).lineNumber; + + if (tryJumpOffset == -1) + tryJumpOffset = lastOffset + 1; + + FastTry fastTry = new FastTry(FastConstants.TRY, lastOffset, lineNumber, tryJumpOffset - lastOffset, + tryInstructions, catches, finallyInstructions); + + // Reduce lists of instructions + FastCodeExceptionAnalyzer.FormatFastTry(localVariables, fce, fastTry, returnOffset); + + // Analyze lists of instructions + ExecuteReconstructors(referenceMap, classFile, tryInstructions, localVariables); + + if (catches != null) + { + int length = catches.size(); + + for (int j = 0; j < length; ++j) { + FastCatch fc = catches.get(j); + List catchInstructions = fc.instructions; + ExecuteReconstructors(referenceMap, classFile, catchInstructions, localVariables); + } + } + + if (finallyInstructions != null) + ExecuteReconstructors(referenceMap, classFile, finallyInstructions, localVariables); + + // Store new FastTry instruction + list.set(index + 1, fastTry); + } + + private static ExceptionLoad SearchExceptionLoadInstruction(List instructions) throws Exception { + int length = instructions.size(); + + for (int i = 0; i < length; i++) { + Instruction instruction = SearchInstructionByOpcodeVisitor.visit(instructions.get(i), + ByteCodeConstants.EXCEPTIONLOAD); + + if (instruction != null) + return (ExceptionLoad) instruction; + } + + return null; + } + + /* + * debut de liste fin de liste | | Liste ... + * --|----|---|==0===1===2===3===4===5===6==7=...=n---|--| ... | | | | | | | + * beforeListOffset | | Offsets | loopEntryOffset endLoopOffset | + * beforeLoopEntryOffset afterLoopOffset + */ + private static void ExecuteReconstructors(ReferenceMap referenceMap, ClassFile classFile, List list, + LocalVariables localVariables) { + // Reconstruction des blocs synchronis�s vide + EmptySynchronizedBlockReconstructor.Reconstruct(localVariables, list); + // Recontruction du mot cl� '.class' pour le JDK 1.1.8 - B + DotClass118BReconstructor.Reconstruct(referenceMap, classFile, list); + // Recontruction du mot cl� '.class' pour le compilateur d'Eclipse + DotClassEclipseReconstructor.Reconstruct(referenceMap, classFile, list); + // Transformation de l'ensemble 'if-break' en simple 'if' + // A executer avant 'ComparisonInstructionAnalyzer' + IfGotoToIfReconstructor.Reconstruct(list); + // Aggregation des instructions 'if' + // A executer apres 'AssignmentInstructionReconstructor', + // 'IfGotoToIfReconstructor' + // A executer avant 'TernaryOpReconstructor' + ComparisonInstructionAnalyzer.Aggregate(list); + // Recontruction des instructions 'assert'. Cette operation doit etre + // executee apres 'ComparisonInstructionAnalyzer'. + AssertInstructionReconstructor.Reconstruct(classFile, list); + // Create ternary operator before analisys of local variables. + // A executer apr�s 'ComparisonInstructionAnalyzer' + TernaryOpReconstructor.Reconstruct(list); + // Recontruction des initialisations de tableaux + // Cette operation doit etre executee apres + // 'AssignmentInstructionReconstructor'. + InitArrayInstructionReconstructor.Reconstruct(list); + // Recontruction des operations binaires d'assignement + AssignmentOperatorReconstructor.Reconstruct(list); + // Retrait des instructions DupLoads & DupStore associ�s � + // une constante ou un attribut. + RemoveDupConstantsAttributes.Reconstruct(list); + } + + // Remove 'goto' jumping on next instruction + private static void RemoveNoJumpGotoInstruction(List list, int afterListOffset) { + int index = list.size(); + + if (index == 0) + return; + + Instruction instruction = list.get(--index); + int lastInstructionOffset = instruction.offset; + + if (instruction.opcode == ByteCodeConstants.GOTO) { + int branch = ((Goto) instruction).branch; + if ((branch >= 0) && (instruction.offset + branch <= afterListOffset)) + list.remove(index); + } + + while (index-- > 0) { + instruction = list.get(index); + + if (instruction.opcode == ByteCodeConstants.GOTO) { + int branch = ((Goto) instruction).branch; + if ((branch >= 0) && (instruction.offset + branch <= lastInstructionOffset)) + list.remove(index); + } + + lastInstructionOffset = instruction.offset; + } + } + + /* + * Effacement de instruction 'return' inutile sauf celle en fin de methode + * necessaire a 'InitInstanceFieldsReconstructor". + */ + private static void RemoveSyntheticReturn(List list, int afterListOffset, int returnOffset) { + if (afterListOffset == returnOffset) { + int index = list.size(); + + if (index == 1) { + RemoveSyntheticReturn(list, --index); + } else if (index-- > 1) { + if (list.get(index).lineNumber < list.get(index - 1).lineNumber) { + RemoveSyntheticReturn(list, index); + } + } + } + } + + private static void RemoveSyntheticReturn(List list, int index) { + switch (list.get(index).opcode) { + case FastConstants.RETURN: + list.remove(index); + break; + case FastConstants.LABEL: + FastLabel fl = (FastLabel) list.get(index); + if (fl.instruction.opcode == FastConstants.RETURN) + fl.instruction = null; + } + } + + private static void AddCastInstructionOnReturn( + ClassFile classFile, Method method, List list) + { + ConstantPool constants = classFile.getConstantPool(); + LocalVariables localVariables = method.getLocalVariables(); + + AttributeSignature as = method.getAttributeSignature(); + int signatureIndex = (as == null) ? + method.descriptor_index : as.signature_index; + String signature = constants.getConstantUtf8(signatureIndex); + String methodReturnedSignature = + SignatureUtil.GetMethodReturnedSignature(signature); + + int index = list.size(); + + while (index-- > 0) + { + Instruction instruction = list.get(index); + + if (instruction.opcode == ByteCodeConstants.XRETURN) + { + ReturnInstruction ri = (ReturnInstruction)instruction; + String returnedSignature = + ri.valueref.getReturnedSignature(constants, localVariables); + + if ((returnedSignature != null) && + returnedSignature.equals(StringConstants.INTERNAL_OBJECT_SIGNATURE) && + ! methodReturnedSignature.equals(StringConstants.INTERNAL_OBJECT_SIGNATURE)) + { + signatureIndex = constants.addConstantUtf8(methodReturnedSignature); + + if (ri.valueref.opcode == ByteCodeConstants.CHECKCAST) + { + ((CheckCast)ri.valueref).index = signatureIndex; + } + else + { + ri.valueref = new CheckCast( + ByteCodeConstants.CHECKCAST, ri.valueref.offset, + ri.valueref.lineNumber, signatureIndex, ri.valueref); + } + } + + /* if (! methodReturnedSignature.equals(returnedSignature)) + { + if (SignatureUtil.IsPrimitiveSignature(methodReturnedSignature)) + { + ri.valueref = new ConvertInstruction( + ByteCodeConstants.CONVERT, ri.valueref.offset, + ri.valueref.lineNumber, ri.valueref, + methodReturnedSignature); + } + else if (! StringConstants.INTERNAL_OBJECT_SIGNATURE.equals(methodReturnedSignature)) + { + signature = SignatureUtil.GetInnerName(methodReturnedSignature); + signatureIndex = constants.addConstantUtf8(signature); + int classIndex = constants.addConstantClass(signatureIndex); + ri.valueref = new CheckCast( + ByteCodeConstants.CHECKCAST, ri.valueref.offset, + ri.valueref.lineNumber, classIndex, ri.valueref); + } + }*/ + } + } + } + + /* + * debut de liste fin de liste | | Liste ... + * --|----|---|==0===1===2===3===4===5===6==7=...=n---|--| ... | | | | | | | + * beforeListOffset | | Offsets | loopEntryOffset endLoopOffset | + * beforeLoopEntryOffset afterLoopOffset + * + * + * beforeLoopEntryOffset & loopEntryOffset: utile pour la generation + * d'instructions 'continue' beforeListOffset: utile pour la generation de + * declarations de variable endLoopOffset & afterLoopOffset: utile pour la + * generation d'instructions 'break' afterListOffset: utile pour la + * generation d'instructions 'if-else' = lastBodyWhileLoop.offset + * + * WHILE instruction avant boucle | goto | beforeSubListOffset instructions + * | instruction | beforeLoopEntryOffset if a saut negatif | + * loopEntryOffset, endLoopOffset, afterListOffset instruction apres boucle + * | afterLoopOffset + * + * DO_WHILE instruction avant boucle | beforeListOffset instructions | + * instruction | beforeLoopEntryOffset if a saut negatif | loopEntryOffset, + * endLoopOffset, afterListOffset instruction apres boucle | afterLoopOffset + * + * FOR instruction avant boucle | goto | beforeListOffset instructions | + * instruction | beforeLoopEntryOffset iinc | loopEntryOffset, + * afterListOffset if a saut negatif | endLoopOffset instruction apres + * boucle | afterLoopOffset + * + * + * INFINITE_LOOP instruction avant boucle | beforeListOffset instructions | + * instruction | beforeLoopEntryOffset goto a saut negatif | + * loopEntryOffset, endLoopOffset, afterListOffset instruction apres boucle + * | afterLoopOffset + */ + private static void AnalyzeList(ClassFile classFile, Method method, List list, + LocalVariables localVariables, IntSet offsetLabelSet, int beforeLoopEntryOffset, int loopEntryOffset, + int afterBodyLoopOffset, int beforeListOffset, int afterListOffset, int breakOffset, int returnOffset) + { + // Create loops + CreateLoops(classFile, method, list, localVariables, offsetLabelSet, beforeLoopEntryOffset, loopEntryOffset, + beforeListOffset, afterListOffset, returnOffset); + + // Create switch + CreateSwitch(classFile, method, list, localVariables, offsetLabelSet, beforeLoopEntryOffset, loopEntryOffset, + afterBodyLoopOffset, afterListOffset, returnOffset); + + AnalyzeTryAndSynchronized(classFile, method, list, localVariables, offsetLabelSet, beforeLoopEntryOffset, + loopEntryOffset, afterBodyLoopOffset, beforeListOffset, afterListOffset, breakOffset, returnOffset); + + // Recontruction de la sequence 'return (b1 == 1);' apres la + // determination des types de variable + // A executer apr�s 'ComparisonInstructionAnalyzer' + TernaryOpInReturnReconstructor.Reconstruct(list); + + // Create labeled 'break' + // Cet appel permettait de reduire le nombre d'imbrication des 'if' en + // Augmentant le nombre de 'break' et 'continue'. + // CreateContinue( + // list, beforeLoopEntryOffset, loopEntryOffset, returnOffset); + + // Create if and if-else + CreateIfElse(classFile, method, list, localVariables, offsetLabelSet, beforeLoopEntryOffset, loopEntryOffset, + afterBodyLoopOffset, afterListOffset, breakOffset, returnOffset); + + // Remove 'goto' instruction jumping to next instruction + RemoveNopGoto(list); + + // // Compacte les instructions 'store' suivies d'instruction 'return' + // // A executer avant l'ajout des declarations. + // StoreReturnAnalyzer.Cleanup(list, localVariables); + + // Add local variable declarations + AddDeclarations(list, localVariables, beforeListOffset); + + // Remove 'goto' jumping on next instruction + // A VALIDER A LONG TERME. + // MODIFICATION AJOUTER SUITE A UNE MAUVAISE RECONSTRUCTION + // DES BLOCS tyr-catch GENERES PAR LE JDK 1.1.8. + // SI CELA PERTURBE LA RECONSTRUCTION DES INSTRUCTIONS if, + // 1) MODIFIER LES SAUTS DES INSTRUCTIONS goto DANS FormatCatch + // 2) DEPLACER CETTE METHODE APRES L'APPEL A + // FastInstructionListBuilder.Build(...) + RemoveNoJumpGotoInstruction(list, afterListOffset); + + // Create labeled 'break' + CreateBreakAndContinue(method, list, offsetLabelSet, beforeLoopEntryOffset, loopEntryOffset, + afterBodyLoopOffset, afterListOffset, breakOffset, returnOffset); + + // Retrait des instructions DupStore associ�es � une seule + // instruction DupLoad + SingleDupLoadAnalyzer.Cleanup(list); + + // Remove synthetic 'return' + RemoveSyntheticReturn(list, afterListOffset, returnOffset); + + // Add cast instruction on return + AddCastInstructionOnReturn(classFile, method, list); + } + + private static void AnalyzeTryAndSynchronized(ClassFile classFile, Method method, List list, + LocalVariables localVariables, IntSet offsetLabelSet, int beforeLoopEntryOffset, int loopEntryOffset, + int afterBodyLoopOffset, int beforeListOffset, int afterListOffset, int breakOffset, int returnOffset) { + int index = list.size(); + + while (index-- > 0) { + Instruction instruction = list.get(index); + + switch (instruction.opcode) { + case FastConstants.TRY: { + FastTry ft = (FastTry) instruction; + int tmpBeforeListOffset = (index > 0) ? list.get(index - 1).offset : beforeListOffset; + + // Try block + AnalyzeList(classFile, method, ft.instructions, localVariables, offsetLabelSet, beforeLoopEntryOffset, + loopEntryOffset, afterBodyLoopOffset, tmpBeforeListOffset, afterListOffset, breakOffset, + returnOffset); + + // Catch blocks + int length = ft.catches.size(); + for (int i = 0; i < length; i++) { + AnalyzeList(classFile, method, ft.catches.get(i).instructions, localVariables, offsetLabelSet, + beforeLoopEntryOffset, loopEntryOffset, afterBodyLoopOffset, tmpBeforeListOffset, + afterListOffset, breakOffset, returnOffset); + } + + // Finally block + if (ft.finallyInstructions != null) { + AnalyzeList(classFile, method, ft.finallyInstructions, localVariables, offsetLabelSet, + beforeLoopEntryOffset, loopEntryOffset, afterBodyLoopOffset, tmpBeforeListOffset, + afterListOffset, breakOffset, returnOffset); + } + } + break; + case FastConstants.SYNCHRONIZED: { + FastSynchronized fs = (FastSynchronized) instruction; + int tmpBeforeListOffset = (index > 0) ? list.get(index - 1).offset : beforeListOffset; + + AnalyzeList(classFile, method, fs.instructions, localVariables, offsetLabelSet, beforeLoopEntryOffset, + loopEntryOffset, afterBodyLoopOffset, tmpBeforeListOffset, afterListOffset, breakOffset, + returnOffset); + } + break; + case FastConstants.MONITORENTER: + case FastConstants.MONITOREXIT: { + // Effacement des instructions 'monitor*' pour les cas + // exceptionnels des blocs synchronises vide. + list.remove(index); + } + break; + } + + afterListOffset = instruction.offset; + } + } + + private static void RemoveNopGoto(List list) { + int length = list.size(); + + if (length > 1) { + int nextOffset = list.get(length - 1).offset; + + for (int index = length - 2; index >= 0; --index) { + Instruction instruction = list.get(index); + + if (instruction.opcode == FastConstants.GOTO) { + Goto gi = (Goto) instruction; + + if ((gi.branch >= 0) && (gi.GetJumpOffset() <= nextOffset)) + list.remove(index); + } + + nextOffset = instruction.offset; + } + } + } + + /* + * Strategie : 1) Les instructions 'store' et 'for' sont pass�es en revue. + * Si elles referencent une variables locales non encore declar�e et dont la + * port�e est incluse � la liste, une declaration est ins�r�e. 2) Le tableau + * des variables locales est pass� en revue. Pour toutes variables locales + * non encore declar�es et dont la port�e est incluse � la liste courante, + * on declare les variables en debut de bloc. + */ + private static void AddDeclarations(List list, LocalVariables localVariables, int beforeListOffset) { + int length = list.size(); + + if (length > 0) { + // 1) Ajout de declaration sur les instructions 'store' et 'for' + StoreInstruction si; + LocalVariable lv; + + int lastOffset = list.get(length - 1).offset; + + for (int i = 0; i < length; i++) + { + Instruction instruction = (Instruction) list.get(i); + + switch (instruction.opcode) { + case ByteCodeConstants.ASTORE: + case ByteCodeConstants.ISTORE: + case ByteCodeConstants.STORE: + si = (StoreInstruction) instruction; + lv = localVariables.getLocalVariableWithIndexAndOffset(si.index, si.offset); + if ((lv != null) && (lv.declarationFlag == NOT_DECLARED) && (beforeListOffset < lv.start_pc) + && (lv.start_pc + lv.length - 1 <= lastOffset)) { + list.set(i, new FastDeclaration(FastConstants.DECLARE, si.offset, si.lineNumber, si.index, si)); + lv.declarationFlag = DECLARED; + UpdateNewAndInitArrayInstruction(si); + } + break; + case FastConstants.FOR: + FastFor ff = (FastFor) instruction; + if (ff.init != null) { + switch (ff.init.opcode) { + case FastConstants.ASTORE: + case FastConstants.ISTORE: + case FastConstants.STORE: + si = (StoreInstruction) ff.init; + lv = localVariables.getLocalVariableWithIndexAndOffset(si.index, si.offset); + if ((lv != null) && (lv.declarationFlag == NOT_DECLARED) + && (beforeListOffset < lv.start_pc) && (lv.start_pc + lv.length - 1 <= lastOffset)) { + ff.init = new FastDeclaration(FastConstants.DECLARE, si.offset, si.lineNumber, + si.index, si); + lv.declarationFlag = DECLARED; + UpdateNewAndInitArrayInstruction(si); + } + } + } + break; + } + } + + // 2) Ajout de declaration pour toutes variables non encore + // declar�es + // TODO A affiner. Exemple: + // 128: String message; <--- Erreur de positionnement. La + // d�claration se limite � l'instruction + // 'if-else'. Dupliquer dans chaque bloc. + // 237: if (!(partnerParameters.isActive())) + // { + // 136: if (this.loggerTarget.isDebugEnabled()) + // { + // 128: message = String.format("Le partenaire [%s] n'est p... + // 136: this.loggerTarget.debug(message); + // } + // } + // else if (StringUtils.equalsIgnoreCase((String)parameter... + // { + // 165: request.setAttribute("SSO_PARTNER_PARAMETERS", partne... + // 184: request.setAttribute("SSO_TOKEN_VALUE", request.getPa... + // 231: if (this.loggerTarget.isDebugEnabled()) + // { + // 223: message = String.format("Prise en compte de la dema... + // partnerParameters.getCpCode(), parameterName }); + // 231: this.loggerTarget.debug(message); + // } + int lvLength = localVariables.size(); + + for (int i = 0; i < lvLength; i++) { + lv = localVariables.getLocalVariableAt(i); + + if ((lv.declarationFlag == NOT_DECLARED) && (beforeListOffset < lv.start_pc) + && (lv.start_pc + lv.length - 1 <= lastOffset)) { + int indexForNewDeclaration = InstructionUtil.getIndexForOffset(list, lv.start_pc); + + if (indexForNewDeclaration == -1) { + // 'start_pc' offset not found + indexForNewDeclaration = 0; + } + + list.add(indexForNewDeclaration, new FastDeclaration(FastConstants.DECLARE, lv.start_pc, + Instruction.UNKNOWN_LINE_NUMBER, lv.index, null)); + lv.declarationFlag = DECLARED; + } + } + } + } + + private static void UpdateNewAndInitArrayInstruction(Instruction instruction) { + switch (instruction.opcode) { + case FastConstants.ASTORE: + Instruction valueref = ((StoreInstruction) instruction).valueref; + if (valueref.opcode == FastConstants.NEWANDINITARRAY) + valueref.opcode = FastConstants.INITARRAY; + } + } + + // private static void CreateContinue( + // List list, int beforeLoopEntryOffset, + // int loopEntryOffset, int returnOffset) + // { + // int length = list.size(); + // for (int index=0; index instructions = + // new ArrayList(1); + // instructions.add(new Return( + // ByteCodeConstants.RETURN, bi.offset, + // Instruction.UNKNOWN_LINE_NUMBER)); + // list.set(index, new FastTestList( + // FastConstants.IF_, bi.offset, bi.lineNumber, + // jumpOffset-bi.offset, bi, instructions)); + // } + // else */ if ((beforeLoopEntryOffset < jumpOffset) && + // (jumpOffset <= loopEntryOffset)) + // { + // if (index+1 < length) + // { + // Instruction nextInstruction = list.get(index+1); + // + // // Si il n'y a pas assez de place pour une sequence + // // 'if' + 'continue', un simple 'if' sera cree. + // if ((bi.lineNumber != Instruction.UNKNOWN_LINE_NUMBER) && + // (index+1 < length) && + // (bi.lineNumber+1 == nextInstruction.lineNumber)) + // continue; + // + // // Si l'instruction de test est suivie d'une seule instruction + // // 'return', la sequence 'if' + 'continue' n'est pas construite. + // if ((nextInstruction.opcode == ByteCodeConstants.RETURN) || + // (nextInstruction.opcode == ByteCodeConstants.XRETURN)) + // continue; + // } + // + // list.set(index, new FastInstruction( + // FastConstants.IF_CONTINUE, bi.offset, + // bi.lineNumber, bi)); + // } + // } + // break; + // } + // } + // } + + private static void CreateBreakAndContinue(Method method, List list, IntSet offsetLabelSet, + int beforeLoopEntryOffset, int loopEntryOffset, int afterBodyLoopOffset, int afterListOffset, + int breakOffset, int returnOffset) { + int length = list.size(); + + for (int index = 0; index < length; index++) + { + Instruction instruction = list.get(index); + + switch (instruction.opcode) { + case FastConstants.IF: + case FastConstants.IFCMP: + case FastConstants.IFXNULL: + case FastConstants.COMPLEXIF: + { + BranchInstruction bi = (BranchInstruction) instruction; + int jumpOffset = bi.GetJumpOffset(); + + if ((beforeLoopEntryOffset < jumpOffset) && (jumpOffset <= loopEntryOffset)) { + list.set(index, new FastInstruction( + FastConstants.IF_CONTINUE, bi.offset, bi.lineNumber, bi)); + } else if (ByteCodeUtil.JumpTo(method.getCode(), breakOffset, jumpOffset)) { + list.set(index, new FastInstruction( + FastConstants.IF_BREAK, bi.offset, bi.lineNumber, bi)); + } else { + // Si la m�thode retourne 'void' et si l'instruction + // saute un goto qui saut sur un goto ... qui saute + // sur 'returnOffset', g�n�rer 'if-return'. + if (ByteCodeUtil.JumpTo(method.getCode(), jumpOffset, returnOffset)) { + List instructions = new ArrayList(1); + instructions.add(new Return(ByteCodeConstants.RETURN, bi.offset, + Instruction.UNKNOWN_LINE_NUMBER)); + list.set(index, new FastTestList(FastConstants.IF_, bi.offset, bi.lineNumber, jumpOffset + - bi.offset, bi, instructions)); + } else { + // Si l'instruction saute vers un '?return' simple, + // duplication de l'instruction cible pour eviter la + // generation d'une instruction *_LABELED_BREAK. + byte[] code = method.getCode(); + + // Reconnaissance bas niveau de la sequence + // '?load_?' suivie de '?return' en fin de methode. + if (code.length == jumpOffset+2) + { + LoadInstruction load = DuplicateLoadInstruction( + code[jumpOffset] & 255, bi.offset, + Instruction.UNKNOWN_LINE_NUMBER); + if (load != null) + { + ReturnInstruction ri = DuplacateReturnInstruction( + code[jumpOffset+1] & 255, bi.offset, + Instruction.UNKNOWN_LINE_NUMBER, load); + if (ri != null) + { + List instructions = new ArrayList(1); + instructions.add(ri); + list.set(index, new FastTestList( + FastConstants.IF_, bi.offset, bi.lineNumber, + jumpOffset-bi.offset, bi, instructions)); + break; + } + } + } + + offsetLabelSet.add(jumpOffset); + list.set(index, new FastInstruction( + FastConstants.IF_LABELED_BREAK, bi.offset, bi.lineNumber, bi)); + } + } + } + break; + + case FastConstants.GOTO: + { + Goto g = (Goto) instruction; + int jumpOffset = g.GetJumpOffset(); + int lineNumber = g.lineNumber; + + if ((index == 0) || (list.get(index-1).lineNumber == lineNumber)) + lineNumber = Instruction.UNKNOWN_LINE_NUMBER; + + if ((beforeLoopEntryOffset < jumpOffset) && (jumpOffset <= loopEntryOffset)) { + // L'instruction 'goto' saute vers le debut de la boucle + if ((afterListOffset == afterBodyLoopOffset) && (index + 1 == length)) { + // L'instruction 'goto' est la derniere instruction + // a s'executer dans la boucle. Elle ne sert a rien. + list.remove(index); + } else { + // Creation d'une instruction 'continue' + list.set(index, new FastInstruction( + FastConstants.GOTO_CONTINUE, g.offset, lineNumber, null)); + } + } else if (ByteCodeUtil.JumpTo(method.getCode(), breakOffset, jumpOffset)) { + list.set(index, new FastInstruction( + FastConstants.GOTO_BREAK, g.offset, lineNumber, null)); + } else { + // Si la m�thode retourne 'void' et si l'instruction + // saute un goto qui saut sur un goto ... qui saute + // sur 'returnOffset', g�n�rer 'return'. + if (ByteCodeUtil.JumpTo(method.getCode(), jumpOffset, returnOffset)) { + list.set(index, new Return( + ByteCodeConstants.RETURN, g.offset, lineNumber)); + } else { + // Si l'instruction saute vers un '?return' simple, + // duplication de l'instruction cible pour eviter la + // generation d'une instruction *_LABELED_BREAK. + byte[] code = method.getCode(); + + // Reconnaissance bas niveau de la sequence + // '?load_?' suivie de '?return' en fin de methode. + if (code.length == jumpOffset+2) + { + LoadInstruction load = DuplicateLoadInstruction( + code[jumpOffset] & 255, g.offset, lineNumber); + if (load != null) + { + ReturnInstruction ri = DuplacateReturnInstruction( + code[jumpOffset+1] & 255, g.offset, lineNumber, load); + if (ri != null) + { + // Si l'instruction precedente est un + // '?store' sur la meme variable et si + // elle a le meme numero de ligne + // => aggregation + if (index > 0) + { + instruction = list.get(index-1); + + if ((load.lineNumber == instruction.lineNumber) && + (ByteCodeConstants.ISTORE <= instruction.opcode) && + (instruction.opcode <= ByteCodeConstants.ASTORE_3) && + (load.index == ((StoreInstruction)instruction).index)) + { + StoreInstruction si = (StoreInstruction)instruction; + ri.valueref = si.valueref; + list.remove(--index); + length--; + } + } + + list.set(index, ri); + break; + } + } + } + + offsetLabelSet.add(jumpOffset); + list.set(index, new FastInstruction( + FastConstants.GOTO_LABELED_BREAK, + g.offset, lineNumber, g)); + } + } + } + break; + } + } + } + + private static LoadInstruction DuplicateLoadInstruction( + int opcode, int offset, int lineNumber) + { + switch (opcode) + { + case ByteCodeConstants.ILOAD: + return new ILoad(ByteCodeConstants.ILOAD, offset, lineNumber, 0); + case ByteCodeConstants.LLOAD: + return new LoadInstruction(ByteCodeConstants.LOAD, offset, lineNumber, 0, "J"); + case ByteCodeConstants.FLOAD: + return new LoadInstruction(ByteCodeConstants.LOAD, offset, lineNumber, 0, "F"); + case ByteCodeConstants.DLOAD: + return new LoadInstruction(ByteCodeConstants.LOAD, offset, lineNumber, 0, "D"); + case ByteCodeConstants.ALOAD: + return new ALoad(ByteCodeConstants.ALOAD, offset, lineNumber, 0); + case ByteCodeConstants.ILOAD_0: + case ByteCodeConstants.ILOAD_1: + case ByteCodeConstants.ILOAD_2: + case ByteCodeConstants.ILOAD_3: + return new ILoad(ByteCodeConstants.ILOAD, offset, lineNumber, opcode-ByteCodeConstants.ILOAD_0); + case ByteCodeConstants.LLOAD_0: + case ByteCodeConstants.LLOAD_1: + case ByteCodeConstants.LLOAD_2: + case ByteCodeConstants.LLOAD_3: + return new LoadInstruction(ByteCodeConstants.LOAD, offset, lineNumber, opcode-ByteCodeConstants.LLOAD_0, "J"); + case ByteCodeConstants.FLOAD_0: + case ByteCodeConstants.FLOAD_1: + case ByteCodeConstants.FLOAD_2: + case ByteCodeConstants.FLOAD_3: + return new LoadInstruction(ByteCodeConstants.LOAD, offset, lineNumber, opcode-ByteCodeConstants.FLOAD_0, "F"); + case ByteCodeConstants.DLOAD_0: + case ByteCodeConstants.DLOAD_1: + case ByteCodeConstants.DLOAD_2: + case ByteCodeConstants.DLOAD_3: + return new LoadInstruction(ByteCodeConstants.LOAD, offset, lineNumber, opcode-ByteCodeConstants.DLOAD_0, "D"); + case ByteCodeConstants.ALOAD_0: + case ByteCodeConstants.ALOAD_1: + case ByteCodeConstants.ALOAD_2: + case ByteCodeConstants.ALOAD_3: + return new ALoad(ByteCodeConstants.ALOAD, offset, lineNumber, opcode-ByteCodeConstants.ALOAD_0); + default: + return null; + } + } + + private static ReturnInstruction DuplacateReturnInstruction( + int opcode, int offset, int lineNumber, Instruction instruction) + { + switch (opcode) + { + case ByteCodeConstants.IRETURN: + case ByteCodeConstants.LRETURN: + case ByteCodeConstants.FRETURN: + case ByteCodeConstants.DRETURN: + case ByteCodeConstants.ARETURN: + return new ReturnInstruction(ByteCodeConstants.XRETURN, offset, lineNumber, instruction); + default: + return null; + } + } + + private static int UnoptimizeIfElseInLoop(ClassFile classFile, Method method, List list, + LocalVariables localVariables, IntSet offsetLabelSet, int beforeListOffset, int afterListOffset, + int returnOffset, int offset, int jumpOffset, int index) { + int firstLoopInstructionIndex = InstructionUtil.getIndexForOffset(list, jumpOffset); + if (firstLoopInstructionIndex != -1) { + int length = list.size(); + if (index + 1 < length) { + int afterLoopInstructionOffset = list.get(index + 1).offset; + + // Changement du calcul du saut : on considere que + // l'instruction vers laquelle le saut negatif pointe. + // int afterLoopJumpOffset = SearchMinusJumpOffset( + // list, firstLoopInstructionIndex, index, + // jumpOffset-1, afterLoopInstructionOffset); + int afterLoopJumpOffset; + Instruction firstLoopInstruction = list.get(firstLoopInstructionIndex); + + switch (firstLoopInstruction.opcode) { + case FastConstants.IF: + case FastConstants.IFCMP: + case FastConstants.IFXNULL: + case FastConstants.COMPLEXIF: + case FastConstants.GOTO: + case FastConstants.TRY: + case FastConstants.SYNCHRONIZED: + BranchInstruction bi = (BranchInstruction) firstLoopInstruction; + afterLoopJumpOffset = bi.GetJumpOffset(); + break; + default: + afterLoopJumpOffset = -1; + break; + } + + if (afterLoopJumpOffset > afterLoopInstructionOffset) { + int afterLoopInstructionIndex = InstructionUtil.getIndexForOffset(list, afterLoopJumpOffset); + + if ((afterLoopInstructionIndex == -1) && (afterLoopJumpOffset <= afterListOffset)) + afterLoopInstructionIndex = length; + + if (afterLoopInstructionIndex != -1) { + int lastInstructionoffset = list.get(afterLoopInstructionIndex - 1).offset; + + if (// Check previous instructions + InstructionUtil.CheckNoJumpToInterval(list, 0, firstLoopInstructionIndex, offset, + lastInstructionoffset) && + // Check next instructions + InstructionUtil.CheckNoJumpToInterval(list, afterLoopInstructionIndex, list.size(), + offset, lastInstructionoffset)) { + // Pattern 1: + // 530: it = s.iterator(); + // 539: if (!it.hasNext()) goto 572; + // 552: nodeAgentSearch = (ObjectName)it.next(); + // 564: if + // (nodeAgentSearch.getCanonicalName().indexOf(this.asName) + // <= 0) goto 532; <--- + // 568: found = true; + // 569: goto 572; + // 572: ... + // Pour: + // it = s.iterator(); + // while (it.hasNext()) { + // nodeAgentSearch = (ObjectName)it.next(); + // if + // (nodeAgentSearch.getCanonicalName().indexOf(this.asName) + // > 0) { + // found = true; + // break; + // } + // } + // Modification de la liste des instructions en: + // 530: it = s.iterator(); + // 539: if (!it.hasNext()) goto 572; + // 552: nodeAgentSearch = (ObjectName)it.next(); + // 564: if + // (nodeAgentSearch.getCanonicalName().indexOf(this.asName) + // <= 0) goto 532; <--- + // 568: found = true; + // 569: goto 572; + // 569: goto 532; <=== + // 572: ... + + // Pattern 2: + // 8: this.byteOff = paramInt1; + // 16: if (this.byteOff>=paramInt2) goto 115; <--- + // ... + // 53: if (i >= 0) goto 76; + // 59: tmp59_58 = this; + // 72: paramArrayOfChar[this.charOff++] = (char)i; + // 73: goto 11; + // 80: if (!this.subMode) goto 102; + // 86: tmp86_85 = this; + // 98: paramArrayOfChar[(this.charOff++)] = 65533; + // 99: goto 11; <--- + // 104: this.badInputLength = 1; + // 114: throw new UnknownCharacterException(); + // 122: return this.charOff - paramInt3; + // Pour: + // for(byteOff = i; byteOff < j;) + // { + // ... + // if(byte0 >= 0) + // { + // ac[charOff++] = (char)byte0; + // } + // else if(subMode) + // { + // ac[charOff++] = '\uFFFD'; + // } + // else + // { + // badInputLength = 1; + // throw new UnknownCharacterException(); + // } + // } + // return charOff - k; + // Modification de la liste des instructions en: + // 8: this.byteOff = paramInt1; + // 16: if (this.byteOff>=paramInt2) goto 115; <--- + // ... + // 53: if (i >= 0) goto 76; + // 59: tmp59_58 = this; + // 72: paramArrayOfChar[this.charOff++] = (char)i; + // 73: goto 11; + // 80: if (!this.subMode) goto 102; + // 86: tmp86_85 = this; + // 98: paramArrayOfChar[(this.charOff++)] = 65533; + // 99: goto 11; <--- + // 104: this.badInputLength = 1; + // 114: throw new UnknownCharacterException(); + // 114: goto 11; <=== + // 122: return this.charOff - paramInt3; + Instruction lastInstruction = list.get(afterLoopInstructionIndex - 1); + // Attention: le goto genere a le meme offset que + // l'instruction precedente. + Goto newGi = new Goto(ByteCodeConstants.GOTO, lastInstruction.offset, + Instruction.UNKNOWN_LINE_NUMBER, jumpOffset - lastInstruction.offset); + list.add(afterLoopInstructionIndex, newGi); + + return AnalyzeBackGoto(classFile, method, list, localVariables, offsetLabelSet, + beforeListOffset, afterLoopJumpOffset, returnOffset, afterLoopInstructionIndex, + newGi, jumpOffset); + } + } + } + } + } + + return -1; + } + + private static int UnoptimizeIfiniteLoop(ClassFile classFile, Method method, List list, + LocalVariables localVariables, IntSet offsetLabelSet, int beforeListOffset, int afterListOffset, + int returnOffset, BranchInstruction bi, int jumpOffset, int jumpIndex) { + // Original: + // 8: ... + // 18: ... + // 124: if (this.used.containsKey(localObject)) goto 9; + // 127: goto 130; + // 134: return ScriptRuntime.toString(localObject); + // Ajout d'une insruction 'goto': + // 8: ... + // 18: ... + // 124: if (this.used.containsKey(localObject)) goto 127+1; <--- + // 127: goto 130; + // 127+1: GOTO 9 <=== + // 134: return ScriptRuntime.toString(localObject); + int length = list.size(); + + if (jumpIndex + 1 >= length) + return -1; + + Instruction instruction = list.get(jumpIndex + 1); + + if (instruction.opcode != ByteCodeConstants.GOTO) + return -1; + + int afterGotoOffset = (jumpIndex + 2 >= length) ? afterListOffset : list.get(jumpIndex + 2).offset; + + Goto g = (Goto) instruction; + int jumpGotoOffset = g.GetJumpOffset(); + + if ((g.offset >= jumpGotoOffset) || (jumpGotoOffset > afterGotoOffset)) + return -1; + + // Motif de code trouv� + int newGotoOffset = g.offset + 1; + + // 1) Modification de l'offset de saut + bi.SetJumpOffset(newGotoOffset); + + // 2) Ajout d'une nouvelle instruction 'goto' + Goto newGoto = new Goto(ByteCodeConstants.GOTO, newGotoOffset, Instruction.UNKNOWN_LINE_NUMBER, jumpOffset + - newGotoOffset); + list.add(jumpIndex + 2, newGoto); + + return AnalyzeBackGoto(classFile, method, list, localVariables, offsetLabelSet, beforeListOffset, + jumpGotoOffset, returnOffset, jumpIndex + 2, newGoto, jumpOffset); + } + + /* + * debut de liste fin de liste | | Liste ... + * --|----|---|==0===1===2===3===4===5===6==7=...=n---|--| ... | | | | | | | + * beforeListOffset | | Offsets | loopEntryOffset endLoopOffset | + * beforeLoopEntryOffset afterLoopOffset + */ + private static void CreateLoops(ClassFile classFile, Method method, List list, + LocalVariables localVariables, IntSet offsetLabelSet, int beforeLoopEntryOffset, int loopEntryOffset, + int beforeListOffset, int afterListOffset, int returnOffset) { + // Unoptimize loop in loop + int index = list.size(); + + while (index-- > 0) { + Instruction instruction = list.get(index); + + switch (instruction.opcode) { + case FastConstants.IF: + case FastConstants.IFCMP: + case FastConstants.IFXNULL: + case FastConstants.COMPLEXIF: + case FastConstants.GOTO: + if (UnoptimizeLoopInLoop(list, beforeListOffset, index, instruction)) + index++; + } + } + + // Create loops + index = list.size(); + + while (index-- > 0) { + Instruction instruction = list.get(index); + + switch (instruction.opcode) { + case FastConstants.IF: + case FastConstants.IFCMP: + case FastConstants.IFXNULL: + case FastConstants.COMPLEXIF: { + BranchInstruction bi = (BranchInstruction) instruction; + if (bi.branch < 0) { + int jumpOffset = bi.GetJumpOffset(); + + if ((beforeListOffset < jumpOffset) + && ((beforeLoopEntryOffset >= jumpOffset) || (jumpOffset > loopEntryOffset))) { + int newIndex = UnoptimizeIfElseInLoop(classFile, method, list, localVariables, offsetLabelSet, + beforeListOffset, afterListOffset, returnOffset, bi.offset, jumpOffset, index); + + if (newIndex == -1) { + newIndex = UnoptimizeIfiniteLoop(classFile, method, list, localVariables, offsetLabelSet, + beforeListOffset, afterListOffset, returnOffset, bi, jumpOffset, index); + } + + if (newIndex == -1) { + index = AnalyzeBackIf(classFile, method, list, localVariables, offsetLabelSet, + beforeListOffset, returnOffset, index, bi); + } else { + index = newIndex; + } + } + } + } + break; + case FastConstants.GOTO: { + Goto gi = (Goto) instruction; + if (gi.branch < 0) { + int jumpOffset = gi.GetJumpOffset(); + + if ((beforeListOffset < jumpOffset) + && ((beforeLoopEntryOffset >= jumpOffset) || (jumpOffset > loopEntryOffset))) { + int newIndex = UnoptimizeIfElseInLoop(classFile, method, list, localVariables, offsetLabelSet, + beforeListOffset, afterListOffset, returnOffset, gi.offset, jumpOffset, index); + + if (newIndex == -1) { + index = AnalyzeBackGoto(classFile, method, list, localVariables, offsetLabelSet, + beforeListOffset, gi.offset, returnOffset, index, gi, jumpOffset); + } else { + index = newIndex; + } + } + } + } + break; + case FastConstants.TRY: + case FastConstants.SYNCHRONIZED: { + FastList fl = (FastList) instruction; + if (fl.instructions.size() > 0) { + int previousOffset = (index > 0) ? list.get(index - 1).offset : beforeListOffset; + int jumpOffset = fl.GetJumpOffset(); + + if ((jumpOffset != -1) && (previousOffset >= jumpOffset) && (beforeListOffset < jumpOffset) + && ((beforeLoopEntryOffset >= jumpOffset) || (jumpOffset > loopEntryOffset))) { + fl.branch = 1; + int afterSubListOffset = (index + 1 < list.size()) ? list.get(index + 1).offset + : afterListOffset; + index = AnalyzeBackGoto(classFile, method, list, localVariables, offsetLabelSet, + beforeListOffset, afterSubListOffset, returnOffset, index, fl, jumpOffset); + } + } + } + break; + } + } + } + + private static boolean UnoptimizeLoopInLoop(List list, int beforeListOffset, int index, + Instruction instruction) { + // Retrait de l'optimisation des boucles dans les boucles c.a.d. rajout + // de l'instruction 'goto' supprim�e. + // + // Original: Optimisation: + // | | + // ,----+ if <----. ,----+ if <-. + // | | | | | | + // | ,--+ if <--. | | + if --'<--. + // | | | | | | | | + // | | + goto -' | | + goto ----' + // | '->+ GOTO ---' '--->| + // '--->| | + // | + // + // Original: Optimisation: + // | | + // ,----+ goto ,----+ goto + // | ,--+ GOTO <-. | | + // | | | <---. | | | <---. + // | | | | | | | | + // | '->+ if --' | | + if --'<--. + // | | | | | | + // '--->+ if ----' '--->+ if ------' + // | | + // + BranchInstruction bi = (BranchInstruction) instruction; + if (bi.branch >= 0) + return false; + + int jumpOffset = bi.GetJumpOffset(); + if (jumpOffset <= beforeListOffset) + return false; + + int indexBi = index; + + // Recherche de l'instruction cible et verification qu'aucune + // instruction switch dans l'intervale ne saute pas a l'exterieur + // de l'intervale. + for (;;) { + if (index == 0) + return false; + + instruction = list.get(--index); + + if (instruction.offset <= jumpOffset) + break; + + switch (instruction.opcode) { + case FastConstants.LOOKUPSWITCH: + case FastConstants.TABLESWITCH: + Switch s = (Switch) instruction; + if (s.offset + s.defaultOffset > bi.offset) + return false; + int j = s.offsets.length; + while (j-- > 0) { + if (s.offset + s.offsets[j] > bi.offset) + return false; + } + break; + } + } + + instruction = list.get(index + 1); + + if (bi == instruction) + return false; + + switch (instruction.opcode) { + case FastConstants.IF: + case FastConstants.IFCMP: + case FastConstants.IFXNULL: + case FastConstants.COMPLEXIF: + BranchInstruction bi2 = (BranchInstruction) instruction; + + if (bi2.branch >= 0) + return false; + + // Verification qu'aucune instruction switch definie avant + // l'intervale ne saute dans l'intervale. + for (int i = 0; i < index; i++) { + instruction = list.get(i); + + switch (instruction.opcode) { + case FastConstants.LOOKUPSWITCH: + case FastConstants.TABLESWITCH: + Switch s = (Switch) instruction; + if (s.offset + s.defaultOffset > bi2.offset) + return false; + int j = s.offsets.length; + while (j-- > 0) { + if (s.offset + s.offsets[j] > bi2.offset) + return false; + } + break; + } + } + + // Unoptimize loop in loop + int jumpOffset2 = bi2.GetJumpOffset(); + + // Recherche de l'instruction cible et verification qu'aucune + // instruction switch dans l'intervale ne saute pas a l'exterieur + // de l'intervale. + for (;;) { + if (index == 0) + return false; + + instruction = list.get(--index); + + if (instruction.offset <= jumpOffset2) + break; + + switch (instruction.opcode) { + case FastConstants.LOOKUPSWITCH: + case FastConstants.TABLESWITCH: + Switch s = (Switch) instruction; + if (s.offset + s.defaultOffset > bi.offset) + return false; + int j = s.offsets.length; + while (j-- > 0) { + if (s.offset + s.offsets[j] > bi.offset) + return false; + } + break; + } + } + + Instruction target = list.get(index + 1); + + if (bi2 == target) + return false; + + // Verification qu'aucune instruction switch definie avant + // l'intervale ne saute dans l'intervale. + for (int i = 0; i < index; i++) { + instruction = list.get(i); + + switch (instruction.opcode) { + case FastConstants.LOOKUPSWITCH: + case FastConstants.TABLESWITCH: + Switch s = (Switch) instruction; + if (s.offset + s.defaultOffset > bi2.offset) + return false; + int j = s.offsets.length; + while (j-- > 0) { + if (s.offset + s.offsets[j] > bi2.offset) + return false; + } + break; + } + } + + if (bi.opcode == ByteCodeConstants.GOTO) { + // Original: Optimisation: + // | | + // ,----+ if <----. ,----+ if <-. + // | | | | | | + // | ,--+ if <--. | | + if --'<--. + // | | | | | | | | + // | | + goto -' | | + goto ----' + // | '->+ GOTO ---' '--->| + // '--->| | + // | + + // 1) Create 'goto' + list.add(indexBi + 1, new Goto(ByteCodeConstants.GOTO, bi.offset + 1, Instruction.UNKNOWN_LINE_NUMBER, + jumpOffset2 - bi.offset - 1)); + // 2) Modify branch offset of first loop + bi2.SetJumpOffset(bi.offset + 1); + } else { + // Original: Optimisation: + // | | + // ,----+ goto ,----+ goto + // | ,--+ GOTO <-. | | + // | | | <---. | | | <---. + // | | | | | | | | + // | '->+ if --' | | + if --'<--. + // | | | | | | + // '--->+ if ----' '--->+ if ------' + // | | + if ((target.opcode == ByteCodeConstants.GOTO) && (((Goto) target).GetJumpOffset() == jumpOffset2)) { + // 'goto' exists + // 1) Modify branch offset of first loop + bi.SetJumpOffset(jumpOffset2); + } else { + // Goto does not exist + // 1) Create 'goto' + list.add(index + 1, new Goto(ByteCodeConstants.GOTO, jumpOffset2 - 1, + Instruction.UNKNOWN_LINE_NUMBER, jumpOffset - jumpOffset2 + 1)); + // 2) Modify branch offset of first loop + bi.SetJumpOffset(jumpOffset2 - 1); + return true; + } + } + } + + return false; + } + + /* + * debut de liste fin de liste | | Liste ... + * --|----|---|==0===1===2===3===4===5===6==7=...=n---|--| ... | | | | | | | + * beforeListOffset | | Offsets | loopEntryOffset endLoopOffset | + * beforeLoopEntryOffset afterLoopOffset + */ + private static void CreateIfElse(ClassFile classFile, Method method, List list, + LocalVariables localVariables, IntSet offsetLabelSet, int beforeLoopEntryOffset, int loopEntryOffset, + int afterBodyLoopOffset, int afterListOffset, int breakOffset, int returnOffset) { + // Create if and if-else + int length = list.size(); + for (int index = 0; index < length; index++) { + Instruction instruction = list.get(index); + + switch (instruction.opcode) { + case FastConstants.IF: + case FastConstants.IFCMP: + case FastConstants.IFXNULL: + case FastConstants.COMPLEXIF: + AnalyzeIfAndIfElse(classFile, method, list, localVariables, offsetLabelSet, beforeLoopEntryOffset, + loopEntryOffset, afterBodyLoopOffset, afterListOffset, breakOffset, returnOffset, index, + (ConditionalBranchInstruction) instruction); + length = list.size(); + break; + } + } + } + + /* + * debut de liste fin de liste | | Liste ... + * --|----|---|==0===1===2===3===4===5===6==7=...=n---|--| ... | | | | | | | + * beforeListOffset | | Offsets | loopEntryOffset endLoopOffset | + * beforeLoopEntryOffset afterLoopOffset + */ + private static void CreateSwitch(ClassFile classFile, Method method, List list, + LocalVariables localVariables, IntSet offsetLabelSet, int beforeLoopEntryOffset, int loopEntryOffset, + int afterBodyLoopOffset, int afterListOffset, int returnOffset) { + // Create switch + for (int index = 0; index < list.size(); index++) { + Instruction instruction = list.get(index); + + switch (instruction.opcode) { + case FastConstants.LOOKUPSWITCH: + AnalyzeLookupSwitch(classFile, method, list, localVariables, offsetLabelSet, beforeLoopEntryOffset, + loopEntryOffset, afterBodyLoopOffset, afterListOffset, returnOffset, index, + (LookupSwitch) instruction); + break; + + case FastConstants.TABLESWITCH: + index = AnalyzeTableSwitch(classFile, method, list, localVariables, offsetLabelSet, + beforeLoopEntryOffset, loopEntryOffset, afterBodyLoopOffset, afterListOffset, returnOffset, + index, (TableSwitch) instruction); + break; + } + } + } + + private static void RemoveLocalVariable(Method method, IndexInstruction ii) + { + LocalVariable lv = method.getLocalVariables().searchLocalVariableWithIndexAndOffset(ii.index, ii.offset); + + if ((lv != null) && (ii.offset == lv.start_pc)) { + method.getLocalVariables().removeLocalVariableWithIndexAndOffset(ii.index, ii.offset); + } + } + + /* + * debut de liste fin de liste | testIndex | | | | Liste ... + * --|----|---|==0===1===2===3===4===5===6==7=...=n---|--| ... | | | | | | | + * beforeListOffset | | Offsets | loopEntryOffset endLoopOffset | + * beforeLoopEntryOffset afterLoopOffset + * + * Pour les boucles 'for', beforeLoopEntryOffset & loopEntryOffset encadrent + * l'instruction d'incrementation. + */ + private static int AnalyzeBackIf(ClassFile classFile, Method method, List list, + LocalVariables localVariables, IntSet offsetLabelSet, int beforeListOffset, int returnOffset, + int testIndex, Instruction test) { + int index = testIndex - 1; + List subList = new ArrayList(); + int firstOffset = ((BranchInstruction) test).GetJumpOffset(); + + int beforeLoopEntryOffset = (index >= 0) ? list.get(index).offset : beforeListOffset; + + // Move body of loop in a new list + while ((index >= 0) && (list.get(index).offset >= firstOffset)) + subList.add(list.remove(index--)); + + int subListLength = subList.size(); + + // Search escape offset + if (index >= 0) + beforeListOffset = list.get(index).offset; + int breakOffset = SearchMinusJumpOffset(subList, 0, subListLength, beforeListOffset, test.offset); + + // Search jump instruction before 'while' loop + Instruction jumpInstructionBeforeLoop = null; + + if (index >= 0) { + int i = index + 1; + + while (i-- > 0) { + Instruction instruction = list.get(i); + + switch (instruction.opcode) { + case FastConstants.IF: + case FastConstants.IFCMP: + case FastConstants.IFXNULL: + case FastConstants.COMPLEXIF: + case FastConstants.TRY: + case FastConstants.SYNCHRONIZED: + case FastConstants.GOTO: + BranchInstruction bi = (BranchInstruction) instruction; + int offset = bi.GetJumpOffset(); + int lastBodyOffset = (subList.size() > 0) ? subList.get(0).offset : bi.offset; + + if ((lastBodyOffset < offset) && (offset <= test.offset)) { + jumpInstructionBeforeLoop = bi; + i = 0; // Fin de boucle + } + } + } + } + + if (jumpInstructionBeforeLoop != null) + { + // Remove 'goto' before 'while' loop + if (jumpInstructionBeforeLoop.opcode == FastConstants.GOTO) + list.remove(index--); + + Instruction beforeLoop = ((index >= 0) && (index < list.size())) ? list.get(index) : null; + + Instruction lastBodyLoop = null; + Instruction beforeLastBodyLoop = null; + + if (subListLength > 0) { + lastBodyLoop = subList.get(0); + + if (subListLength > 1) { + beforeLastBodyLoop = subList.get(1); + + // V�rification qu'aucune instruction ne saute entre + // 'lastBodyLoop' et 'test' + if (!InstructionUtil.CheckNoJumpToInterval(subList, 0, subListLength, lastBodyLoop.offset, + test.offset)) { + // 'lastBodyLoop' ne peut pas etre l'instruction + // d'incrementation d'une boucle 'for' + lastBodyLoop = null; + beforeLastBodyLoop = null; + } + } + } + + // if instruction before while loop affect same variable + // last instruction of loop, create For loop. + int typeLoop = GetLoopType(beforeLoop, test, beforeLastBodyLoop, lastBodyLoop); + + switch (typeLoop) { + case 2: // while (test) + if (subListLength > 0) { + Collections.reverse(subList); + AnalyzeList(classFile, method, subList, localVariables, offsetLabelSet, beforeLoopEntryOffset, + test.offset, test.offset, jumpInstructionBeforeLoop.offset, test.offset, breakOffset, + returnOffset); + } + + int branch = 1; + if (breakOffset != -1) + branch = breakOffset - test.offset; + + list.set(++index, new FastTestList( + FastConstants.WHILE, test.offset, test.lineNumber, + branch, test, subList)); + break; + case 3: // for (beforeLoop; test;) + // Remove initialisation instruction before sublist + list.remove(index); + + if (subListLength > 0) { + Collections.reverse(subList); + AnalyzeList(classFile, method, subList, localVariables, offsetLabelSet, beforeLoopEntryOffset, + test.offset, test.offset, jumpInstructionBeforeLoop.offset, test.offset, breakOffset, + returnOffset); + } + + CreateForLoopCase1(classFile, method, list, index, beforeLoop, test, subList, breakOffset); + break; + case 6: // for (; test; lastBodyLoop) + if (subListLength > 1) { + Collections.reverse(subList); + // Remove incrementation instruction + subList.remove(--subListLength); + + AnalyzeList(classFile, method, subList, localVariables, offsetLabelSet, beforeLastBodyLoop.offset, + lastBodyLoop.offset, lastBodyLoop.offset, jumpInstructionBeforeLoop.offset, + lastBodyLoop.offset, breakOffset, returnOffset); + + branch = 1; + if (breakOffset != -1) + branch = breakOffset - test.offset; + + list.set(++index, new FastFor(FastConstants.FOR, test.offset, test.lineNumber, branch, null, test, + lastBodyLoop, subList)); + } else { + if (subListLength == 1) { + AnalyzeList(classFile, method, subList, localVariables, offsetLabelSet, beforeLoopEntryOffset, + test.offset, test.offset, jumpInstructionBeforeLoop.offset, test.offset, breakOffset, + returnOffset); + } + + branch = 1; + if (breakOffset != -1) + branch = breakOffset - test.offset; + + list.set(++index, new FastTestList(FastConstants.WHILE, test.offset, test.lineNumber, branch, test, + subList)); + } + break; + case 7: // for (beforeLoop; test; lastBodyLoop) + if (subListLength > 0) { + // Remove initialisation instruction before sublist + list.remove(index); + + Collections.reverse(subList); + // Remove incrementation instruction + subList.remove(--subListLength); + + if (subListLength > 0) + AnalyzeList(classFile, method, subList, localVariables, offsetLabelSet, + beforeLastBodyLoop.offset, lastBodyLoop.offset, lastBodyLoop.offset, + jumpInstructionBeforeLoop.offset, lastBodyLoop.offset, breakOffset, returnOffset); + } + + index = CreateForLoopCase3(classFile, method, list, index, beforeLoop, test, lastBodyLoop, subList, + breakOffset); + break; + default: + throw new UnexpectedElementException("AnalyzeBackIf"); + } + } else { + if (subListLength > 0) { + Collections.reverse(subList); + AnalyzeList(classFile, method, subList, localVariables, offsetLabelSet, beforeLoopEntryOffset, + test.offset, test.offset, beforeListOffset, test.offset, breakOffset, returnOffset); + + int branch = 1; + if (breakOffset != -1) + branch = breakOffset - test.offset; + + list.set(++index, new FastTestList(FastConstants.DO_WHILE, test.offset, + Instruction.UNKNOWN_LINE_NUMBER, branch, test, subList)); + } else { + // 'do-while' avec une liste d'instructions vide devient un + // 'while'. + list.set(++index, new FastTestList(FastConstants.WHILE, test.offset, test.lineNumber, 1, test, null)); + } + } + + return index; + } + + private static int SearchMinusJumpOffset( + List list, + int fromIndex, int toIndex, + int beforeListOffset, int lastListOffset) + { + int breakOffset = -1; + int index = toIndex; + + while (index-- > fromIndex) { + Instruction instruction = list.get(index); + + switch (instruction.opcode) { + case FastConstants.GOTO: + case FastConstants.IF: + case FastConstants.IFCMP: + case FastConstants.IFXNULL: + case FastConstants.COMPLEXIF: + BranchInstruction bi = (BranchInstruction) instruction; + int jumpOffset = bi.GetJumpOffset(); + + if ((jumpOffset != -1) && ((jumpOffset <= beforeListOffset) || (lastListOffset < jumpOffset))) + { + if ((breakOffset == -1) || (breakOffset > jumpOffset)) + breakOffset = jumpOffset; + } + break; + case FastConstants.FOR: + case FastConstants.FOREACH: + case FastConstants.WHILE: + case FastConstants.DO_WHILE: + case FastConstants.SYNCHRONIZED: + FastList fl = (FastList) instruction; + List instructions = fl.instructions; + if (instructions != null) + { + jumpOffset = SearchMinusJumpOffset(instructions, 0, instructions.size(), beforeListOffset, + lastListOffset); + + if ((jumpOffset != -1) && ((jumpOffset <= beforeListOffset) || (lastListOffset < jumpOffset))) { + if ((breakOffset == -1) || (breakOffset > jumpOffset)) + breakOffset = jumpOffset; + } + } + break; + case FastConstants.TRY: + FastTry ft = (FastTry) instruction; + + jumpOffset = ft.GetJumpOffset(); + + if ((jumpOffset != -1) && ((jumpOffset <= beforeListOffset) || (lastListOffset < jumpOffset))) { + if ((breakOffset == -1) || (breakOffset > jumpOffset)) + breakOffset = jumpOffset; + } + + // Try block + instructions = ft.instructions; + jumpOffset = SearchMinusJumpOffset(instructions, 0, instructions.size(), beforeListOffset, + lastListOffset); + + if ((jumpOffset != -1) && ((jumpOffset <= beforeListOffset) || (lastListOffset < jumpOffset))) + { + if ((breakOffset == -1) || (breakOffset > jumpOffset)) + breakOffset = jumpOffset; + } + + // Catch blocks + int i = ft.catches.size(); + while (i-- > 0) + { + List catchInstructions = ft.catches.get(i).instructions; + jumpOffset = SearchMinusJumpOffset(catchInstructions, 0, catchInstructions.size(), + beforeListOffset, lastListOffset); + + if ((jumpOffset != -1) && ((jumpOffset <= beforeListOffset) || (lastListOffset < jumpOffset))) + { + if ((breakOffset == -1) || (breakOffset > jumpOffset)) + breakOffset = jumpOffset; + } + } + + // Finally block + if (ft.finallyInstructions != null) + { + List finallyInstructions = ft.finallyInstructions; + jumpOffset = SearchMinusJumpOffset(finallyInstructions, 0, finallyInstructions.size(), + beforeListOffset, lastListOffset); + + if ((jumpOffset != -1) && ((jumpOffset <= beforeListOffset) || (lastListOffset < jumpOffset))) + { + if ((breakOffset == -1) || (breakOffset > jumpOffset)) + breakOffset = jumpOffset; + } + } + break; + case FastConstants.SWITCH: + case FastConstants.SWITCH_ENUM: + case FastConstants.SWITCH_STRING: + FastSwitch fs = (FastSwitch) instruction; + + jumpOffset = fs.GetJumpOffset(); + + if ((jumpOffset != -1) && ((jumpOffset <= beforeListOffset) || (lastListOffset < jumpOffset))) + { + if ((breakOffset == -1) || (breakOffset > jumpOffset)) + breakOffset = jumpOffset; + } + + i = fs.pairs.length; + while (i-- > 0) + { + List caseInstructions = + fs.pairs[i].getInstructions(); + if (caseInstructions != null) + { + jumpOffset = SearchMinusJumpOffset(caseInstructions, 0, caseInstructions.size(), + beforeListOffset, lastListOffset); + + if ((jumpOffset != -1) && ((jumpOffset <= beforeListOffset) || (lastListOffset < jumpOffset))) { + if ((breakOffset == -1) || (breakOffset > jumpOffset)) + breakOffset = jumpOffset; + } + } + } + break; + } + } + + return breakOffset; + } + + private static int GetMaxOffset(Instruction beforeWhileLoop, Instruction test) { + return (beforeWhileLoop.offset > test.offset) ? beforeWhileLoop.offset : test.offset; + } + + private static int GetMaxOffset(Instruction beforeWhileLoop, Instruction test, Instruction lastBodyWhileLoop) { + int offset = GetMaxOffset(beforeWhileLoop, test); + + return (offset > lastBodyWhileLoop.offset) ? offset : lastBodyWhileLoop.offset; + } + + private static Instruction CreateForEachVariableInstruction(Instruction i) { + switch (i.opcode) { + case FastConstants.DECLARE: + ((FastDeclaration) i).instruction = null; + return i; + case FastConstants.ASTORE: + return new ALoad(FastConstants.ALOAD, i.offset, i.lineNumber, ((AStore) i).index); + case FastConstants.ISTORE: + return new ILoad(FastConstants.ILOAD, i.offset, i.lineNumber, ((IStore) i).index); + case FastConstants.STORE: + return new LoadInstruction(FastConstants.LOAD, i.offset, i.lineNumber, ((StoreInstruction) i).index, + ((StoreInstruction) i).getReturnedSignature(null, null)); + default: + return i; + } + } + + private static void CreateForLoopCase1(ClassFile classFile, Method method, List list, + int beforeWhileLoopIndex, Instruction beforeWhileLoop, Instruction test, List subList, + int breakOffset) { + int forLoopOffset = GetMaxOffset(beforeWhileLoop, test); + + int branch = 1; + if (breakOffset != -1) + branch = breakOffset - forLoopOffset; + + // Is a for-each pattern ? + if (IsAForEachIteratorPattern(classFile, method, beforeWhileLoop, test, subList)) { + Instruction variable = CreateForEachVariableInstruction(subList.remove(0)); + + InvokeNoStaticInstruction insi = (InvokeNoStaticInstruction) (((AStore) beforeWhileLoop).valueref); + Instruction values = insi.objectref; + + // Remove iterator local variable + RemoveLocalVariable(method, (StoreInstruction) beforeWhileLoop); + + list.set(beforeWhileLoopIndex, new FastForEach(FastConstants.FOREACH, forLoopOffset, + beforeWhileLoop.lineNumber, branch, variable, values, subList)); + } else { + list.set(beforeWhileLoopIndex, new FastFor(FastConstants.FOR, forLoopOffset, beforeWhileLoop.lineNumber, + branch, beforeWhileLoop, test, null, subList)); + } + } + + private static int CreateForLoopCase3(ClassFile classFile, Method method, List list, + int beforeWhileLoopIndex, Instruction beforeWhileLoop, Instruction test, Instruction lastBodyWhileLoop, + List subList, int breakOffset) { + int forLoopOffset = GetMaxOffset(beforeWhileLoop, test, lastBodyWhileLoop); + + int branch = 1; + if (breakOffset != -1) + branch = breakOffset - forLoopOffset; + + // Is a for-each pattern ? + switch (GetForEachArrayPatternType(classFile, beforeWhileLoop, test, lastBodyWhileLoop, list, + beforeWhileLoopIndex, subList)) { + case 1: // SUN 1.5 + { + Instruction variable = CreateForEachVariableInstruction(subList.remove(0)); + + StoreInstruction beforeBeforeWhileLoop = (StoreInstruction) list.remove(--beforeWhileLoopIndex); + AssignmentInstruction ai = (AssignmentInstruction) ((ArrayLength) beforeBeforeWhileLoop.valueref).arrayref; + Instruction values = ai.value2; + + // Remove lenght local variable + RemoveLocalVariable(method, beforeBeforeWhileLoop); + // Remove index local variable + RemoveLocalVariable(method, (StoreInstruction) beforeWhileLoop); + // Remove array tmp local variable + RemoveLocalVariable(method, (AStore) ai.value1); + + list.set(beforeWhileLoopIndex, new FastForEach(FastConstants.FOREACH, forLoopOffset, variable.lineNumber, + branch, variable, values, subList)); + } + break; + case 2: // SUN 1.6 + { + Instruction variable = CreateForEachVariableInstruction(subList.remove(0)); + + StoreInstruction beforeBeforeWhileLoop = (StoreInstruction) list.remove(--beforeWhileLoopIndex); + + StoreInstruction beforeBeforeBeforeWhileLoop = (StoreInstruction) list.remove(--beforeWhileLoopIndex); + Instruction values = beforeBeforeBeforeWhileLoop.valueref; + + // Remove lenght local variable + RemoveLocalVariable(method, beforeBeforeWhileLoop); + // Remove index local variable + RemoveLocalVariable(method, (StoreInstruction) beforeWhileLoop); + // Remove array tmp local variable + RemoveLocalVariable(method, beforeBeforeBeforeWhileLoop); + + list.set(beforeWhileLoopIndex, new FastForEach(FastConstants.FOREACH, forLoopOffset, variable.lineNumber, + branch, variable, values, subList)); + } + break; + case 3: // IBM + { + Instruction variable = CreateForEachVariableInstruction(subList.remove(0)); + + StoreInstruction siIndex = (StoreInstruction) list.remove(--beforeWhileLoopIndex); + + StoreInstruction siTmpArray = (StoreInstruction) list.remove(--beforeWhileLoopIndex); + Instruction values = siTmpArray.valueref; + + // Remove lenght local variable + RemoveLocalVariable(method, (StoreInstruction) beforeWhileLoop); + // Remove index local variable + RemoveLocalVariable(method, siIndex); + // Remove array tmp local variable + RemoveLocalVariable(method, siTmpArray); + + list.set(beforeWhileLoopIndex, new FastForEach(FastConstants.FOREACH, forLoopOffset, variable.lineNumber, + branch, variable, values, subList)); + } + break; + default: { + list.set(beforeWhileLoopIndex, new FastFor(FastConstants.FOR, forLoopOffset, beforeWhileLoop.lineNumber, + branch, beforeWhileLoop, test, lastBodyWhileLoop, subList)); + } + } + + return beforeWhileLoopIndex; + } + + /* + * Pattern: 7: List strings = new ArrayList(); 44: for (Iterator + * localIterator = strings.iterator(); localIterator.hasNext(); ) { 29: + * String s = (String)localIterator.next(); 34: System.out.println(s); } + */ + private static boolean IsAForEachIteratorPattern(ClassFile classFile, Method method, Instruction init, + Instruction test, List subList) { + // Tests: (Java 5 or later) + (Not empty sub list) + if ((classFile.getMajorVersion() < 49) || (subList.size() == 0)) + return false; + + Instruction firstInstruction = subList.get(0); + + // Test: Same line number + if (test.lineNumber != firstInstruction.lineNumber) + return false; + + // Test 'init' instruction: Iterator localIterator = strings.iterator() + if (init.opcode != ByteCodeConstants.ASTORE) + return false; + AStore astoreIterator = (AStore) init; + if ((astoreIterator.valueref.opcode != ByteCodeConstants.INVOKEINTERFACE) + && (astoreIterator.valueref.opcode != ByteCodeConstants.INVOKEVIRTUAL)) + return false; + LocalVariable lv = method.getLocalVariables().getLocalVariableWithIndexAndOffset(astoreIterator.index, + astoreIterator.offset); + if ((lv == null) || (lv.signature_index == 0)) + return false; + ConstantPool constants = classFile.getConstantPool(); + InvokeNoStaticInstruction insi = (InvokeNoStaticInstruction) astoreIterator.valueref; + ConstantMethodref cmr = constants.getConstantMethodref(insi.index); + ConstantNameAndType cnat = constants.getConstantNameAndType(cmr.name_and_type_index); + String iteratorMethodName = constants.getConstantUtf8(cnat.name_index); + if (!"iterator".equals(iteratorMethodName)) + return false; + String iteratorMethodDescriptor = constants.getConstantUtf8(cnat.descriptor_index); + if (!"()Ljava/util/Iterator;".equals(iteratorMethodDescriptor)) + return false; + + // Test 'test' instruction: localIterator.hasNext() + if (test.opcode != ByteCodeConstants.IF) + return false; + IfInstruction ifi = (IfInstruction) test; + if (ifi.value.opcode != ByteCodeConstants.INVOKEINTERFACE) + return false; + insi = (InvokeNoStaticInstruction) ifi.value; + if ((insi.objectref.opcode != ByteCodeConstants.ALOAD) + || (((ALoad) insi.objectref).index != astoreIterator.index)) + return false; + cmr = constants.getConstantMethodref(insi.index); + cnat = constants.getConstantNameAndType(cmr.name_and_type_index); + String hasNextMethodName = constants.getConstantUtf8(cnat.name_index); + if (!"hasNext".equals(hasNextMethodName)) + return false; + String hasNextMethodDescriptor = constants.getConstantUtf8(cnat.descriptor_index); + if (!"()Z".equals(hasNextMethodDescriptor)) + return false; + + // Test first instruction: String s = (String)localIterator.next() + if (firstInstruction.opcode != FastConstants.DECLARE) + return false; + FastDeclaration declaration = (FastDeclaration) firstInstruction; + if (declaration.instruction == null) + return false; + if (declaration.instruction.opcode != FastConstants.ASTORE) + return false; + AStore astoreVariable = (AStore) declaration.instruction; + + if (astoreVariable.valueref.opcode == FastConstants.CHECKCAST) + { + // Une instruction Cast est utilis�e si le type de l'interation + // n'est pas Object. + CheckCast cc = (CheckCast) astoreVariable.valueref; + if (cc.objectref.opcode != FastConstants.INVOKEINTERFACE) + return false; + insi = (InvokeNoStaticInstruction) cc.objectref; + } + else + { + if (astoreVariable.valueref.opcode != FastConstants.INVOKEINTERFACE) + return false; + insi = (InvokeNoStaticInstruction)astoreVariable.valueref; + } + + if ((insi.objectref.opcode != ByteCodeConstants.ALOAD) + || (((ALoad) insi.objectref).index != astoreIterator.index)) + return false; + cmr = constants.getConstantMethodref(insi.index); + cnat = constants.getConstantNameAndType(cmr.name_and_type_index); + String nextMethodName = constants.getConstantUtf8(cnat.name_index); + if (!"next".equals(nextMethodName)) + return false; + String nextMethodDescriptor = constants.getConstantUtf8(cnat.descriptor_index); + if (!"()Ljava/lang/Object;".equals(nextMethodDescriptor)) + return false; + + return true; + } + + /* + * Pattern SUN 1.5: 14: String[] strings = { "a", "b" }; 20: int j = + * (arrayOfString1 = strings).length; 48: for (int i = 0; i < j; ++i) { 33: + * String s = arrayOfString1[i]; 38: System.out.println(s); } + * + * Return 0: No pattern 1: Pattern SUN 1.5 + */ + private static int GetForEachArraySun15PatternType(Instruction init, Instruction test, Instruction inc, + Instruction firstInstruction, StoreInstruction siLenght) { + // Test before 'for' instruction: j = (arrayOfString1 = strings).length; + ArrayLength al = ((ArrayLength) siLenght.valueref); + if (al.arrayref.opcode != ByteCodeConstants.ASSIGNMENT) + return 0; + AssignmentInstruction ai = (AssignmentInstruction) al.arrayref; + if ((!ai.operator.equals("=")) || (ai.value1.opcode != ByteCodeConstants.ASTORE)) + return 0; + StoreInstruction siTmpArray = (StoreInstruction) ai.value1; + + // Test 'init' instruction: int i = 0 + if (init.opcode != ByteCodeConstants.ISTORE) + return 0; + StoreInstruction siIndex = (StoreInstruction) init; + if (siIndex.valueref.opcode != ByteCodeConstants.ICONST) + return 0; + IConst iconst = (IConst) siIndex.valueref; + if ((iconst.value != 0) || (!iconst.signature.equals("I"))) + return 0; + + // Test 'test' instruction: i < j + if (test.opcode != ByteCodeConstants.IFCMP) + return 0; + IfCmp ifcmp = (IfCmp) test; + if ((ifcmp.value1.opcode != ByteCodeConstants.ILOAD) || (ifcmp.value2.opcode != ByteCodeConstants.ILOAD) + || (((ILoad) ifcmp.value1).index != siIndex.index) || (((ILoad) ifcmp.value2).index != siLenght.index)) + return 0; + + // Test 'inc' instruction: ++i + if ((inc.opcode != ByteCodeConstants.IINC) || (((IInc) inc).index != siIndex.index) + || (((IInc) inc).count != 1)) + return 0; + + // Test first instruction: String s = arrayOfString1[i]; + if (firstInstruction.opcode == FastConstants.DECLARE) { + FastDeclaration declaration = (FastDeclaration) firstInstruction; + if (declaration.instruction == null) + return 0; + firstInstruction = declaration.instruction; + } + if ((firstInstruction.opcode != FastConstants.STORE) && (firstInstruction.opcode != FastConstants.ASTORE) + && (firstInstruction.opcode != FastConstants.ISTORE)) + return 0; + StoreInstruction siVariable = (StoreInstruction) firstInstruction; + if (siVariable.valueref.opcode != ByteCodeConstants.ARRAYLOAD) + return 0; + ArrayLoadInstruction ali = (ArrayLoadInstruction) siVariable.valueref; + if ((ali.arrayref.opcode != ByteCodeConstants.ALOAD) || (ali.indexref.opcode != ByteCodeConstants.ILOAD) + || (((ALoad) ali.arrayref).index != siTmpArray.index) + || (((ILoad) ali.indexref).index != siIndex.index)) + return 0; + + return 1; + } + + /* + * Pattern SUN 1.6: String[] arr$ = { "a", "b" }; int len$ = arr$.length; + * for(int i$ = 0; i$ < len$; i$++) { String s = arr$[i$]; + * System.out.println(s); } + * + * Return 0: No pattern 2: Pattern SUN 1.6 + */ + private static int GetForEachArraySun16PatternType(Instruction init, Instruction test, Instruction inc, + Instruction firstInstruction, StoreInstruction siLenght, Instruction beforeBeforeForInstruction) { + // Test before 'for' instruction: len$ = arr$.length; + ArrayLength al = ((ArrayLength) siLenght.valueref); + if (al.arrayref.opcode != ByteCodeConstants.ALOAD) + return 0; + + // Test before before 'for' instruction: arr$ = ...; + if (beforeBeforeForInstruction.opcode != ByteCodeConstants.ASTORE) + return 0; + StoreInstruction siTmpArray = (StoreInstruction) beforeBeforeForInstruction; + if (siTmpArray.index != ((IndexInstruction) al.arrayref).index) + return 0; + + // Test 'init' instruction: int i = 0 + if (init.opcode != ByteCodeConstants.ISTORE) + return 0; + StoreInstruction siIndex = (StoreInstruction) init; + if (siIndex.valueref.opcode != ByteCodeConstants.ICONST) + return 0; + IConst iconst = (IConst) siIndex.valueref; + if ((iconst.value != 0) || (!iconst.signature.equals("I"))) + return 0; + + // Test 'test' instruction: i < j + if (test.opcode != ByteCodeConstants.IFCMP) + return 0; + IfCmp ifcmp = (IfCmp) test; + if ((ifcmp.value1.opcode != ByteCodeConstants.ILOAD) || (ifcmp.value2.opcode != ByteCodeConstants.ILOAD) + || (((ILoad) ifcmp.value1).index != siIndex.index) || (((ILoad) ifcmp.value2).index != siLenght.index)) + return 0; + + // Test 'inc' instruction: ++i + if ((inc.opcode != ByteCodeConstants.IINC) || (((IInc) inc).index != siIndex.index) + || (((IInc) inc).count != 1)) + return 0; + + // Test first instruction: String s = arrayOfString1[i]; + if (firstInstruction.opcode == FastConstants.DECLARE) { + FastDeclaration declaration = (FastDeclaration) firstInstruction; + if (declaration.instruction == null) + return 0; + firstInstruction = declaration.instruction; + } + if ((firstInstruction.opcode != FastConstants.STORE) && (firstInstruction.opcode != FastConstants.ASTORE) + && (firstInstruction.opcode != FastConstants.ISTORE)) + return 0; + StoreInstruction siVariable = (StoreInstruction) firstInstruction; + if (siVariable.valueref.opcode != ByteCodeConstants.ARRAYLOAD) + return 0; + ArrayLoadInstruction ali = (ArrayLoadInstruction) siVariable.valueref; + if ((ali.arrayref.opcode != ByteCodeConstants.ALOAD) || (ali.indexref.opcode != ByteCodeConstants.ILOAD) + || (((ALoad) ali.arrayref).index != siTmpArray.index) + || (((ILoad) ali.indexref).index != siIndex.index)) + return 0; + + return 2; + } + + /* + * Pattern IBM: 81: Object localObject = args; 84: GUIMap guiMap = 0; 116: + * for (GUIMap localGUIMap1 = localObject.length; guiMap < localGUIMap1; + * ++guiMap) { 99: String arg = localObject[guiMap]; 106: + * System.out.println(arg); } + * + * Return 0: No pattern 3: Pattern IBM + */ + private static int GetForEachArrayIbmPatternType(ClassFile classFile, Instruction init, Instruction test, + Instruction inc, List list, int beforeWhileLoopIndex, Instruction firstInstruction, + StoreInstruction siIndex) { + // Test before 'for' instruction: guiMap = 0; + IConst icont = ((IConst) siIndex.valueref); + if (icont.value != 0) + return 0; + + // Test before before 'for' instruction: Object localObject = args; + if (beforeWhileLoopIndex < 2) + return 0; + Instruction beforeBeforeForInstruction = list.get(beforeWhileLoopIndex - 2); + // Test: Same line number + if (test.lineNumber != beforeBeforeForInstruction.lineNumber) + return 0; + if (beforeBeforeForInstruction.opcode != ByteCodeConstants.ASTORE) + return 0; + StoreInstruction siTmpArray = (StoreInstruction) beforeBeforeForInstruction; + + // Test 'init' instruction: localGUIMap1 = localObject.length + if (init.opcode != ByteCodeConstants.ISTORE) + return 0; + StoreInstruction siLenght = (StoreInstruction) init; + if (siLenght.valueref.opcode != ByteCodeConstants.ARRAYLENGTH) + return 0; + ArrayLength al = (ArrayLength) siLenght.valueref; + if (al.arrayref.opcode != ByteCodeConstants.ALOAD) + return 0; + if (((ALoad) al.arrayref).index != siTmpArray.index) + return 0; + + // Test 'test' instruction: guiMap < localGUIMap1 + if (test.opcode != ByteCodeConstants.IFCMP) + return 0; + IfCmp ifcmp = (IfCmp) test; + if ((ifcmp.value1.opcode != ByteCodeConstants.ILOAD) || (ifcmp.value2.opcode != ByteCodeConstants.ILOAD) + || (((ILoad) ifcmp.value1).index != siIndex.index) || (((ILoad) ifcmp.value2).index != siLenght.index)) + return 0; + + // Test 'inc' instruction: ++i + if ((inc.opcode != ByteCodeConstants.IINC) || (((IInc) inc).index != siIndex.index) + || (((IInc) inc).count != 1)) + return 0; + + // Test first instruction: String arg = localObject[guiMap]; + if (firstInstruction.opcode != FastConstants.DECLARE) + return 0; + FastDeclaration declaration = (FastDeclaration) firstInstruction; + if (declaration.instruction == null) + return 0; + if ((declaration.instruction.opcode != FastConstants.STORE) + && (declaration.instruction.opcode != FastConstants.ASTORE) + && (declaration.instruction.opcode != FastConstants.ISTORE)) + return 0; + StoreInstruction siVariable = (StoreInstruction) declaration.instruction; + if (siVariable.valueref.opcode != ByteCodeConstants.ARRAYLOAD) + return 0; + ArrayLoadInstruction ali = (ArrayLoadInstruction) siVariable.valueref; + if ((ali.arrayref.opcode != ByteCodeConstants.ALOAD) || (ali.indexref.opcode != ByteCodeConstants.ILOAD) + || (((ALoad) ali.arrayref).index != siTmpArray.index) + || (((ILoad) ali.indexref).index != siIndex.index)) + return 0; + + return 3; + } + + /* + * Pattern SUN 1.5: 14: String[] strings = { "a", "b" }; 20: int j = + * (arrayOfString1 = strings).length; 48: for (int i = 0; i < j; ++i) { 33: + * String s = arrayOfString1[i]; 38: System.out.println(s); } + * + * Pattern SUN 1.6: String[] arr$ = { "a", "b" }; int len$ = arr$.length; + * for(int i$ = 0; i$ < len$; i$++) { String s = arr$[i$]; + * System.out.println(s); } + * + * Pattern IBM: 81: Object localObject = args; 84: GUIMap guiMap = 0; 116: + * for (GUIMap localGUIMap1 = localObject.length; guiMap < localGUIMap1; + * ++guiMap) { 99: String arg = localObject[guiMap]; 106: + * System.out.println(arg); } + * + * Return 0: No pattern 1: Pattern SUN 1.5 2: Pattern SUN 1.6 3: Pattern IBM + */ + private static int GetForEachArrayPatternType(ClassFile classFile, Instruction init, Instruction test, + Instruction inc, List list, int beforeWhileLoopIndex, List subList) { + // Tests: (Java 5 or later) + (Not empty sub list) + if ((classFile.getMajorVersion() < 49) || (beforeWhileLoopIndex == 0) || (subList.size() == 0)) + return 0; + + Instruction firstInstruction = subList.get(0); + + // Test: Same line number + if (test.lineNumber != firstInstruction.lineNumber) + return 0; + + Instruction beforeForInstruction = list.get(beforeWhileLoopIndex - 1); + + // Test: Same line number + if (test.lineNumber != beforeForInstruction.lineNumber) + return 0; + + // Test before 'for' instruction: + // SUN 1.5: j = (arrayOfString1 = strings).length; + // SUN 1.6: len$ = arr$.length; + // IBM : guiMap = 0; + if (beforeForInstruction.opcode != ByteCodeConstants.ISTORE) + return 0; + StoreInstruction si = (StoreInstruction) beforeForInstruction; + if (si.valueref.opcode == ByteCodeConstants.ARRAYLENGTH) { + ArrayLength al = ((ArrayLength) si.valueref); + if (al.arrayref.opcode == ByteCodeConstants.ASSIGNMENT) { + return GetForEachArraySun15PatternType(init, test, inc, firstInstruction, si); + } else if (beforeWhileLoopIndex > 1) { + Instruction beforeBeforeForInstruction = list.get(beforeWhileLoopIndex - 2); + return GetForEachArraySun16PatternType(init, test, inc, firstInstruction, si, + beforeBeforeForInstruction); + } + } + + if (si.valueref.opcode == ByteCodeConstants.ICONST) + return GetForEachArrayIbmPatternType(classFile, init, test, inc, list, beforeWhileLoopIndex, + firstInstruction, si); + + return 0; + } + + /* + * Type de boucle infinie: 0: for (;;) 1: for (beforeLoop; ;) 2: while + * (test) 3: for (beforeLoop; test;) 4: for (; ; lastBodyLoop) 5: for + * (beforeLoop; ; lastBodyLoop) 6: for (; test; lastBodyLoop) 7: for + * (beforeLoop; test; lastBodyLoop) + */ + private static int GetLoopType(Instruction beforeLoop, Instruction test, Instruction beforeLastBodyLoop, + Instruction lastBodyLoop) { + if (beforeLoop == null) { + // Cas possibles : 0, 2, 4, 6 + /* + * 0: for (;;) 2: while (test) 4: for (; ; lastBodyLoop) 6: for (; + * test; lastBodyLoop) + */ + if (test == null) { + // Cas possibles : 0, 4 + if (lastBodyLoop == null) { + // Cas possibles : 0 + return 0; + } else { + // Cas possibles : 0, 4 + return ((beforeLastBodyLoop != null) && (beforeLastBodyLoop.lineNumber > lastBodyLoop.lineNumber)) ? 4 + : 0; + } + } else { + // Cas possibles : 0, 2, 4, 6 + /* + * 2: while (test) 6: for (; test; lastBodyLoop) + */ + if (lastBodyLoop == null) { + // Cas possibles : 0, 2 + return 2; + } else { + // Cas possibles : 0, 2, 4, 6 + if (test.lineNumber == Instruction.UNKNOWN_LINE_NUMBER) { + return 2; + } else { + return (test.lineNumber == lastBodyLoop.lineNumber) ? 6 : 2; + } + } + } + } else { + if (beforeLoop.opcode == FastConstants.ASSIGNMENT) { + beforeLoop = ((AssignmentInstruction) beforeLoop).value1; + } + + // Cas possibles : 0, 1, 2, 3, 4, 5, 6, 7 + if (test == null) { + // Cas possibles : 0, 1, 4, 5 + /* + * 0: for (;;) 1: for (beforeLoop; ;) 4: for (; ; lastBodyLoop) + * 5: for (beforeLoop; ; lastBodyLoop) + */ + if (lastBodyLoop == null) { + // Cas possibles : 0, 1 + return 0; + } else { + if (lastBodyLoop.opcode == FastConstants.ASSIGNMENT) { + lastBodyLoop = ((AssignmentInstruction) lastBodyLoop).value1; + } + + // Cas possibles : 0, 1, 4, 5 + if (beforeLoop.lineNumber == Instruction.UNKNOWN_LINE_NUMBER) { + // beforeLoop & lastBodyLoop sont-elles des instructions + // d'affectation ou d'incrementation ? + // (a|d|f|i|l|s)store ou iinc ? + return CheckBeforeLoopAndLastBodyLoop(beforeLoop, lastBodyLoop) ? 5 : 0; + } else if (beforeLoop.lineNumber == lastBodyLoop.lineNumber) { + return 5; + } else { + return ((beforeLastBodyLoop != null) && + (beforeLastBodyLoop.lineNumber > lastBodyLoop.lineNumber)) ? 4 : 0; + } + } + } else { + // Cas possibles : 2, 3, 4, 5, 6, 7 + if (lastBodyLoop == null) { + // Cas possibles : 2, 3 + /* + * 2: while (test) 3: for (beforeLoop; test;) + */ + if (beforeLoop.lineNumber == Instruction.UNKNOWN_LINE_NUMBER) { + return 2; + } else { + return (beforeLoop.lineNumber == test.lineNumber) ? 3 : 2; + } + } else { + if (lastBodyLoop.opcode == FastConstants.ASSIGNMENT) { + lastBodyLoop = ((AssignmentInstruction) lastBodyLoop).value1; + } + + // Cas possibles : 0, 1, 2, 3, 4, 5, 6, 7 + if (beforeLoop.lineNumber == Instruction.UNKNOWN_LINE_NUMBER) { + // beforeLoop & lastBodyLoop sont-elles des instructions + // d'affectation ou d'incrementation ? + // (a|d|f|i|l|s)store ou iinc ? + /* + * 2: while (test) 7: for (beforeLoop; test; + * lastBodyLoop) + */ + return CheckBeforeLoopAndLastBodyLoop(beforeLoop, lastBodyLoop) ? 7 : 2; + } else { + if (beforeLastBodyLoop == null) { + if (beforeLoop.lineNumber == test.lineNumber) { + // Cas possibles : 3, 7 + /* + * 3: for (beforeLoop; test;) 7: for + * (beforeLoop; test; lastBodyLoop) + */ + return (beforeLoop.lineNumber == lastBodyLoop.lineNumber) ? 7 : 3; + } else { + // Cas possibles : 2, 6 + /* + * 2: while (test) 6: for (; test; lastBodyLoop) + */ + return (test.lineNumber == lastBodyLoop.lineNumber) ? 6 : 2; + } + } else { + if (beforeLastBodyLoop.lineNumber >= lastBodyLoop.lineNumber) { + // Cas possibles : 6, 7 + /* + * 6: for (; test; lastBodyLoop) 7: for + * (beforeLoop; test; lastBodyLoop) + */ + if (beforeLoop.lineNumber == test.lineNumber) { + return 7; + } else { + return CheckBeforeLoopAndLastBodyLoop(beforeLoop, lastBodyLoop) ? 7 : 6; + } + } else { + // Cas possibles : 2, 3 + /* + * 2: while (test) 3: for (beforeLoop; test;) + */ + return (beforeLoop.lineNumber == test.lineNumber) ? 3 : 2; + } + } + } + } + } + } + } + + private static boolean CheckBeforeLoopAndLastBodyLoop(Instruction beforeLoop, Instruction lastBodyLoop) { + switch (beforeLoop.opcode) { + case FastConstants.LOAD: + case FastConstants.STORE: + case FastConstants.ALOAD: + case FastConstants.ASTORE: + case FastConstants.GETSTATIC: + case FastConstants.PUTSTATIC: + case FastConstants.GETFIELD: + case FastConstants.PUTFIELD: { + switch (lastBodyLoop.opcode) { + case FastConstants.LOAD: + case FastConstants.STORE: + case FastConstants.ALOAD: + case FastConstants.ASTORE: + case FastConstants.GETSTATIC: + case FastConstants.PUTSTATIC: + case FastConstants.GETFIELD: + case FastConstants.PUTFIELD: { + return ((IndexInstruction) beforeLoop).index == ((IndexInstruction) lastBodyLoop).index; + } + } + } + break; + case FastConstants.ISTORE: { + if ((beforeLoop.opcode == lastBodyLoop.opcode) || (lastBodyLoop.opcode == FastConstants.IINC)) { + return ((IndexInstruction) beforeLoop).index == ((IndexInstruction) lastBodyLoop).index; + } + } + break; + } + + return false; + } + + /* + * debut de liste fin de liste | gotoIndex | | | | Liste ... + * --|----|---|==0===1===2===3===4===5===6==7=...=n---|--| ... | | | | | | | + * beforeListOffset | | Offsets | loopEntryOffset endLoopOffset | + * beforeLoopEntryOffset afterLoopOffset + */ + private static int AnalyzeBackGoto(ClassFile classFile, Method method, List list, + LocalVariables localVariables, IntSet offsetLabelSet, int beforeListOffset, int afterSubListOffset, + int returnOffset, int jumpInstructionIndex, Instruction jumpInstruction, int firstOffset) { + List subList = new ArrayList(); + int index = jumpInstructionIndex - 1; + + switch (jumpInstruction.opcode) { + case FastConstants.TRY: + case FastConstants.SYNCHRONIZED: + subList.add(list.get(jumpInstructionIndex)); + list.set(jumpInstructionIndex, null); + } + + while ((index >= 0) && (list.get(index).offset >= firstOffset)) + subList.add(list.remove(index--)); + + int subListLength = subList.size(); + + if (subListLength > 0) + { + Instruction beforeLoop = (index >= 0) ? list.get(index) : null; + if (beforeLoop != null) + beforeListOffset = beforeLoop.offset; + Instruction instruction = subList.get(subListLength - 1); + + // Search escape offset + int breakOffset = SearchMinusJumpOffset(subList, 0, subListLength, beforeListOffset, jumpInstruction.offset); + + // Search test instruction + BranchInstruction test = null; + + switch (instruction.opcode) { + case FastConstants.IF: + case FastConstants.IFCMP: + case FastConstants.IFXNULL: + case FastConstants.COMPLEXIF: + BranchInstruction bi = (BranchInstruction) instruction; + if (bi.GetJumpOffset() == breakOffset) + test = bi; + break; + } + + Instruction lastBodyLoop = null; + Instruction beforeLastBodyLoop = null; + + if (subListLength > 0) { + lastBodyLoop = subList.get(0); + + if (lastBodyLoop == test) { + lastBodyLoop = null; + } else if (subListLength > 1) { + beforeLastBodyLoop = subList.get(1); + if (beforeLastBodyLoop == test) + beforeLastBodyLoop = null; + + // V�rification qu'aucune instruction ne saute entre + // 'lastBodyLoop' et 'jumpInstruction' + if (!InstructionUtil.CheckNoJumpToInterval(subList, 0, subListLength, lastBodyLoop.offset, + jumpInstruction.offset)) { + // 'lastBodyLoop' ne peut pas etre l'instruction + // d'incrementation d'une boucle 'for' + lastBodyLoop = null; + beforeLastBodyLoop = null; + } else if (!InstructionUtil.CheckNoJumpToInterval(subList, 0, subListLength, beforeListOffset, + firstOffset)) { + // 'lastBodyLoop' ne peut pas etre l'instruction + // d'incrementation d'une boucle 'for' + lastBodyLoop = null; + beforeLastBodyLoop = null; + } + } + } + + int typeLoop = GetLoopType(beforeLoop, test, beforeLastBodyLoop, lastBodyLoop); + + switch (typeLoop) { + case 0: // for (;;) + { + Collections.reverse(subList); + Instruction firstBodyLoop = subList.get(0); + + AnalyzeList(classFile, method, subList, localVariables, offsetLabelSet, beforeListOffset, + firstBodyLoop.offset, afterSubListOffset, beforeListOffset, afterSubListOffset, breakOffset, + returnOffset); + + int branch = 1; + if (breakOffset != -1) + branch = breakOffset - jumpInstruction.offset; + + list.set(++index, new FastList(FastConstants.INFINITE_LOOP, jumpInstruction.offset, + Instruction.UNKNOWN_LINE_NUMBER, branch, subList)); + } + break; + case 1: // for (beforeLoop; ;) + { + Collections.reverse(subList); + Instruction firstBodyLoop = subList.get(0); + + AnalyzeList(classFile, method, subList, localVariables, offsetLabelSet, beforeLoop.offset, + firstBodyLoop.offset, afterSubListOffset, beforeListOffset, afterSubListOffset, breakOffset, + returnOffset); + + int branch = 1; + if (breakOffset != -1) + branch = breakOffset - jumpInstruction.offset; + + list.set(++index, new FastList(FastConstants.INFINITE_LOOP, jumpInstruction.offset, + Instruction.UNKNOWN_LINE_NUMBER, branch, subList)); + } + break; + case 2: // while (test) + { + // Remove test + subList.remove(--subListLength); + + if (subListLength > 0) { + Collections.reverse(subList); + + int beforeTestOffset; + + if (beforeLoop == null) + beforeTestOffset = (beforeListOffset == -1) ? -1 : beforeListOffset; + else + beforeTestOffset = beforeLoop.offset; + + AnalyzeList(classFile, method, subList, localVariables, offsetLabelSet, beforeTestOffset, + test.offset, afterSubListOffset, test.offset, afterSubListOffset, breakOffset, returnOffset); + } + + int branch = 1; + if (breakOffset != -1) + branch = breakOffset - jumpInstruction.offset; + + // 'while' + ComparisonInstructionAnalyzer.InverseComparison(test); + list.set(++index, new FastTestList(FastConstants.WHILE, jumpInstruction.offset, test.lineNumber, + branch, test, subList)); + } + break; + case 3: // for (beforeLoop; test;) + { + // Remove initialisation instruction before sublist + list.remove(index); + // Remove test + subList.remove(--subListLength); + + if (subListLength > 0) { + lastBodyLoop = subList.get(0); + Collections.reverse(subList); + + AnalyzeList(classFile, method, subList, localVariables, offsetLabelSet, beforeLoop.offset, + test.offset, afterSubListOffset, test.offset, afterSubListOffset, breakOffset, returnOffset); + } + + ComparisonInstructionAnalyzer.InverseComparison(test); + CreateForLoopCase1(classFile, method, list, index, beforeLoop, test, subList, breakOffset); + } + break; + case 4: // for (; ; lastBodyLoop) + { + Collections.reverse(subList); + // Remove incrementation instruction + subList.remove(--subListLength); + + if (subListLength > 0) { + beforeLastBodyLoop = subList.get(--subListLength); + + AnalyzeList(classFile, method, subList, localVariables, offsetLabelSet, beforeLastBodyLoop.offset, + lastBodyLoop.offset, lastBodyLoop.offset, beforeListOffset, afterSubListOffset, + breakOffset, returnOffset); + } + + int branch = 1; + if (breakOffset != -1) + branch = breakOffset - jumpInstruction.offset; + + list.set(++index, new FastFor(FastConstants.FOR, jumpInstruction.offset, lastBodyLoop.lineNumber, + branch, null, null, lastBodyLoop, subList)); + } + break; + case 5: // for (beforeLoop; ; lastBodyLoop) + // Remove initialisation instruction before sublist + list.remove(index); + + Collections.reverse(subList); + // Remove incrementation instruction + subList.remove(--subListLength); + + if (subListLength > 0) { + beforeLastBodyLoop = subList.get(--subListLength); + + AnalyzeList(classFile, method, subList, localVariables, offsetLabelSet, beforeLastBodyLoop.offset, + lastBodyLoop.offset, lastBodyLoop.offset, beforeListOffset, afterSubListOffset, + breakOffset, returnOffset); + } + + int branch = 1; + if (breakOffset != -1) + branch = breakOffset - jumpInstruction.offset; + + list.set(index, new FastFor(FastConstants.FOR, jumpInstruction.offset, lastBodyLoop.lineNumber, branch, + beforeLoop, null, lastBodyLoop, subList)); + break; + case 6: // for (; test; lastBodyLoop) + // Remove test + subList.remove(--subListLength); + + if (subListLength > 1) { + Collections.reverse(subList); + // Remove incrementation instruction + subList.remove(--subListLength); + + if (subListLength > 0) { + beforeLastBodyLoop = subList.get(subListLength - 1); + + AnalyzeList(classFile, method, subList, localVariables, offsetLabelSet, + beforeLastBodyLoop.offset, lastBodyLoop.offset, lastBodyLoop.offset, test.offset, + afterSubListOffset, breakOffset, returnOffset); + } + + branch = 1; + if (breakOffset != -1) + branch = breakOffset - jumpInstruction.offset; + + ComparisonInstructionAnalyzer.InverseComparison(test); + list.set(++index, new FastFor(FastConstants.FOR, jumpInstruction.offset, lastBodyLoop.lineNumber, + branch, null, test, lastBodyLoop, subList)); + } else { + if (subListLength == 1) { + int beforeTestOffset; + + if (beforeLoop == null) + beforeTestOffset = (beforeListOffset == -1) ? -1 : beforeListOffset; + else + beforeTestOffset = beforeLoop.offset; + + AnalyzeList(classFile, method, subList, localVariables, offsetLabelSet, beforeTestOffset, + test.offset, lastBodyLoop.offset, test.offset, afterSubListOffset, breakOffset, + returnOffset); + } + + branch = 1; + if (breakOffset != -1) + branch = breakOffset - jumpInstruction.offset; + + // 'while' + ComparisonInstructionAnalyzer.InverseComparison(test); + list.set(++index, new FastTestList(FastConstants.WHILE, jumpInstruction.offset, test.lineNumber, + branch, test, subList)); + } + break; + case 7: // for (beforeLoop; test; lastBodyLoop) + // Remove initialisation instruction before sublist + list.remove(index); + // Remove test + subList.remove(--subListLength); + + Collections.reverse(subList); + // Remove incrementation instruction + subList.remove(--subListLength); + + if (subListLength > 0) { + beforeLastBodyLoop = subList.get(subListLength - 1); + + AnalyzeList(classFile, method, subList, localVariables, offsetLabelSet, beforeLastBodyLoop.offset, + lastBodyLoop.offset, lastBodyLoop.offset, test.offset, afterSubListOffset, breakOffset, + returnOffset); + } + + ComparisonInstructionAnalyzer.InverseComparison(test); + index = CreateForLoopCase3(classFile, method, list, index, beforeLoop, test, lastBodyLoop, subList, + breakOffset); + break; + } + } else { + // Empty infinite loop + list.set(++index, new FastList(FastConstants.INFINITE_LOOP, jumpInstruction.offset, + Instruction.UNKNOWN_LINE_NUMBER, 0, subList)); + } + + return index; + } + + /* + * debut de liste fin de liste | testIndex | | | | Liste ... + * --|----|---|==0===1===2===3===4===5===6==7=...=n---|--| ... | | | | | | | + * beforeListOffset | | Offsets | loopEntryOffset endLoopOffset | + * beforeLoopEntryOffset afterLoopOffset + */ + private static void AnalyzeIfAndIfElse(ClassFile classFile, Method method, List list, + LocalVariables localVariables, IntSet offsetLabelSet, int beforeLoopEntryOffset, int loopEntryOffset, + int afterBodyLoopOffset, int afterListOffset, int breakOffset, int returnOffset, int testIndex, + ConditionalBranchInstruction test) { + int length = list.size(); + + if (length == 0) + return; + + int elseOffset = test.GetJumpOffset(); + // if (elseOffset == breakOffset) NE PLUS PRODUIRE D'INSTRUCTIONS + // IF_CONTINUE ET IF_BREAK + // return; + + if ((test.branch < 0) && + (beforeLoopEntryOffset < elseOffset) && + (elseOffset <= loopEntryOffset) && + (afterBodyLoopOffset == afterListOffset)) + { + // L'instruction saute sur un debut de boucle et la liste termine + // le block de la boucle. + elseOffset = afterListOffset; + } + + if ((elseOffset <= test.offset) || + ((afterListOffset != -1) && (elseOffset > afterListOffset))) + return; + + // Analyse classique des instructions 'if' + int index = testIndex + 1; + + if (index < length) { + // Non empty 'if'. Construct if block instructions + List subList = new ArrayList(); + length = ExtrackBlock(list, subList, index, length, elseOffset); + int subListLength = subList.size(); + + if (subListLength == 0) { + // Empty 'if' + ComparisonInstructionAnalyzer.InverseComparison(test); + list.set(testIndex, new FastTestList(FastConstants.IF_, test.offset, test.lineNumber, elseOffset + - test.offset, test, null)); + return; + } + + int beforeSubListOffset = test.offset; + Instruction beforeElseBlock = subList.get(subListLength - 1); + int minusJumpOffset = SearchMinusJumpOffset( + subList, 0, subListLength, + test.offset, beforeElseBlock.offset); + int lastListOffset = list.get(length - 1).offset; + + // TODO le bloc suivant est a revoir : produit une erreur dans + // com.adventnet.snmp.ui.SasFileDialog:void + // mouseDoubleClicked(MouseEvent e) + if ((minusJumpOffset == -1) + && (subListLength > 1) + && (beforeElseBlock.opcode == ByteCodeConstants.RETURN) + && ((afterListOffset == -1) || (afterListOffset == returnOffset) || + ByteCodeUtil.JumpTo( + method.getCode(), + ByteCodeUtil.NextInstructionOffset(method.getCode(), lastListOffset), returnOffset))) { + // Si la derniere instruction est un 'return' et si son + // numero de ligne est inferieur a l'instruction precedente, + // il s'agit d'une instruction synthetique ==> if-else + if (subList.get(subListLength - 2).lineNumber > beforeElseBlock.lineNumber) { + minusJumpOffset = (returnOffset == -1) ? lastListOffset + 1 : returnOffset; + } + // Sinon, si l'instruction 'return' a un numero de ligne + // superieure au numero de ligne de l'instruction suivante, + // elle est prise en compte aussi + else if ((index < length) && (list.get(index).lineNumber < beforeElseBlock.lineNumber)) { + minusJumpOffset = (returnOffset == -1) ? lastListOffset + 1 : returnOffset; + } + } + + if (minusJumpOffset != -1) + { + if ((subListLength == 1) && + (beforeElseBlock.opcode == FastConstants.GOTO)) + { + // Instruction 'if' suivi d'un bloc contenant un seul 'goto' + // ==> Generation d'une instrcution 'break' ou 'continue' + CreateBreakAndContinue(method, subList, offsetLabelSet, beforeLoopEntryOffset, loopEntryOffset, + afterBodyLoopOffset, afterListOffset, breakOffset, returnOffset); + + ComparisonInstructionAnalyzer.InverseComparison(test); + list.set(testIndex, new FastTestList(FastConstants.IF_, beforeElseBlock.offset, test.lineNumber, + elseOffset - beforeElseBlock.offset, test, subList)); + return; + } + + int afterIfElseOffset; + + if ((minusJumpOffset < test.offset) && + (beforeLoopEntryOffset < minusJumpOffset) && + (minusJumpOffset <= loopEntryOffset)) + { + // Jump to loop entry ==> continue + int positiveJumpOffset = SearchMinusJumpOffset( + subList, 0, subListLength, -1, beforeElseBlock.offset); + + // S'il n'y a pas de saut positif ou si le saut mini positif + // est au dela de la fin de la liste (pour sauter vers le + // 'return' final par exemple) et si la liste courante termine + // la boucle courante + if (((positiveJumpOffset == -1) || (positiveJumpOffset >= afterListOffset)) && + (afterBodyLoopOffset == afterListOffset)) + { + // Cas des instructions de saut n�gatif dans une boucle qui + // participent tout de meme � une instruction if-else + // L'instruction saute sur un debut de boucle et la liste + // termine le block de la boucle. + afterIfElseOffset = afterListOffset; + } else { + // If-else + afterIfElseOffset = positiveJumpOffset; + } + + } else { + // If ou If-else + afterIfElseOffset = minusJumpOffset; + } + + if ((afterIfElseOffset > elseOffset) + && ((afterListOffset == -1) || (afterIfElseOffset <= afterListOffset) || + ByteCodeUtil.JumpTo( + method.getCode(), + ByteCodeUtil.NextInstructionOffset(method.getCode(), lastListOffset), afterIfElseOffset))) + { + // If-else or If-elseif-... + if (((beforeElseBlock.opcode == FastConstants.GOTO) && (((Goto) beforeElseBlock).GetJumpOffset() == minusJumpOffset)) + || (beforeElseBlock.opcode == ByteCodeConstants.RETURN)) { + // Remove 'goto' or 'return' + subList.remove(subListLength - 1); + } + + // Construct else block instructions + List subElseList = new ArrayList(); + length = ExtrackBlock(list, subElseList, index, length, afterIfElseOffset); + + if (subElseList.size() > 0) { + AnalyzeList( + classFile, method, subList, localVariables, offsetLabelSet, beforeLoopEntryOffset, + loopEntryOffset, afterBodyLoopOffset, beforeSubListOffset, afterIfElseOffset, + breakOffset, returnOffset); + + beforeSubListOffset = beforeElseBlock.offset; + + AnalyzeList(classFile, method, subElseList, localVariables, offsetLabelSet, + beforeLoopEntryOffset, loopEntryOffset, afterBodyLoopOffset, beforeSubListOffset, + afterIfElseOffset, breakOffset, returnOffset); + + int subElseListLength = subElseList.size(); + int lastIfElseOffset = (subElseListLength > 0) ? + subElseList.get(subElseListLength - 1).offset : + beforeSubListOffset; + + ComparisonInstructionAnalyzer.InverseComparison(test); + list.set(testIndex, new FastTest2Lists( + FastConstants.IF_ELSE, lastIfElseOffset, test.lineNumber, + afterIfElseOffset - lastIfElseOffset, test, subList, subElseList)); + return; + } + } + } + + // Simple 'if' + AnalyzeList(classFile, method, subList, localVariables, offsetLabelSet, beforeLoopEntryOffset, + loopEntryOffset, afterBodyLoopOffset, beforeSubListOffset, elseOffset, breakOffset, returnOffset); + + ComparisonInstructionAnalyzer.InverseComparison(test); + list.set(testIndex, new FastTestList( + FastConstants.IF_, beforeElseBlock.offset, test.lineNumber, + elseOffset - beforeElseBlock.offset, test, subList)); + } else if (elseOffset == breakOffset) { + // If-break + list.set(testIndex, new FastInstruction(FastConstants.IF_BREAK, test.offset, test.lineNumber, test)); + } else { + // Empty 'if' + list.set(testIndex, new FastTestList(FastConstants.IF_, test.offset, test.lineNumber, elseOffset + - test.offset, test, null)); + } + } + + private static int ExtrackBlock( + List list, List subList, + int index, int length, int endOffset) + { + while ((index < length) && (list.get(index).offset < endOffset)) { + subList.add(list.remove(index)); + length--; + } + + return length; + } + + /* + * debut de liste fin de liste | switchIndex | | | | Liste ... + * --|----|---|==0===1===2===3===4===5===6==7=...=n---|--| ... | | | | | | | + * beforeListOffset | | Offsets | loopEntryOffset endLoopOffset | + * beforeLoopEntryOffset afterLoopOffset + */ + private static void AnalyzeLookupSwitch(ClassFile classFile, Method method, List list, + LocalVariables localVariables, IntSet offsetLabelSet, int beforeLoopEntryOffset, int loopEntryOffset, + int afterBodyLoopOffset, int afterListOffset, int returnOffset, int switchIndex, LookupSwitch ls) { + int pairLength = ls.keys.length; + FastSwitch.Pair[] pairs = new FastSwitch.Pair[pairLength + 1]; + + // Construct list of pairs + boolean defaultFlag = true; + int pairIndex = 0; + for (int i = 0; i < pairLength; i++) { + if (defaultFlag && (ls.offsets[i] > ls.defaultOffset)) { + pairs[pairIndex++] = new FastSwitch.Pair(true, 0, ls.offset + ls.defaultOffset); + defaultFlag = false; + } + + pairs[pairIndex++] = new FastSwitch.Pair(false, ls.keys[i], ls.offset + ls.offsets[i]); + } + + if (defaultFlag) + pairs[pairIndex++] = new FastSwitch.Pair(true, 0, ls.offset + ls.defaultOffset); + + // SWITCH or SWITCH_ENUM ? + int switchOpcode = AnalyzeSwitchType(classFile, ls.key); + + // SWITCH or Eclipse SWITCH_STRING ? + if ((classFile.getMajorVersion() >= 51) && (switchOpcode == FastConstants.SWITCH) + && (ls.key.opcode == ByteCodeConstants.ILOAD) && (switchIndex > 2)) { + if (AnalyzeSwitchString(classFile, localVariables, list, switchIndex, ls, pairs)) { + // Switch+String found. + // Remove FastSwitch + list.remove(--switchIndex); + // Remove IStore + list.remove(--switchIndex); + // Remove AStore + list.remove(--switchIndex); + // Change opcode + switchOpcode = FastConstants.SWITCH_STRING; + } + } + + AnalyzeSwitch(classFile, method, list, localVariables, offsetLabelSet, beforeLoopEntryOffset, loopEntryOffset, + afterBodyLoopOffset, afterListOffset, returnOffset, switchIndex, switchOpcode, ls.offset, + ls.lineNumber, ls.key, pairs, pairLength); + } + + private static int AnalyzeSwitchType(ClassFile classFile, Instruction i) + { + if (i.opcode == ByteCodeConstants.ARRAYLOAD) + { + // switch(1.$SwitchMap$basic$data$TestEnum$enum1[e.ordinal()]) ? + // switch(1.$SwitchMap$basic$data$TestEnum$enum1[request.getOperationType().ordinal()]) ? + ArrayLoadInstruction ali = (ArrayLoadInstruction)i; + + if (ali.indexref.opcode == ByteCodeConstants.INVOKEVIRTUAL) + { + if (ali.arrayref.opcode == ByteCodeConstants.GETSTATIC) + { + GetStatic gs = (GetStatic) ali.arrayref; + + ConstantPool constants = classFile.getConstantPool(); + ConstantFieldref cfr = constants.getConstantFieldref(gs.index); + ConstantNameAndType cnat = constants.getConstantNameAndType(cfr.name_and_type_index); + + if (classFile.getSwitchMaps().containsKey(cnat.name_index)) { + Invokevirtual iv = (Invokevirtual) ali.indexref; + + if (iv.args.size() == 0) { + ConstantMethodref cmr = constants.getConstantMethodref(iv.index); + cnat = constants.getConstantNameAndType(cmr.name_and_type_index); + + if (StringConstants.ORDINAL_METHOD_NAME.equals(constants.getConstantUtf8(cnat.name_index))) { + // SWITCH_ENUM found + return FastConstants.SWITCH_ENUM; + } + } + } + } + else if (ali.arrayref.opcode == ByteCodeConstants.INVOKESTATIC) + { + Invokestatic is = (Invokestatic) ali.arrayref; + + if (is.args.size() == 0) { + ConstantPool constants = classFile.getConstantPool(); + ConstantMethodref cmr = constants.getConstantMethodref(is.index); + + if (cmr.class_index == classFile.getThisClassIndex()) { + ConstantNameAndType cnat = constants.getConstantNameAndType(cmr.name_and_type_index); + if (classFile.getSwitchMaps().containsKey(cnat.name_index)) { + Invokevirtual iv = (Invokevirtual) ali.indexref; + + if (iv.args.size() == 0) { + cmr = constants.getConstantMethodref(iv.index); + cnat = constants.getConstantNameAndType(cmr.name_and_type_index); + + if (StringConstants.ORDINAL_METHOD_NAME.equals(constants.getConstantUtf8(cnat.name_index))) { + // Eclipse SWITCH_ENUM found + return FastConstants.SWITCH_ENUM; + } + } + } + } + } + } + } + } + + return FastConstants.SWITCH; + } + + /* + * debut de liste fin de liste | switchIndex | | | | Liste ... + * --|----|---|==0===1===2===3===4===5===6==7=...=n---|--| ... | | | | | | | + * beforeListOffset | | Offsets | loopEntryOffset endLoopOffset | + * beforeLoopEntryOffset afterLoopOffset + */ + private static int AnalyzeTableSwitch(ClassFile classFile, Method method, List list, + LocalVariables localVariables, IntSet offsetLabelSet, int beforeLoopEntryOffset, int loopEntryOffset, + int afterBodyLoopOffset, int afterListOffset, int returnOffset, int switchIndex, TableSwitch ts) { + int pairLength = ts.offsets.length; + FastSwitch.Pair[] pairs = new FastSwitch.Pair[pairLength + 1]; + + // Construct list of pairs + boolean defaultFlag = true; + int pairIndex = 0; + for (int i = 0; i < pairLength; i++) { + if (defaultFlag && (ts.offsets[i] > ts.defaultOffset)) { + pairs[pairIndex++] = new FastSwitch.Pair(true, 0, ts.offset + ts.defaultOffset); + defaultFlag = false; + } + + pairs[pairIndex++] = new FastSwitch.Pair(false, ts.low + i, ts.offset + ts.offsets[i]); + } + + if (defaultFlag) + pairs[pairIndex++] = new FastSwitch.Pair(true, 0, ts.offset + ts.defaultOffset); + + // SWITCH or Eclipse SWITCH_ENUM ? + int switchOpcode = AnalyzeSwitchType(classFile, ts.key); + + // SWITCH or Eclipse SWITCH_STRING ? + if ((classFile.getMajorVersion() >= 51) && (switchOpcode == FastConstants.SWITCH) + && (ts.key.opcode == ByteCodeConstants.ILOAD) && (switchIndex > 2)) { + if (AnalyzeSwitchString(classFile, localVariables, list, switchIndex, ts, pairs)) { + // Switch+String found. + // Remove FastSwitch + list.remove(--switchIndex); + // Remove IStore + list.remove(--switchIndex); + // Remove AStore + list.remove(--switchIndex); + // Change opcode + switchOpcode = FastConstants.SWITCH_STRING; + } + } + + AnalyzeSwitch(classFile, method, list, localVariables, offsetLabelSet, beforeLoopEntryOffset, loopEntryOffset, + afterBodyLoopOffset, afterListOffset, returnOffset, switchIndex, switchOpcode, ts.offset, + ts.lineNumber, ts.key, pairs, pairLength); + + return switchIndex; + } + + private static boolean AnalyzeSwitchString(ClassFile classFile, LocalVariables localVariables, + List list, int switchIndex, Switch s, FastSwitch.Pair[] pairs) { + Instruction instruction = list.get(switchIndex - 3); + if ((instruction.opcode != FastConstants.ASTORE) || (instruction.lineNumber != s.key.lineNumber)) + return false; + AStore astore = (AStore) instruction; + + instruction = list.get(switchIndex - 2); + if ((instruction.opcode != FastConstants.ISTORE) || (instruction.lineNumber != astore.lineNumber)) + return false; + + instruction = list.get(switchIndex - 1); + if ((instruction.opcode != FastConstants.SWITCH) || (instruction.lineNumber != astore.lineNumber)) + return false; + + FastSwitch previousSwitch = (FastSwitch) instruction; + if (previousSwitch.test.opcode != FastConstants.INVOKEVIRTUAL) + return false; + + Invokevirtual iv = (Invokevirtual) previousSwitch.test; + + if ((iv.objectref.opcode != FastConstants.ALOAD) || (iv.args.size() != 0)) + return false; + + ConstantPool constants = classFile.getConstantPool(); + ConstantMethodref cmr = constants.getConstantMethodref(iv.index); + + if (!cmr.getReturnedSignature().equals("I")) + return false; + + String className = constants.getConstantClassName(cmr.class_index); + if (!className.equals("java/lang/String")) + return false; + + ConstantNameAndType cnat = constants.getConstantNameAndType(cmr.name_and_type_index); + String descriptorName = constants.getConstantUtf8(cnat.descriptor_index); + if (!descriptorName.equals("()I")) + return false; + + String methodName = constants.getConstantUtf8(cnat.name_index); + if (!methodName.equals("hashCode")) + return false; + + Pair[] previousPairs = previousSwitch.pairs; + int i = previousPairs.length; + if (i == 0) + return false; + + int tsKeyIloadIndex = ((ILoad) s.key).index; + int previousSwitchAloadIndex = ((ALoad) iv.objectref).index; + HashMap stringIndexes = new HashMap(); + + while (i-- > 0) { + Pair pair = previousPairs[i]; + if (pair.isDefault()) + continue; + + List instructions = pair.getInstructions(); + + for (;;) { + int length = instructions.size(); + if (length == 0) + return false; + + instruction = instructions.get(0); + + /* + * if (instruction.opcode == FastConstants.IF_BREAK) { if + * (((length == 2) || (length == 3)) && + * (AnalyzeSwitchStringTestInstructions( constants, cmr, + * tsKeyIloadIndex, previousSwitchAloadIndex, stringIndexes, + * ((FastInstruction)instruction).instruction, + * instructions.get(1), FastConstants.CMP_EQ))) { break; } else + * { return false; } } else + */if (instruction.opcode == FastConstants.IF_) { + switch (length) { + case 1: + break; + case 2: + if (instructions.get(1).opcode == FastConstants.GOTO_BREAK) + break; + default: + return false; + } + FastTestList ftl = (FastTestList) instruction; + if ((ftl.instructions.size() == 1) + && AnalyzeSwitchStringTestInstructions(constants, cmr, tsKeyIloadIndex, + previousSwitchAloadIndex, stringIndexes, ftl.test, ftl.instructions.get(0), + FastConstants.CMP_NE)) { + break; + } else { + return false; + } + } else if (instruction.opcode == FastConstants.IF_ELSE) { + if (length != 1) + return false; + FastTest2Lists ft2l = (FastTest2Lists) instruction; + if ((ft2l.instructions.size() == 1) + && AnalyzeSwitchStringTestInstructions(constants, cmr, tsKeyIloadIndex, + previousSwitchAloadIndex, stringIndexes, ft2l.test, ft2l.instructions.get(0), + FastConstants.CMP_NE)) { + instructions = ft2l.instructions2; + } else { + return false; + } + } else { + return false; + } + } + } + + // First switch instruction for Switch+String found + // Replace value of each pair + i = pairs.length; + + while (i-- > 0) { + Pair pair = pairs[i]; + if (pair.isDefault()) + continue; + pair.setKey(stringIndexes.get(pair.getKey())); + } + + // Remove synthetic local variable integer + localVariables.removeLocalVariableWithIndexAndOffset(tsKeyIloadIndex, s.key.offset); + // Remove synthetic local variable string + localVariables.removeLocalVariableWithIndexAndOffset(astore.index, astore.offset); + // Replace switch test + s.key = astore.valueref; + + return true; + } + + private static boolean AnalyzeSwitchStringTestInstructions(ConstantPool constants, ConstantMethodref cmr, + int tsKeyIloadIndex, int previousSwitchAloadIndex, HashMap stringIndexes, + Instruction test, Instruction value, int cmp) { + if (test.opcode != FastConstants.IF) + return false; + + if (value.opcode != FastConstants.ISTORE) + return false; + + IStore istore = (IStore) value; + if (istore.index != tsKeyIloadIndex) + return false; + + int opcode = istore.valueref.opcode; + int index; + + if (opcode == FastConstants.BIPUSH) + index = ((BIPush) istore.valueref).value; + else if (opcode == FastConstants.ICONST) + index = ((IConst) istore.valueref).value; + else + return false; + + IfInstruction ii = (IfInstruction) test; + if ((ii.cmp != cmp) || (ii.value.opcode != FastConstants.INVOKEVIRTUAL)) + return false; + + Invokevirtual ivTest = (Invokevirtual) ii.value; + + if ((ivTest.args.size() != 1) || (ivTest.objectref.opcode != FastConstants.ALOAD) + || (((ALoad) ivTest.objectref).index != previousSwitchAloadIndex) + || (ivTest.args.get(0).opcode != FastConstants.LDC)) + return false; + + ConstantMethodref cmrTest = constants.getConstantMethodref(ivTest.index); + if (cmr.class_index != cmrTest.class_index) + return false; + + ConstantNameAndType cnatTest = constants.getConstantNameAndType(cmrTest.name_and_type_index); + String descriptorNameTest = constants.getConstantUtf8(cnatTest.descriptor_index); + if (!descriptorNameTest.equals("(Ljava/lang/Object;)Z")) + return false; + + String methodNameTest = constants.getConstantUtf8(cnatTest.name_index); + if (!methodNameTest.equals("equals")) + return false; + + stringIndexes.put(index, Integer.valueOf(((Ldc) ivTest.args.get(0)).index)); + + return true; + } + + /* + * debut de liste fin de liste | switchIndex | | | | Liste ... + * --|----|---|==0===1===2===3===4===5===6==7=...=n---|--| ... | | | | | | | + * | beforeListOff. | | | Offsets | loopEntryOffset switchOffset + * endLoopOffset | beforeLoopEntryOffset afterLoopOffset + */ + private static void AnalyzeSwitch(ClassFile classFile, Method method, List list, + LocalVariables localVariables, IntSet offsetLabelSet, int beforeLoopEntryOffset, int loopEntryOffset, + int afterBodyLoopOffset, int afterListOffset, int returnOffset, int switchIndex, int switchOpcode, + int switchOffset, int switchLineNumber, Instruction test, FastSwitch.Pair[] pairs, int pairLength) { + int breakOffset = -1; + + // Order pairs by offset + Arrays.sort(pairs); + + // Extract list of instructions for all pairs + int lastSwitchOffset = switchOffset; + int index = switchIndex + 1; + + if (index < list.size()) { + // Switch non vide ou non en derniere position dans la serie + // d'instructions + for (int i = 0; i < pairLength; i++) + { + ArrayList instructions = null; + int beforeCaseOffset = lastSwitchOffset; + int afterCaseOffset = pairs[i + 1].getOffset(); + + while (index < list.size()) + { + Instruction instruction = list.get(index); + if (instruction.offset >= afterCaseOffset) + { + if (instructions != null) + { + int nbrInstrucrions = instructions.size(); + if (nbrInstrucrions > 0) + { + // Recherche de 'breakOffset' + int breakOffsetTmp = SearchMinusJumpOffset(instructions, 0, nbrInstrucrions, + beforeCaseOffset, lastSwitchOffset); + if (breakOffsetTmp != -1) { + if ((breakOffset == -1) || (breakOffset > breakOffsetTmp)) + breakOffset = breakOffsetTmp; + } + + // Remplacement du dernier 'goto' + instruction = instructions.get(nbrInstrucrions - 1); + if (instruction.opcode == FastConstants.GOTO) { + int lineNumber = instruction.lineNumber; + + if ((nbrInstrucrions <= 1) || (instructions.get(nbrInstrucrions-2).lineNumber == lineNumber)) + lineNumber = Instruction.UNKNOWN_LINE_NUMBER; + + // Replace goto by break; + instructions.set(nbrInstrucrions - 1, new FastInstruction(FastConstants.GOTO_BREAK, + instruction.offset, lineNumber, null)); + } + } + } + break; + } + + if (instructions == null) + instructions = new ArrayList(); + + list.remove(index); + instructions.add(instruction); + lastSwitchOffset = instruction.offset; + } + + pairs[i].setInstructions(instructions); + } + + // Extract last block + if (breakOffset != -1) { + int afterSwitchOffset = (breakOffset >= switchOffset) ? breakOffset + : list.get(list.size() - 1).offset + 1; + + // Reduction de 'afterSwitchOffset' via les 'Branch + // Instructions' + Instruction instruction; + // Check previous instructions + int i = switchIndex; + while (i-- > 0) { + instruction = list.get(i); + + switch (instruction.opcode) { + case ByteCodeConstants.IF: + case ByteCodeConstants.IFCMP: + case ByteCodeConstants.IFXNULL: + case ByteCodeConstants.GOTO: + case FastConstants.SWITCH: + case FastConstants.SWITCH_ENUM: + case FastConstants.SWITCH_STRING: + int jumpOffset = ((BranchInstruction) instruction).GetJumpOffset(); + if ((lastSwitchOffset < jumpOffset) && (jumpOffset < afterSwitchOffset)) + afterSwitchOffset = jumpOffset; + } + } + // Check next instructions + i = list.size(); + while (i-- > 0) { + instruction = list.get(i); + + switch (instruction.opcode) { + case ByteCodeConstants.IF: + case ByteCodeConstants.IFCMP: + case ByteCodeConstants.IFXNULL: + case ByteCodeConstants.GOTO: + case FastConstants.SWITCH: + case FastConstants.SWITCH_ENUM: + case FastConstants.SWITCH_STRING: + int jumpOffset = ((BranchInstruction) instruction).GetJumpOffset(); + if ((lastSwitchOffset < jumpOffset) && (jumpOffset < afterSwitchOffset)) + afterSwitchOffset = jumpOffset; + } + + if ((instruction.offset <= afterSwitchOffset) || (instruction.offset <= lastSwitchOffset)) + break; + } + + // Extraction + List instructions = null; + + while (index < list.size()) + { + instruction = list.get(index); + if (instruction.offset >= afterSwitchOffset) + { + if (instructions != null) + { + int nbrInstrucrions = instructions.size(); + if (nbrInstrucrions > 0) + { + instruction = instructions.get(nbrInstrucrions - 1); + if (instruction.opcode == FastConstants.GOTO) { + int lineNumber = instruction.lineNumber; + + if ((nbrInstrucrions <= 1) || (instructions.get(nbrInstrucrions-2).lineNumber == lineNumber)) + lineNumber = Instruction.UNKNOWN_LINE_NUMBER; + + // Replace goto by break; + instructions.set(nbrInstrucrions - 1, new FastInstruction(FastConstants.GOTO_BREAK, + instruction.offset, instruction.lineNumber, null)); + } + } + } + break; + } + + if (instructions == null) + instructions = new ArrayList(); + + list.remove(index); + instructions.add(instruction); + lastSwitchOffset = instruction.offset; + } + + pairs[pairLength].setInstructions(instructions); + } + + // Analyze instructions (recursive analyze) + int beforeListOffset = test.offset; + if (index < list.size()) + afterListOffset = list.get(index).offset; + + for (int i = 0; i <= pairLength; i++) + { + FastSwitch.Pair pair = pairs[i]; + List instructions = pair.getInstructions(); + if (instructions != null) + { + int nbrInstrucrions = instructions.size(); + if (nbrInstrucrions > 0) + { + Instruction instruction = instructions.get(nbrInstrucrions - 1); + if (instruction.opcode == FastConstants.GOTO_BREAK) + { + instructions.remove(nbrInstrucrions - 1); + AnalyzeList(classFile, method, instructions, localVariables, offsetLabelSet, + beforeLoopEntryOffset, loopEntryOffset, afterBodyLoopOffset, beforeListOffset, + afterListOffset, breakOffset, returnOffset); + instructions.add(instruction); + } + else + { + AnalyzeList(classFile, method, instructions, localVariables, offsetLabelSet, + beforeLoopEntryOffset, loopEntryOffset, afterBodyLoopOffset, beforeListOffset, + afterListOffset, breakOffset, returnOffset); + + nbrInstrucrions = instructions.size(); + if (nbrInstrucrions > 0) + { + instruction = instructions.get(nbrInstrucrions - 1); + + switch (instruction.opcode) + { + case ByteCodeConstants.IF: + case ByteCodeConstants.IFCMP: + case ByteCodeConstants.IFXNULL: + case FastConstants.IF_: + case FastConstants.IF_ELSE: + case ByteCodeConstants.GOTO: + case FastConstants.SWITCH: + case FastConstants.SWITCH_ENUM: + case FastConstants.SWITCH_STRING: + int jumpOffset = ((BranchInstruction) instruction).GetJumpOffset(); + if ((jumpOffset < switchOffset) || (lastSwitchOffset < jumpOffset)) { + instructions.add(new FastInstruction(FastConstants.GOTO_BREAK, + lastSwitchOffset + 1, Instruction.UNKNOWN_LINE_NUMBER, null)); + } + break; + } + } + } + beforeListOffset = instruction.offset; + } + } + } + } + + // Create instruction + int branch = (breakOffset == -1) ? 1 : (breakOffset - lastSwitchOffset); + + list.set(switchIndex, new FastSwitch(switchOpcode, lastSwitchOffset, switchLineNumber, branch, test, pairs)); + } + + private static void AddLabels(List list, IntSet offsetLabelSet) { + for (int i = offsetLabelSet.size() - 1; i >= 0; --i) { + SearchInstructionAndAddLabel(list, offsetLabelSet.get(i)); + } + } + + /** + * @param list + * @param labelOffset + * @return false si aucune instruction ne correspond et true sinon. + */ + private static boolean SearchInstructionAndAddLabel(List list, int labelOffset) { + int index = InstructionUtil.getIndexForOffset(list, labelOffset); + + if (index < 0) + return false; + + boolean found = false; + Instruction instruction = list.get(index); + + switch (instruction.opcode) { + case FastConstants.INFINITE_LOOP: { + List instructions = ((FastList) instruction).instructions; + if (instructions != null) + found = SearchInstructionAndAddLabel(instructions, labelOffset); + } + break; + case FastConstants.WHILE: + case FastConstants.DO_WHILE: + case FastConstants.IF_: { + FastTestList ftl = (FastTestList) instruction; + if ((labelOffset >= ftl.test.offset) && (ftl.instructions != null)) + found = SearchInstructionAndAddLabel(ftl.instructions, labelOffset); + } + break; + case FastConstants.SYNCHRONIZED: { + FastSynchronized fs = (FastSynchronized) instruction; + if ((labelOffset >= fs.monitor.offset) && (fs.instructions != null)) + found = SearchInstructionAndAddLabel(fs.instructions, labelOffset); + } + break; + case FastConstants.FOR: { + FastFor ff = (FastFor) instruction; + if (((ff.init == null) || (labelOffset >= ff.init.offset)) && (ff.instructions != null)) + found = SearchInstructionAndAddLabel(ff.instructions, labelOffset); + } + break; + case FastConstants.IF_ELSE: { + FastTest2Lists ft2l = (FastTest2Lists) instruction; + if (labelOffset >= ft2l.test.offset) + found = SearchInstructionAndAddLabel(ft2l.instructions, labelOffset) + || SearchInstructionAndAddLabel(ft2l.instructions2, labelOffset); + } + break; + case FastConstants.SWITCH: + case FastConstants.SWITCH_ENUM: + case FastConstants.SWITCH_STRING: { + FastSwitch fs = (FastSwitch) instruction; + if (labelOffset >= fs.test.offset) { + FastSwitch.Pair[] pairs = fs.pairs; + if (pairs != null) + for (int i = pairs.length - 1; i >= 0 && !found; --i) { + List instructions = pairs[i].getInstructions(); + if (instructions != null) + found = SearchInstructionAndAddLabel(instructions, labelOffset); + } + } + } + break; + case FastConstants.TRY: { + FastTry ft = (FastTry) instruction; + found = SearchInstructionAndAddLabel(ft.instructions, labelOffset); + + if (!found && (ft.catches != null)) + for (int i = ft.catches.size() - 1; i >= 0 && !found; --i) { + found = SearchInstructionAndAddLabel(ft.catches.get(i).instructions, labelOffset); + } + + if (!found && (ft.finallyInstructions != null)) + found = SearchInstructionAndAddLabel(ft.finallyInstructions, labelOffset); + } + } + + if (!found) + list.set(index, new FastLabel(FastConstants.LABEL, labelOffset, instruction.lineNumber, instruction)); + + return true; + } +} \ No newline at end of file diff --git a/src/jd/core/process/analyzer/instruction/fast/ReturnLineNumberAnalyzer.java b/src/jd/core/process/analyzer/instruction/fast/ReturnLineNumberAnalyzer.java new file mode 100644 index 00000000..84d230d9 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/fast/ReturnLineNumberAnalyzer.java @@ -0,0 +1,136 @@ +package jd.core.process.analyzer.instruction.fast; + +import java.util.List; + +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.Return; +import jd.core.model.instruction.fast.FastConstants; +import jd.core.model.instruction.fast.instruction.FastList; +import jd.core.model.instruction.fast.instruction.FastSwitch; +import jd.core.model.instruction.fast.instruction.FastTest2Lists; +import jd.core.model.instruction.fast.instruction.FastTry; + + +/* + * Le numero de ligne des instructions 'return' genere par les compilateurs + * sont faux et perturbe l'affichage des sources + */ +public class ReturnLineNumberAnalyzer +{ + public static void Check(Method method) + { + List list = method.getFastNodes(); + int length = list.size(); + + if (length > 1) + { + int afterListLineNumber = list.get(length-1).lineNumber; + + if (afterListLineNumber != Instruction.UNKNOWN_LINE_NUMBER) + { + RecursiveCheck(list , afterListLineNumber); + } + } + } + + private static void RecursiveCheck( + List list, int afterListLineNumber) + { + int index = list.size(); + + // Appels recursifs + while (index-- > 0) + { + Instruction instruction = list.get(index); + + switch (instruction.opcode) + { + case FastConstants.WHILE: + case FastConstants.DO_WHILE: + case FastConstants.INFINITE_LOOP: + case FastConstants.FOR: + case FastConstants.FOREACH: + case FastConstants.IF_: + case FastConstants.SYNCHRONIZED: + { + List instructions = + ((FastList)instruction).instructions; + if (instructions != null) + RecursiveCheck(instructions, afterListLineNumber); + } + break; + case FastConstants.IF_ELSE: + { + FastTest2Lists ft2l = (FastTest2Lists)instruction; + RecursiveCheck(ft2l.instructions, afterListLineNumber); + RecursiveCheck(ft2l.instructions2, afterListLineNumber); + } + break; + case FastConstants.SWITCH: + case FastConstants.SWITCH_ENUM: + case FastConstants.SWITCH_STRING: + { + FastSwitch.Pair[] pairs = ((FastSwitch)instruction).pairs; + if (pairs != null) + for (int i=pairs.length-1; i>=0; --i) + { + List instructions = pairs[i].getInstructions(); + if (instructions != null) + { + RecursiveCheck(instructions, afterListLineNumber); + if (instructions.size() > 0) + { + afterListLineNumber = + instructions.get(0).lineNumber; + } + } + } + } + break; + case FastConstants.TRY: + { + FastTry ft = (FastTry)instruction; + + if (ft.finallyInstructions != null) + { + RecursiveCheck(ft.finallyInstructions, afterListLineNumber); + if (ft.finallyInstructions.size() > 0) + { + afterListLineNumber = + ft.finallyInstructions.get(0).lineNumber; + } + } + + if (ft.catches != null) + { + for (int i=ft.catches.size()-1; i>=0; --i) + { + List catchInstructions = + ft.catches.get(i).instructions; + RecursiveCheck( + catchInstructions, afterListLineNumber); + if (catchInstructions.size() > 0) + { + afterListLineNumber = + catchInstructions.get(0).lineNumber; + } + } + } + + RecursiveCheck(ft.instructions, afterListLineNumber); + } + break; + case FastConstants.RETURN: + { + Return r = (Return)instruction; + if (r.lineNumber > afterListLineNumber) + r.lineNumber = Instruction.UNKNOWN_LINE_NUMBER; + } + break; + } + + afterListLineNumber = instruction.lineNumber; + } + } +} diff --git a/src/jd/core/process/analyzer/instruction/fast/SingleDupLoadAnalyzer.java b/src/jd/core/process/analyzer/instruction/fast/SingleDupLoadAnalyzer.java new file mode 100644 index 00000000..d3e347b6 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/fast/SingleDupLoadAnalyzer.java @@ -0,0 +1,59 @@ +package jd.core.process.analyzer.instruction.fast; + +import java.util.List; + +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.DupStore; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.process.analyzer.classfile.visitor.ReplaceDupLoadVisitor; +import jd.core.process.analyzer.instruction.fast.visitor.CountDupLoadVisitor; + + +/** + * Efface les instructions DupStore si elles sont associ�es � une seule + * instruction DupLoad. + */ +public class SingleDupLoadAnalyzer +{ + public static void Cleanup(List list) + { + CountDupLoadVisitor countDupLoadVisitor = + new CountDupLoadVisitor(); + ReplaceDupLoadVisitor replaceDupLoadVisitor = + new ReplaceDupLoadVisitor(); + + int length = list.size(); + + // Effacement des instructions DupStore et DupLoad + for (int dupStoreIndex=0; dupStoreIndex= 2) + break; + } + + int counter = countDupLoadVisitor.getCounter(); + + if (counter < 2) + { + if (counter > 0) + { + replaceDupLoadVisitor.init(dupStore, dupStore.objectref); + for (int index=dupStoreIndex+1; index list) + { + int i = list.size(); + + if (i < 5) + return; + + i -= 4; + ConstantPool constants = classFile.getConstantPool(); + + while (i-- > 0) + { + Instruction instruction = list.get(i); + + if (instruction.opcode != ByteCodeConstants.DUPSTORE) + continue; + + DupStore ds = (DupStore)instruction; + + if (ds.objectref.opcode != ByteCodeConstants.GETSTATIC) + continue; + + GetStatic gs = (GetStatic)ds.objectref; + + ConstantFieldref cfr = constants.getConstantFieldref(gs.index); + + if (cfr.class_index != classFile.getThisClassIndex()) + continue; + + instruction = list.get(i+1); + + if (instruction.opcode != ByteCodeConstants.IFXNULL) + continue; + + IfInstruction ii = (IfInstruction)instruction; + + if ((ii.value.opcode != ByteCodeConstants.DUPLOAD) || + (ds.offset != ii.value.offset)) + continue; + + instruction = list.get(i+2); + + if (instruction.opcode != ByteCodeConstants.POP) + continue; + + Pop pop = (Pop)instruction; + + if ((pop.objectref.opcode != ByteCodeConstants.DUPLOAD) || + (ds.offset != pop.objectref.offset)) + continue; + + instruction = list.get(i+3); + + if (instruction.opcode != FastConstants.TRY) + continue; + + FastTry ft = (FastTry)instruction; + + if ((ft.finallyInstructions != null) || + (ft.instructions.size() != 1) || + (ft.catches.size() != 1)) + continue; + + List catchInstructions = + ft.catches.get(0).instructions; + + if ((catchInstructions.size() != 1) || + (catchInstructions.get(0).opcode != ByteCodeConstants.ATHROW)) + continue; + + instruction = ft.instructions.get(0); + + if (instruction.opcode != ByteCodeConstants.TERNARYOPSTORE) + continue; + + TernaryOpStore tos = (TernaryOpStore)instruction; + + if (tos.objectref.opcode != ByteCodeConstants.ASSIGNMENT) + continue; + + AssignmentInstruction ai = (AssignmentInstruction)tos.objectref; + + if (ai.value2.opcode != ByteCodeConstants.INVOKESTATIC) + continue; + + Invokestatic is = (Invokestatic)ai.value2; + + if (is.args.size() != 1) + continue; + + instruction = is.args.get(0); + + if (instruction.opcode != ByteCodeConstants.LDC) + continue; + + ConstantNameAndType cnatField = constants.getConstantNameAndType( + cfr.name_and_type_index); + + String signature = + constants.getConstantUtf8(cnatField.descriptor_index); + + if (! StringConstants.INTERNAL_CLASS_SIGNATURE.equals(signature)) + continue; + + String nameField = constants.getConstantUtf8(cnatField.name_index); + + if (! nameField.startsWith(StringConstants.CLASS_DOLLAR)) + continue; + + ConstantMethodref cmr = + constants.getConstantMethodref(is.index); + + String className = + constants.getConstantClassName(cmr.class_index); + + if (! className.equals(StringConstants.INTERNAL_CLASS_CLASS_NAME)) + continue; + + ConstantNameAndType cnatMethod = + constants.getConstantNameAndType(cmr.name_and_type_index); + String nameMethod = + constants.getConstantUtf8(cnatMethod.name_index); + + if (! nameMethod.equals(StringConstants.FORNAME_METHOD_NAME)) + continue; + + Ldc ldc = (Ldc)instruction; + ConstantValue cv = constants.getConstantValue(ldc.index); + + if (cv.tag != ConstantConstant.CONSTANT_String) + continue; + + // Trouve ! + ConstantString cs = (ConstantString)cv; + String dotClassName = constants.getConstantUtf8(cs.string_index); + String internalName = dotClassName.replace( + StringConstants.PACKAGE_SEPARATOR, + StringConstants.INTERNAL_PACKAGE_SEPARATOR); + + referenceMap.add(internalName); + + // Ajout du nom interne + int index = constants.addConstantUtf8(internalName); + // Ajout d'une nouvelle classe + index = constants.addConstantClass(index); + ldc = new Ldc( + ByteCodeConstants.LDC, ii.offset, + ii.lineNumber, index); + + // Remplacement de l'intruction GetStatic par l'instruction Ldc + ReplaceDupLoadVisitor visitor = new ReplaceDupLoadVisitor(ds, ldc); + + visitor.visit(list.get(i+4)); + + // Retrait de l'intruction FastTry + list.remove(i+3); + // Retrait de l'intruction Pop + list.remove(i+2); + // Retrait de l'intruction IfNotNull + list.remove(i+1); + // Retrait de l'intruction DupStore + list.remove(i); + + // Recherche de l'attribut statique et ajout de l'attribut SYNTHETIC + Field[] fields = classFile.getFields(); + int j = fields.length; + + while (j-- > 0) + { + Field field = fields[j]; + + if (field.name_index == cnatField.name_index) + { + field.access_flags |= ClassFileConstants.ACC_SYNTHETIC; + break; + } + } + } + } +} diff --git a/src/jd/core/process/analyzer/instruction/fast/reconstructor/DotClassEclipseReconstructor.java b/src/jd/core/process/analyzer/instruction/fast/reconstructor/DotClassEclipseReconstructor.java new file mode 100644 index 00000000..2f4730ef --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/fast/reconstructor/DotClassEclipseReconstructor.java @@ -0,0 +1,223 @@ +package jd.core.process.analyzer.instruction.fast.reconstructor; + +import java.util.List; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.ClassFileConstants; +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.Field; +import jd.core.model.classfile.constant.ConstantConstant; +import jd.core.model.classfile.constant.ConstantFieldref; +import jd.core.model.classfile.constant.ConstantMethodref; +import jd.core.model.classfile.constant.ConstantNameAndType; +import jd.core.model.classfile.constant.ConstantString; +import jd.core.model.classfile.constant.ConstantValue; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.DupStore; +import jd.core.model.instruction.bytecode.instruction.GetStatic; +import jd.core.model.instruction.bytecode.instruction.IfInstruction; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.Invokestatic; +import jd.core.model.instruction.bytecode.instruction.Ldc; +import jd.core.model.instruction.bytecode.instruction.PutStatic; +import jd.core.model.instruction.fast.FastConstants; +import jd.core.model.instruction.fast.instruction.FastTry; +import jd.core.model.instruction.fast.instruction.FastTry.FastCatch; +import jd.core.model.reference.ReferenceMap; +import jd.core.process.analyzer.classfile.visitor.ReplaceDupLoadVisitor; +import jd.core.util.StringConstants; + + +/* + * Recontruction du mot cle '.class' depuis les instructions generees par le + * compilateur d'Eclipse : + * ... + * ifnotnull( getstatic( current class, 'class$...', Class ) ) + * try + * { + * dupstore( invokestatic( 'Class', 'forName', nom de la classe ) ) + * putstatic( current class, 'class$...', Class, dupload ) + * } + * catch (Ljava/lang/ClassNotFoundException;) + * { + * athrow ... + * } + * ???( getstatic( class, 'class$...' ) ) + * ... + */ +public class DotClassEclipseReconstructor +{ + public static void Reconstruct( + ReferenceMap referenceMap, ClassFile classFile, List list) + { + int i = list.size(); + + if (i < 3) + return; + + i -= 2; + ConstantPool constants = classFile.getConstantPool(); + + while (i-- > 0) + { + Instruction instruction = list.get(i); + + if (instruction.opcode != FastConstants.IFXNULL) + continue; + + IfInstruction ii = (IfInstruction)instruction; + + if (ii.value.opcode != ByteCodeConstants.GETSTATIC) + continue; + + int jumpOffset = ii.GetJumpOffset(); + + instruction = list.get(i+1); + + if (instruction.opcode != FastConstants.TRY) + continue; + + FastTry ft = (FastTry)instruction; + + if ((ft.catches.size() != 1) || (ft.finallyInstructions != null) || + (ft.instructions.size() != 2)) + continue; + + FastCatch fc = ft.catches.get(0); + + if ((fc.instructions.size() != 1) || + (fc.otherExceptionTypeIndexes != null)) + continue; + + instruction = list.get(i+2); + + if ((ft.offset >= jumpOffset) || (jumpOffset > instruction.offset)) + continue; + + GetStatic gs = (GetStatic)ii.value; + + ConstantFieldref cfr = constants.getConstantFieldref(gs.index); + + if (cfr.class_index != classFile.getThisClassIndex()) + continue; + + ConstantNameAndType cnatField = constants.getConstantNameAndType( + cfr.name_and_type_index); + + String signature = + constants.getConstantUtf8(cnatField.descriptor_index); + + if (! StringConstants.INTERNAL_CLASS_SIGNATURE.equals(signature)) + continue; + + String name = constants.getConstantUtf8(cnatField.name_index); + + if (! name.startsWith(StringConstants.CLASS_DOLLAR)) + continue; + + instruction = ft.instructions.get(0); + + if (instruction.opcode != ByteCodeConstants.DUPSTORE) + continue; + + DupStore ds = (DupStore)instruction; + + if (ds.objectref.opcode != ByteCodeConstants.INVOKESTATIC) + continue; + + Invokestatic is = (Invokestatic)ds.objectref; + + if (is.args.size() != 1) + continue; + + instruction = is.args.get(0); + + if (instruction.opcode != ByteCodeConstants.LDC) + continue; + + ConstantMethodref cmr = + constants.getConstantMethodref(is.index); + + name = constants.getConstantClassName(cmr.class_index); + + if (! name.equals(StringConstants.INTERNAL_CLASS_CLASS_NAME)) + continue; + + ConstantNameAndType cnatMethod = + constants.getConstantNameAndType(cmr.name_and_type_index); + name = constants.getConstantUtf8(cnatMethod.name_index); + + if (! name.equals(StringConstants.FORNAME_METHOD_NAME)) + continue; + + Ldc ldc = (Ldc)instruction; + ConstantValue cv = constants.getConstantValue(ldc.index); + + if (cv.tag != ConstantConstant.CONSTANT_String) + continue; + + instruction = ft.instructions.get(1); + + if (instruction.opcode != ByteCodeConstants.PUTSTATIC) + continue; + + PutStatic ps = (PutStatic)instruction; + + if ((ps.index != gs.index) || + (ps.valueref.opcode != ByteCodeConstants.DUPLOAD) || + (ps.valueref.offset != ds.offset)) + continue; + + String exceptionName = + constants.getConstantClassName(fc.exceptionTypeIndex); + + if (! exceptionName.equals(StringConstants.INTERNAL_CLASSNOTFOUNDEXCEPTION_SIGNATURE)) + continue; + + if (fc.instructions.get(0).opcode != ByteCodeConstants.ATHROW) + continue; + + // Trouve ! + ConstantString cs = (ConstantString)cv; + String className = constants.getConstantUtf8(cs.string_index); + String internalName = className.replace( + StringConstants.PACKAGE_SEPARATOR, + StringConstants.INTERNAL_PACKAGE_SEPARATOR); + + referenceMap.add(internalName); + + // Ajout du nom interne + int index = constants.addConstantUtf8(internalName); + // Ajout d'une nouvelle classe + index = constants.addConstantClass(index); + ldc = new Ldc( + ByteCodeConstants.LDC, ii.offset, + ii.lineNumber, index); + + // Remplacement de l'intruction GetStatic par l'instruction Ldc + ReplaceDupLoadVisitor visitor = new ReplaceDupLoadVisitor(ds, ldc); + + visitor.visit(list.get(i+2)); + + // Retrait de l'intruction FastTry + list.remove(i+1); + // Retrait de l'intruction IfNotNull + list.remove(i); + + // Recherche de l'attribut statique et ajout de l'attribut SYNTHETIC + Field[] fields = classFile.getFields(); + int j = fields.length; + + while (j-- > 0) + { + Field field = fields[j]; + + if (field.name_index == cnatField.name_index) + { + field.access_flags |= ClassFileConstants.ACC_SYNTHETIC; + break; + } + } + } + } +} diff --git a/src/jd/core/process/analyzer/instruction/fast/reconstructor/EmptySynchronizedBlockReconstructor.java b/src/jd/core/process/analyzer/instruction/fast/reconstructor/EmptySynchronizedBlockReconstructor.java new file mode 100644 index 00000000..5ce25345 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/fast/reconstructor/EmptySynchronizedBlockReconstructor.java @@ -0,0 +1,84 @@ +package jd.core.process.analyzer.instruction.fast.reconstructor; + +import java.util.ArrayList; +import java.util.List; + +import jd.core.model.classfile.LocalVariables; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.AStore; +import jd.core.model.instruction.bytecode.instruction.DupStore; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.MonitorEnter; +import jd.core.model.instruction.fast.FastConstants; +import jd.core.model.instruction.fast.instruction.FastSynchronized; + + +public class EmptySynchronizedBlockReconstructor +{ + public static void Reconstruct( + LocalVariables localVariables, List list) + { + int index = list.size(); + + while (index-- > 2) + { + Instruction monitorExit = list.get(index); + + if (monitorExit.opcode != ByteCodeConstants.MONITOREXIT) + continue; + + Instruction instruction = list.get(index-1); + + if (instruction.opcode != ByteCodeConstants.MONITORENTER) + continue; + + MonitorEnter me = (MonitorEnter)instruction; + + if (me.objectref.opcode != ByteCodeConstants.DUPLOAD) + continue; + + DupStore dupStore; + instruction = list.get(index-2); + + if (instruction.opcode == ByteCodeConstants.DUPSTORE) + { + dupStore = (DupStore)instruction; + } + else if (instruction.opcode == ByteCodeConstants.ASTORE) + { + if (index <= 2) + continue; + + AStore astore = (AStore)instruction; + + instruction = list.get(index-3); + if (instruction.opcode != ByteCodeConstants.DUPSTORE) + continue; + + dupStore = (DupStore)instruction; + + // Remove local variable for monitor + localVariables.removeLocalVariableWithIndexAndOffset( + astore.index, astore.offset); + // Remove MonitorExit + list.remove(index--); + } + else + { + continue; + } + + FastSynchronized fastSynchronized = new FastSynchronized( + FastConstants.SYNCHRONIZED, monitorExit.offset, + instruction.lineNumber, 1, new ArrayList()); + fastSynchronized.monitor = dupStore.objectref; + + // Remove MonitorExit/MonitorEnter + list.remove(index--); + // Remove MonitorEnter/Astore + list.remove(index--); + // Replace DupStore with FastSynchronized + list.set(index, fastSynchronized); + } + } +} diff --git a/src/jd/core/process/analyzer/instruction/fast/reconstructor/IfGotoToIfReconstructor.java b/src/jd/core/process/analyzer/instruction/fast/reconstructor/IfGotoToIfReconstructor.java new file mode 100644 index 00000000..97fd6760 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/fast/reconstructor/IfGotoToIfReconstructor.java @@ -0,0 +1,67 @@ +package jd.core.process.analyzer.instruction.fast.reconstructor; + +import java.util.List; + +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.BranchInstruction; +import jd.core.model.instruction.bytecode.instruction.Goto; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.process.analyzer.instruction.bytecode.ComparisonInstructionAnalyzer; + + +/** + * Transformation de l'ensemble 'if-break' en simple 'if': + * + * 35: ifge +6 -> 41 + * 38: goto +56 -> 94 + * 41: ... + * + * to + * + * 35: ifLT +59 -> 94 + * 41: ... + * + */ +public class IfGotoToIfReconstructor +{ + public static void Reconstruct(List list) + { + int length = list.size(); + if (length < 3) + return; + + int index = length-2; + + while (index-- > 0) + { + Instruction i = list.get(index); + + switch (i.opcode) + { + case ByteCodeConstants.IF: + case ByteCodeConstants.IFCMP: + case ByteCodeConstants.IFXNULL: + case ByteCodeConstants.COMPLEXIF: + BranchInstruction bi = (BranchInstruction)i; + + i = list.get(index+1); + if (i.opcode != ByteCodeConstants.GOTO) + continue; + + Goto g = (Goto)i; + + i = list.get(index+2); + int jumpOffset = bi.GetJumpOffset(); + + if ((jumpOffset <= g.offset) || (i.offset < jumpOffset)) + continue; + + // Setup BranchInstruction + bi.branch = g.GetJumpOffset() - bi.offset; + ComparisonInstructionAnalyzer.InverseComparison(bi); + // Delete Goto + list.remove(index+1); + } + } + } +} \ No newline at end of file diff --git a/src/jd/core/process/analyzer/instruction/fast/reconstructor/InitArrayInstructionReconstructor.java b/src/jd/core/process/analyzer/instruction/fast/reconstructor/InitArrayInstructionReconstructor.java new file mode 100644 index 00000000..0d41ad02 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/fast/reconstructor/InitArrayInstructionReconstructor.java @@ -0,0 +1,196 @@ +package jd.core.process.analyzer.instruction.fast.reconstructor; + +import java.util.ArrayList; +import java.util.List; + +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.ArrayStoreInstruction; +import jd.core.model.instruction.bytecode.instruction.BIPush; +import jd.core.model.instruction.bytecode.instruction.DupStore; +import jd.core.model.instruction.bytecode.instruction.IConst; +import jd.core.model.instruction.bytecode.instruction.InitArrayInstruction; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.NewArray; +import jd.core.model.instruction.bytecode.instruction.SIPush; +import jd.core.process.analyzer.util.ReconstructorUtil; + + +/* + * Recontruction des initialisation de tableaux depuis le motif : + * DupStore0 ( NewArray | ANewArray ... ) + * ?AStore ( DupLoad0, index=0, value ) + * DupStore1 ( DupLoad0 ) + * ?AStore ( DupLoad1, index=1, value ) + * DupStore2 ( DupLoad1 ) + * ?AStore ( DupLoad2, index=2, value ) + * ... + * ???( DupLoadN ) + * + * Cette operation doit etre executee avant 'AssignmentInstructionReconstructor'. + */ +public class InitArrayInstructionReconstructor +{ + public static void Reconstruct(List list) + { + for (int index=list.size()-1; index>=0; --index) + { + Instruction i = list.get(index); + + if (i.opcode != ByteCodeConstants.DUPSTORE) + continue; + + DupStore dupStore = (DupStore)i; + int opcode = dupStore.objectref.opcode; + + if ((opcode != ByteCodeConstants.NEWARRAY) && + (opcode != ByteCodeConstants.ANEWARRAY)) + continue; + + ReconstructAInstruction(list, index, dupStore); + } + } + + private static void ReconstructAInstruction( + List list, int index, DupStore dupStore) + { + // 1er DupStore trouv� + final int length = list.size(); + int firstDupStoreIndex = index; + DupStore lastDupStore = dupStore; + ArrayStoreInstruction lastAsi = null; + int arrayIndex = 0; + List values = new ArrayList(); + + while (++index < length) + { + Instruction i = list.get(index); + + // Recherche de ?AStore ( DupLoad, index, value ) + if ((i.opcode != ByteCodeConstants.AASTORE) && + (i.opcode != ByteCodeConstants.ARRAYSTORE)) + break; + + ArrayStoreInstruction asi = (ArrayStoreInstruction)i; + + if ((asi.arrayref.opcode != ByteCodeConstants.DUPLOAD) || + (asi.arrayref.offset != lastDupStore.offset)) + break; + + lastAsi = asi; + + // Si les premieres cases d'un tableau ont pour valeur 0, elles + // ne sont pas initialisee ! La boucle suivante reconstruit + // l'initialisation des valeurs 0. + int indexOfArrayStoreInstruction = getArrayIndex(asi.indexref); + while (indexOfArrayStoreInstruction > arrayIndex) + { + values.add(new IConst( + ByteCodeConstants.ICONST, asi.offset, asi.lineNumber, 0)); + arrayIndex++; + } + + values.add(asi.valueref); + arrayIndex++; + + // Recherche de DupStoreM( DupLoadN ) + if (++index >= length) + break; + + i = list.get(index); + + if (i.opcode != ByteCodeConstants.DUPSTORE) + break; + + DupStore nextDupStore = (DupStore)i; + + if ((nextDupStore.objectref.opcode != ByteCodeConstants.DUPLOAD) || + (nextDupStore.objectref.offset != lastDupStore.offset)) + break; + + lastDupStore = nextDupStore; + } + + if (lastAsi != null) + { + // Instanciation d'une instruction InitArrayInstruction + InitArrayInstruction iai = new InitArrayInstruction( + ByteCodeConstants.NEWANDINITARRAY, lastAsi.offset, + dupStore.lineNumber, dupStore.objectref, values); + + // Recherche de l'instruction 'DupLoad' suivante + Instruction parent = ReconstructorUtil.ReplaceDupLoad( + list, index, lastDupStore, iai); + + if (parent != null) + switch (parent.opcode) + { + case ByteCodeConstants.AASTORE: + iai.opcode = ByteCodeConstants.INITARRAY; + } + + // Retrait des instructions de la liste + while (firstDupStoreIndex < index) + list.remove(--index); + + // Initialisation des types de constantes entieres + if (iai.newArray.opcode == ByteCodeConstants.NEWARRAY) + { + NewArray na = (NewArray)iai.newArray; + + switch (na.type) + { + case ByteCodeConstants.T_BOOLEAN: + SetContantTypes("Z", iai.values); + break; + case ByteCodeConstants.T_CHAR: + SetContantTypes("C", iai.values); + break; + case ByteCodeConstants.T_BYTE: + SetContantTypes("B", iai.values); + break; + case ByteCodeConstants.T_SHORT: + SetContantTypes("S", iai.values); + break; + case ByteCodeConstants.T_INT: + SetContantTypes("I", iai.values); + break; + } + } + } + } + + private static void SetContantTypes( + String signature, List values) + { + final int length = values.size(); + + for (int i=0; i list) + { + for (int dupStoreIndex=0; dupStoreIndex list) + { + for (int index=list.size()-1; index>=0; --index) + { + if (list.get(index).opcode != ByteCodeConstants.XRETURN) + continue; + + ReturnInstruction ri1 = (ReturnInstruction)list.get(index); + int opcode = ri1.valueref.opcode; + + if ((opcode != ByteCodeConstants.SIPUSH) && + (opcode != ByteCodeConstants.BIPUSH) && + (opcode != ByteCodeConstants.ICONST)) + continue; + + IConst iConst1 = (IConst)ri1.valueref; + + if (!"Z".equals(iConst1.signature)) + continue; + + if (index <= 0) + continue; + + int index2 = index - 1; + + if (list.get(index2).opcode != ByteCodeConstants.XRETURN) + continue; + + ReturnInstruction ri2 = (ReturnInstruction)list.get(index2); + + if ((ri1.lineNumber != Instruction.UNKNOWN_LINE_NUMBER) && + (ri1.lineNumber > ri2.lineNumber)) + continue; + + opcode = ri2.valueref.opcode; + + if ((opcode != ByteCodeConstants.SIPUSH) && + (opcode != ByteCodeConstants.BIPUSH) && + (opcode != ByteCodeConstants.ICONST)) + continue; + + IConst iConst2 = (IConst)ri2.valueref; + + if (!"Z".equals(iConst2.signature)) + continue; + + if (index2 <= 0) + continue; + + Instruction instruction = list.get(--index2); + + opcode = instruction.opcode; + + if ((opcode != ByteCodeConstants.IF) && + (opcode != ByteCodeConstants.IFCMP) && + (opcode != ByteCodeConstants.IFXNULL) && + (opcode != ByteCodeConstants.COMPLEXIF)) + continue; + + BranchInstruction bi = (BranchInstruction)instruction; + int offset = bi.GetJumpOffset(); + + if ((ri2.offset >= offset) || (offset > ri1.offset)) + continue; + + // Verification qu'aucune instruction saute sur 'ri1' + boolean found = false; + int i = index2; + + while (i-- > 0) + { + instruction = list.get(i); + opcode = instruction.opcode; + + if (opcode == ByteCodeConstants.GOTO) + { + int jumpOffset = ((Goto)instruction).GetJumpOffset(); + if ((ri2.offset < jumpOffset) && (jumpOffset <= ri1.offset)) + { + found = true; + break; + } + } + else if ((opcode == ByteCodeConstants.IF) || + (opcode == ByteCodeConstants.IFCMP) || + (opcode == ByteCodeConstants.IFXNULL) || + (opcode == ByteCodeConstants.COMPLEXIF)) + { + int jumpOffset = + ((BranchInstruction)instruction).GetJumpOffset(); + if ((ri2.offset < jumpOffset) && (jumpOffset <= ri1.offset)) + { + found = true; + break; + } + } + } + + if (found == true) + continue; + + if (iConst2.value == 1) + ComparisonInstructionAnalyzer.InverseComparison( bi ); + + list.remove(index); + list.remove(index2); + + ri2.valueref = bi; + + index -= 3; + } + } +} diff --git a/src/jd/core/process/analyzer/instruction/fast/reconstructor/TernaryOpReconstructor.java b/src/jd/core/process/analyzer/instruction/fast/reconstructor/TernaryOpReconstructor.java new file mode 100644 index 00000000..9115eb77 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/fast/reconstructor/TernaryOpReconstructor.java @@ -0,0 +1,125 @@ +package jd.core.process.analyzer.instruction.fast.reconstructor; + +import java.util.List; + +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.BranchInstruction; +import jd.core.model.instruction.bytecode.instruction.IConst; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.TernaryOpStore; +import jd.core.model.instruction.bytecode.instruction.TernaryOperator; +import jd.core.process.analyzer.instruction.bytecode.ComparisonInstructionAnalyzer; +import jd.core.process.analyzer.instruction.fast.visitor.ReplaceInstructionVisitor; + + +/* + * Reconstruction des operateurs ternaires. + * Contenu de la liste d'instructions : + * offset-1) If instruction (IF || IFCMP || IFXNULL || COMPLEXIF) + * offset) TernaryOpStore + * offset+1) Goto + */ +public class TernaryOpReconstructor +{ + public static void Reconstruct(List list) + { + int length = list.size(); + + for (int index=1; index 0) + { + Instruction instruction = list.get(indexTest); + int opcode = instruction.opcode; + + if ((opcode == ByteCodeConstants.IF) || + (opcode == ByteCodeConstants.IFCMP) || + (opcode == ByteCodeConstants.IFXNULL) || + (opcode == ByteCodeConstants.COMPLEXIF)) + { + int jumpOffset = + ((BranchInstruction)instruction).GetJumpOffset(); + if ((gi.offset < jumpOffset) && + (jumpOffset <= afterGi.offset)) + { + test = instruction; + break; + } + } + } + + if (test == null) + continue; + + TernaryOpStore value1 = (TernaryOpStore)i; + + ComparisonInstructionAnalyzer.InverseComparison(test); + + TernaryOperator fto = new TernaryOperator( + ByteCodeConstants.TERNARYOP, + value1.ternaryOp2ndValueOffset, test.lineNumber, + test, value1.objectref, null); + + ReplaceInstructionVisitor visitor = + new ReplaceInstructionVisitor( + value1.ternaryOp2ndValueOffset, fto); + + int indexVisitor = index+2; + while ((indexVisitor branchList = + ((ComplexConditionalBranchInstruction)instruction).instructions; + for (int i=branchList.size()-1; i>=0; --i) + { + if (Visit(localVariables, maxOffset, branchList.get(i))) + return true; + } + return false; + } + case ByteCodeConstants.INSTANCEOF: + return Visit( + localVariables, maxOffset, ((InstanceOf)instruction).objectref); + case ByteCodeConstants.INVOKEINTERFACE: + case ByteCodeConstants.INVOKESPECIAL: + case ByteCodeConstants.INVOKEVIRTUAL: + if (Visit( + localVariables, maxOffset, + ((InvokeNoStaticInstruction)instruction).objectref)) + return true; + case ByteCodeConstants.INVOKESTATIC: + { + List list = ((InvokeInstruction)instruction).args; + for (int i=list.size()-1; i>=0; --i) + { + if (Visit(localVariables, maxOffset, list.get(i))) + return true; + } + return false; + } + case ByteCodeConstants.INVOKENEW: + { + List list = ((InvokeNew)instruction).args; + for (int i=list.size()-1; i>=0; --i) + { + if (Visit(localVariables, maxOffset, list.get(i))) + return true; + } + return false; + } + case ByteCodeConstants.LOOKUPSWITCH: + return Visit( + localVariables, maxOffset, ((LookupSwitch)instruction).key); + case ByteCodeConstants.MONITORENTER: + return Visit( + localVariables, maxOffset, + ((MonitorEnter)instruction).objectref); + case ByteCodeConstants.MONITOREXIT: + return Visit( + localVariables, maxOffset, + ((MonitorExit)instruction).objectref); + case ByteCodeConstants.MULTIANEWARRAY: + { + Instruction[] dimensions = ((MultiANewArray)instruction).dimensions; + for (int i=dimensions.length-1; i>=0; --i) + { + if (Visit(localVariables, maxOffset, dimensions[i])) + return true; + } + return false; + } + case ByteCodeConstants.NEWARRAY: + return Visit( + localVariables, maxOffset, + ((NewArray)instruction).dimension); + case ByteCodeConstants.ANEWARRAY: + return Visit( + localVariables, maxOffset, + ((ANewArray)instruction).dimension); + case ByteCodeConstants.POP: + return Visit( + localVariables, maxOffset, + ((Pop)instruction).objectref); + case ByteCodeConstants.PUTFIELD: + { + PutField putField = (PutField)instruction; + if (Visit(localVariables, maxOffset, putField.objectref)) + return true; + return Visit(localVariables, maxOffset, putField.valueref); + } + case ByteCodeConstants.PUTSTATIC: + return Visit( + localVariables, maxOffset, + ((PutStatic)instruction).valueref); + case ByteCodeConstants.XRETURN: + return Visit( + localVariables, maxOffset, + ((ReturnInstruction)instruction).valueref); + case ByteCodeConstants.TABLESWITCH: + return Visit( + localVariables, maxOffset, + ((TableSwitch)instruction).key); + case ByteCodeConstants.TERNARYOPSTORE: + return Visit( + localVariables, maxOffset, + ((TernaryOpStore)instruction).objectref); + case ByteCodeConstants.TERNARYOP: + { + TernaryOperator to = (TernaryOperator)instruction; + if (Visit(localVariables, maxOffset, to.value1)) + return true; + return Visit(localVariables, maxOffset, to.value2); + } + case ByteCodeConstants.ASSIGNMENT: + { + AssignmentInstruction ai = (AssignmentInstruction)instruction; + if (Visit(localVariables, maxOffset, ai.value1)) + return true; + return Visit(localVariables, maxOffset, ai.value2); + } + case ByteCodeConstants.ARRAYLOAD: + { + ArrayLoadInstruction ali = (ArrayLoadInstruction)instruction; + if (Visit(localVariables, maxOffset, ali.arrayref)) + return true; + return Visit(localVariables, maxOffset, ali.indexref); + } + case ByteCodeConstants.PREINC: + case ByteCodeConstants.POSTINC: + return Visit( + localVariables, maxOffset, + ((IncInstruction)instruction).value); + case ByteCodeConstants.GETFIELD: + return Visit( + localVariables, maxOffset, + ((GetField)instruction).objectref); + case ByteCodeConstants.INITARRAY: + case ByteCodeConstants.NEWANDINITARRAY: + { + InitArrayInstruction iai = (InitArrayInstruction)instruction; + if (Visit(localVariables, maxOffset, iai.newArray)) + return true; + if (iai.values != null) + if (visit(localVariables, maxOffset, iai.values)) + return true; + return false; + } + case FastConstants.FOR: + { + FastFor ff = (FastFor)instruction; + if (ff.init != null) + if (Visit(localVariables, maxOffset, ff.init)) + return true; + if (ff.inc != null) + if (Visit(localVariables, maxOffset, ff.inc)) + return true; + return false; + } + case FastConstants.WHILE: + case FastConstants.DO_WHILE: + case FastConstants.IF_: + { + Instruction test = ((FastTestList)instruction).test; + if (test != null) + if (Visit(localVariables, maxOffset, test)) + return true; + return false; + } + case FastConstants.INFINITE_LOOP: + { + List instructions = + ((FastList)instruction).instructions; + if (instructions != null) + return visit(localVariables, maxOffset, instructions); + return false; + } + case FastConstants.FOREACH: + { + FastForEach ffe = (FastForEach)instruction; + if (Visit(localVariables, maxOffset, ffe.variable)) + return true; + if (Visit(localVariables, maxOffset, ffe.values)) + return true; + return visit(localVariables, maxOffset, ffe.instructions); + } + case FastConstants.IF_ELSE: + { + FastTest2Lists ft2l = (FastTest2Lists)instruction; + if (Visit(localVariables, maxOffset, ft2l.test)) + return true; + if (visit(localVariables, maxOffset, ft2l.instructions)) + return true; + return visit(localVariables, maxOffset, ft2l.instructions2); + } + case FastConstants.IF_CONTINUE: + case FastConstants.IF_BREAK: + case FastConstants.IF_LABELED_BREAK: + case FastConstants.GOTO_CONTINUE: + case FastConstants.GOTO_BREAK: + case FastConstants.GOTO_LABELED_BREAK: + { + FastInstruction fi = (FastInstruction)instruction; + if (fi.instruction != null) + if (Visit(localVariables, maxOffset, fi.instruction)) + return true; + return false; + } + case FastConstants.SWITCH: + case FastConstants.SWITCH_ENUM: + case FastConstants.SWITCH_STRING: + { + FastSwitch fs = (FastSwitch)instruction; + if (Visit(localVariables, maxOffset, fs.test)) + return true; + FastSwitch.Pair[] pairs = fs.pairs; + for (int i=pairs.length-1; i>=0; --i) + { + List instructions = pairs[i].getInstructions(); + if (instructions != null) + if (visit(localVariables, maxOffset, instructions)) + return true; + } + return false; + } + case FastConstants.TRY: + { + FastTry ft = (FastTry)instruction; + if (visit(localVariables, maxOffset, ft.instructions)) + return true; + if (ft.finallyInstructions != null) + if (visit(localVariables, maxOffset, ft.finallyInstructions)) + return true; + List catchs = ft.catches; + for (int i=catchs.size()-1; i>=0; --i) + if (visit(localVariables, maxOffset, catchs.get(i).instructions)) + return true; + return false; + } + case FastConstants.SYNCHRONIZED: + { + FastSynchronized fsd = (FastSynchronized)instruction; + if (Visit(localVariables, maxOffset, fsd.monitor)) + return true; + return visit(localVariables, maxOffset, fsd.instructions); + } + case FastConstants.LABEL: + { + FastLabel fl = (FastLabel)instruction; + if (fl.instruction != null) + if (Visit(localVariables, maxOffset, fl.instruction)) + return true; + return false; + } + case FastConstants.DECLARE: + { + FastDeclaration fd = (FastDeclaration)instruction; + if (fd.instruction != null) + if (Visit(localVariables, maxOffset, fd.instruction)) + return true; + return false; + } + case ByteCodeConstants.GETSTATIC: + case ByteCodeConstants.OUTERTHIS: + case ByteCodeConstants.ACONST_NULL: + case ByteCodeConstants.BIPUSH: + case ByteCodeConstants.ICONST: + case ByteCodeConstants.LCONST: + case ByteCodeConstants.FCONST: + case ByteCodeConstants.DCONST: + case ByteCodeConstants.GOTO: + case ByteCodeConstants.IINC: + case ByteCodeConstants.JSR: + case ByteCodeConstants.LDC: + case ByteCodeConstants.LDC2_W: + case ByteCodeConstants.NEW: + case ByteCodeConstants.NOP: + case ByteCodeConstants.SIPUSH: + case ByteCodeConstants.RET: + case ByteCodeConstants.RETURN: + case ByteCodeConstants.EXCEPTIONLOAD: + case ByteCodeConstants.RETURNADDRESSLOAD: + case ByteCodeConstants.DUPLOAD: + return false; + default: + System.err.println( + "Can not find local variable used in " + + instruction.getClass().getName() + + ", opcode=" + instruction.opcode); + return false; + } + } + + private static boolean visit( + LocalVariables localVariables, int maxOffset, + List instructions) + { + for (int i=instructions.size()-1; i>=0; --i) + if (Visit(localVariables, maxOffset, instructions.get(i))) + return true; + return false; + } +} diff --git a/src/jd/core/process/analyzer/instruction/fast/visitor/CountDupLoadVisitor.java b/src/jd/core/process/analyzer/instruction/fast/visitor/CountDupLoadVisitor.java new file mode 100644 index 00000000..69f50fe1 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/fast/visitor/CountDupLoadVisitor.java @@ -0,0 +1,396 @@ +package jd.core.process.analyzer.instruction.fast.visitor; + +import java.util.List; + +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.ANewArray; +import jd.core.model.instruction.bytecode.instruction.AThrow; +import jd.core.model.instruction.bytecode.instruction.ArrayLength; +import jd.core.model.instruction.bytecode.instruction.ArrayLoadInstruction; +import jd.core.model.instruction.bytecode.instruction.ArrayStoreInstruction; +import jd.core.model.instruction.bytecode.instruction.AssignmentInstruction; +import jd.core.model.instruction.bytecode.instruction.BinaryOperatorInstruction; +import jd.core.model.instruction.bytecode.instruction.CheckCast; +import jd.core.model.instruction.bytecode.instruction.ComplexConditionalBranchInstruction; +import jd.core.model.instruction.bytecode.instruction.ConvertInstruction; +import jd.core.model.instruction.bytecode.instruction.DupLoad; +import jd.core.model.instruction.bytecode.instruction.DupStore; +import jd.core.model.instruction.bytecode.instruction.GetField; +import jd.core.model.instruction.bytecode.instruction.IfCmp; +import jd.core.model.instruction.bytecode.instruction.IfInstruction; +import jd.core.model.instruction.bytecode.instruction.IncInstruction; +import jd.core.model.instruction.bytecode.instruction.InitArrayInstruction; +import jd.core.model.instruction.bytecode.instruction.InstanceOf; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.InvokeInstruction; +import jd.core.model.instruction.bytecode.instruction.InvokeNew; +import jd.core.model.instruction.bytecode.instruction.InvokeNoStaticInstruction; +import jd.core.model.instruction.bytecode.instruction.LookupSwitch; +import jd.core.model.instruction.bytecode.instruction.MonitorEnter; +import jd.core.model.instruction.bytecode.instruction.MonitorExit; +import jd.core.model.instruction.bytecode.instruction.MultiANewArray; +import jd.core.model.instruction.bytecode.instruction.NewArray; +import jd.core.model.instruction.bytecode.instruction.Pop; +import jd.core.model.instruction.bytecode.instruction.PutField; +import jd.core.model.instruction.bytecode.instruction.PutStatic; +import jd.core.model.instruction.bytecode.instruction.ReturnInstruction; +import jd.core.model.instruction.bytecode.instruction.StoreInstruction; +import jd.core.model.instruction.bytecode.instruction.TableSwitch; +import jd.core.model.instruction.bytecode.instruction.TernaryOpStore; +import jd.core.model.instruction.bytecode.instruction.TernaryOperator; +import jd.core.model.instruction.bytecode.instruction.UnaryOperatorInstruction; +import jd.core.model.instruction.fast.FastConstants; +import jd.core.model.instruction.fast.instruction.FastDeclaration; +import jd.core.model.instruction.fast.instruction.FastFor; +import jd.core.model.instruction.fast.instruction.FastForEach; +import jd.core.model.instruction.fast.instruction.FastInstruction; +import jd.core.model.instruction.fast.instruction.FastLabel; +import jd.core.model.instruction.fast.instruction.FastList; +import jd.core.model.instruction.fast.instruction.FastSwitch; +import jd.core.model.instruction.fast.instruction.FastSynchronized; +import jd.core.model.instruction.fast.instruction.FastTest2Lists; +import jd.core.model.instruction.fast.instruction.FastTestList; +import jd.core.model.instruction.fast.instruction.FastTry; +import jd.core.model.instruction.fast.instruction.FastTry.FastCatch; + + +public class CountDupLoadVisitor +{ + private DupStore dupStore; + private int counter; + + public CountDupLoadVisitor() + { + init(null); + } + + public void init(DupStore dupStore) + { + this.dupStore = dupStore; + this.counter = 0; + } + + public void visit(Instruction instruction) + { + switch (instruction.opcode) + { + case ByteCodeConstants.ARRAYLENGTH: + visit(((ArrayLength)instruction).arrayref); + break; + case ByteCodeConstants.AASTORE: + case ByteCodeConstants.ARRAYSTORE: + { + ArrayStoreInstruction asi = (ArrayStoreInstruction)instruction; + visit(asi.arrayref); + visit(asi.indexref); + visit(asi.valueref); + } + break; + case ByteCodeConstants.ATHROW: + visit(((AThrow)instruction).value); + break; + case ByteCodeConstants.UNARYOP: + visit(((UnaryOperatorInstruction)instruction).value); + break; + case ByteCodeConstants.BINARYOP: + { + BinaryOperatorInstruction boi = (BinaryOperatorInstruction)instruction; + visit(boi.value1); + visit(boi.value2); + } + break; + case ByteCodeConstants.CHECKCAST: + visit(((CheckCast)instruction).objectref); + break; + case ByteCodeConstants.STORE: + case ByteCodeConstants.ASTORE: + case ByteCodeConstants.ISTORE: + visit(((StoreInstruction)instruction).valueref); + break; + case ByteCodeConstants.DUPSTORE: + visit(((DupStore)instruction).objectref); + break; + case ByteCodeConstants.CONVERT: + case ByteCodeConstants.IMPLICITCONVERT: + visit(((ConvertInstruction)instruction).value); + break; + case ByteCodeConstants.IFCMP: + { + IfCmp ifCmp = (IfCmp)instruction; + visit(ifCmp.value1); + visit(ifCmp.value2); + } + break; + case ByteCodeConstants.IF: + case ByteCodeConstants.IFXNULL: + visit(((IfInstruction)instruction).value); + break; + case ByteCodeConstants.COMPLEXIF: + { + List branchList = + ((ComplexConditionalBranchInstruction)instruction).instructions; + for (int i=branchList.size()-1; i>=0; --i) + { + visit(branchList.get(i)); + } + } + break; + case ByteCodeConstants.INSTANCEOF: + visit(((InstanceOf)instruction).objectref); + break; + case ByteCodeConstants.INVOKEINTERFACE: + case ByteCodeConstants.INVOKESPECIAL: + case ByteCodeConstants.INVOKEVIRTUAL: + visit(((InvokeNoStaticInstruction)instruction).objectref); + case ByteCodeConstants.INVOKESTATIC: + { + List list = ((InvokeInstruction)instruction).args; + for (int i=list.size()-1; i>=0; --i) + { + visit(list.get(i)); + } + } + break; + case ByteCodeConstants.INVOKENEW: + { + List list = ((InvokeNew)instruction).args; + for (int i=list.size()-1; i>=0; --i) + { + visit(list.get(i)); + } + } + break; + case ByteCodeConstants.LOOKUPSWITCH: + visit(((LookupSwitch)instruction).key); + break; + case ByteCodeConstants.MONITORENTER: + visit(((MonitorEnter)instruction).objectref); + break; + case ByteCodeConstants.MONITOREXIT: + visit(((MonitorExit)instruction).objectref); + break; + case ByteCodeConstants.MULTIANEWARRAY: + { + Instruction[] dimensions = ((MultiANewArray)instruction).dimensions; + for (int i=dimensions.length-1; i>=0; --i) + { + visit(dimensions[i]); + } + } + break; + case ByteCodeConstants.NEWARRAY: + visit(((NewArray)instruction).dimension); + break; + case ByteCodeConstants.ANEWARRAY: + visit(((ANewArray)instruction).dimension); + break; + case ByteCodeConstants.POP: + visit(((Pop)instruction).objectref); + break; + case ByteCodeConstants.PUTFIELD: + { + PutField putField = (PutField)instruction; + visit(putField.objectref); + visit(putField.valueref); + } + break; + case ByteCodeConstants.PUTSTATIC: + visit(((PutStatic)instruction).valueref); + break; + case ByteCodeConstants.XRETURN: + visit(((ReturnInstruction)instruction).valueref); + break; + case ByteCodeConstants.TABLESWITCH: + visit(((TableSwitch)instruction).key); + break; + case ByteCodeConstants.TERNARYOPSTORE: + visit(((TernaryOpStore)instruction).objectref); + break; + case ByteCodeConstants.TERNARYOP: + { + TernaryOperator to = (TernaryOperator)instruction; + visit(to.value1); + visit(to.value2); + } + break; + case ByteCodeConstants.ASSIGNMENT: + { + AssignmentInstruction ai = (AssignmentInstruction)instruction; + visit(ai.value1); + visit(ai.value2); + } + break; + case ByteCodeConstants.ARRAYLOAD: + { + ArrayLoadInstruction ali = (ArrayLoadInstruction)instruction; + visit(ali.arrayref); + visit(ali.indexref); + } + break; + case ByteCodeConstants.PREINC: + case ByteCodeConstants.POSTINC: + visit(((IncInstruction)instruction).value); + break; + case ByteCodeConstants.GETFIELD: + visit(((GetField)instruction).objectref); + break; + case ByteCodeConstants.DUPLOAD: + { + if (((DupLoad)instruction).dupStore == this.dupStore) + this.counter++; + } + break; + case ByteCodeConstants.INITARRAY: + case ByteCodeConstants.NEWANDINITARRAY: + { + InitArrayInstruction iai = (InitArrayInstruction)instruction; + visit(iai.newArray); + if (iai.values != null) + visit(iai.values); + } + break; + case FastConstants.FOR: + { + FastFor ff = (FastFor)instruction; + if (ff.init != null) + visit(ff.init); + if (ff.inc != null) + visit(ff.inc); + } + case FastConstants.WHILE: + case FastConstants.DO_WHILE: + case FastConstants.IF_: + { + Instruction test = ((FastTestList)instruction).test; + if (test != null) + visit(test); + } + case FastConstants.INFINITE_LOOP: + { + List instructions = + ((FastList)instruction).instructions; + if (instructions != null) + visit(instructions); + } + break; + case FastConstants.FOREACH: + { + FastForEach ffe = (FastForEach)instruction; + visit(ffe.variable); + visit(ffe.values); + visit(ffe.instructions); + } + break; + case FastConstants.IF_ELSE: + { + FastTest2Lists ft2l = (FastTest2Lists)instruction; + visit(ft2l.test); + visit(ft2l.instructions); + visit(ft2l.instructions2); + } + break; + case FastConstants.IF_CONTINUE: + case FastConstants.IF_BREAK: + case FastConstants.IF_LABELED_BREAK: + case FastConstants.GOTO_CONTINUE: + case FastConstants.GOTO_BREAK: + case FastConstants.GOTO_LABELED_BREAK: + { + FastInstruction fi = (FastInstruction)instruction; + if (fi.instruction != null) + visit(fi.instruction); + } + break; + case FastConstants.SWITCH: + case FastConstants.SWITCH_ENUM: + case FastConstants.SWITCH_STRING: + { + FastSwitch fs = (FastSwitch)instruction; + visit(fs.test); + FastSwitch.Pair[] pairs = fs.pairs; + for (int i=pairs.length-1; i>=0; --i) + { + List instructions = pairs[i].getInstructions(); + if (instructions != null) + visit(instructions); + } + } + break; + case FastConstants.TRY: + { + FastTry ft = (FastTry)instruction; + visit(ft.instructions); + if (ft.finallyInstructions != null) + visit(ft.finallyInstructions); + List catchs = ft.catches; + for (int i=catchs.size()-1; i>=0; --i) + visit(catchs.get(i).instructions); + } + break; + case FastConstants.SYNCHRONIZED: + { + FastSynchronized fsd = (FastSynchronized)instruction; + visit(fsd.monitor); + visit(fsd.instructions); + } + break; + case FastConstants.LABEL: + { + FastLabel fl = (FastLabel)instruction; + if (fl.instruction != null) + visit(fl.instruction); + } + break; + case FastConstants.DECLARE: + { + FastDeclaration fd = (FastDeclaration)instruction; + if (fd.instruction != null) + visit(fd.instruction); + } + break; + case ByteCodeConstants.GETSTATIC: + case ByteCodeConstants.OUTERTHIS: + case ByteCodeConstants.ACONST_NULL: + case ByteCodeConstants.LOAD: + case ByteCodeConstants.ALOAD: + case ByteCodeConstants.ILOAD: + case ByteCodeConstants.BIPUSH: + case ByteCodeConstants.ICONST: + case ByteCodeConstants.LCONST: + case ByteCodeConstants.FCONST: + case ByteCodeConstants.DCONST: + case ByteCodeConstants.GOTO: + case ByteCodeConstants.IINC: + case ByteCodeConstants.JSR: + case ByteCodeConstants.LDC: + case ByteCodeConstants.LDC2_W: + case ByteCodeConstants.NEW: + case ByteCodeConstants.NOP: + case ByteCodeConstants.SIPUSH: + case ByteCodeConstants.RET: + case ByteCodeConstants.RETURN: + case ByteCodeConstants.EXCEPTIONLOAD: + case ByteCodeConstants.RETURNADDRESSLOAD: + break; + default: + System.err.println( + "Can not count DupLoad in " + + instruction.getClass().getName() + + ", opcode=" + instruction.opcode); + } + } + + private void visit(List instructions) + { + for (int i=instructions.size()-1; i>=0; --i) + visit(instructions.get(i)); + } + + /** + * @return le dernier parent sur lequel une substitution a �t� faite + */ + public int getCounter() + { + return this.counter; + } +} diff --git a/src/jd/core/process/analyzer/instruction/fast/visitor/FastCompareInstructionVisitor.java b/src/jd/core/process/analyzer/instruction/fast/visitor/FastCompareInstructionVisitor.java new file mode 100644 index 00000000..fcbea9e3 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/fast/visitor/FastCompareInstructionVisitor.java @@ -0,0 +1,121 @@ +package jd.core.process.analyzer.instruction.fast.visitor; + +import java.util.List; + +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.fast.FastConstants; +import jd.core.model.instruction.fast.instruction.FastSynchronized; +import jd.core.model.instruction.fast.instruction.FastTry; +import jd.core.model.instruction.fast.instruction.FastTry.FastCatch; +import jd.core.process.analyzer.classfile.visitor.CompareInstructionVisitor; + + +public class FastCompareInstructionVisitor extends CompareInstructionVisitor +{ + public boolean visit( + List list1, List list2, + int index1, int index2, int length) + { + if ((index1+length <= list1.size()) && (index2+length <= list2.size())) + { + while (length-- > 0) + { + if (!visit(list1.get(index1++), list2.get(index2++))) + return false; + } + } + + return true; + } + + public boolean visit(Instruction i1, Instruction i2) + { + if (i1.opcode != i2.opcode) + return false; + + switch (i1.opcode) + { + case FastConstants.TRY: + { + FastTry ft1 = (FastTry)i1; + FastTry ft2 = (FastTry)i2; + + int i = ft1.catches.size(); + + if (i != ft2.catches.size()) + return false; + + if (ft1.finallyInstructions == null) + { + if (ft2.finallyInstructions != null) + return false; + } + else if (ft2.finallyInstructions == null) + { + if (ft1.finallyInstructions != null) + return false; + } + else + { + if (! visit( + ft1.finallyInstructions, + ft2.finallyInstructions)) + return false; + } + + while (i-- > 0) + { + FastCatch fc1 = ft1.catches.get(i); + FastCatch fc2 = ft2.catches.get(i); + + if ((fc1.exceptionTypeIndex != fc2.exceptionTypeIndex) || + (! visit(fc1.instructions, fc2.instructions)) || + (! CompareExceptionTypeIndexes( + fc1.otherExceptionTypeIndexes, fc2.otherExceptionTypeIndexes))) + return false; + } + + return visit(ft1.instructions, ft2.instructions); + } + case FastConstants.SYNCHRONIZED: + { + FastSynchronized fs1 = (FastSynchronized)i1; + FastSynchronized fs2 = (FastSynchronized)i2; + + if (! visit(fs1.monitor, fs2.monitor)) + return false; + + return visit(fs1.instructions, fs2.instructions); + } + default: + return super.visit(i1, i2); + } + } + + private static boolean CompareExceptionTypeIndexes( + int otherExceptionTypeIndexes1[], int otherExceptionTypeIndexes2[]) + { + if (otherExceptionTypeIndexes1 == null) + { + return otherExceptionTypeIndexes2 == null; + } + else + { + if (otherExceptionTypeIndexes2 == null) + return false; + + int i = otherExceptionTypeIndexes1.length; + + if (i != otherExceptionTypeIndexes2.length) + return false; + + while (i-- > 0) + { + if (otherExceptionTypeIndexes1[i] != otherExceptionTypeIndexes2[i]) + return false; + } + + return true; + } + } +} diff --git a/src/jd/core/process/analyzer/instruction/fast/visitor/ReplaceInstructionVisitor.java b/src/jd/core/process/analyzer/instruction/fast/visitor/ReplaceInstructionVisitor.java new file mode 100644 index 00000000..a68e9443 --- /dev/null +++ b/src/jd/core/process/analyzer/instruction/fast/visitor/ReplaceInstructionVisitor.java @@ -0,0 +1,771 @@ +package jd.core.process.analyzer.instruction.fast.visitor; + +import java.util.List; + +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.ANewArray; +import jd.core.model.instruction.bytecode.instruction.AThrow; +import jd.core.model.instruction.bytecode.instruction.ArrayLength; +import jd.core.model.instruction.bytecode.instruction.ArrayStoreInstruction; +import jd.core.model.instruction.bytecode.instruction.AssertInstruction; +import jd.core.model.instruction.bytecode.instruction.BinaryOperatorInstruction; +import jd.core.model.instruction.bytecode.instruction.CheckCast; +import jd.core.model.instruction.bytecode.instruction.ComplexConditionalBranchInstruction; +import jd.core.model.instruction.bytecode.instruction.ConvertInstruction; +import jd.core.model.instruction.bytecode.instruction.DupStore; +import jd.core.model.instruction.bytecode.instruction.GetField; +import jd.core.model.instruction.bytecode.instruction.IfCmp; +import jd.core.model.instruction.bytecode.instruction.IfInstruction; +import jd.core.model.instruction.bytecode.instruction.IncInstruction; +import jd.core.model.instruction.bytecode.instruction.InitArrayInstruction; +import jd.core.model.instruction.bytecode.instruction.InstanceOf; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.InvokeInstruction; +import jd.core.model.instruction.bytecode.instruction.InvokeNew; +import jd.core.model.instruction.bytecode.instruction.InvokeNoStaticInstruction; +import jd.core.model.instruction.bytecode.instruction.LookupSwitch; +import jd.core.model.instruction.bytecode.instruction.MonitorEnter; +import jd.core.model.instruction.bytecode.instruction.MonitorExit; +import jd.core.model.instruction.bytecode.instruction.MultiANewArray; +import jd.core.model.instruction.bytecode.instruction.NewArray; +import jd.core.model.instruction.bytecode.instruction.Pop; +import jd.core.model.instruction.bytecode.instruction.PutField; +import jd.core.model.instruction.bytecode.instruction.PutStatic; +import jd.core.model.instruction.bytecode.instruction.ReturnInstruction; +import jd.core.model.instruction.bytecode.instruction.StoreInstruction; +import jd.core.model.instruction.bytecode.instruction.TableSwitch; +import jd.core.model.instruction.bytecode.instruction.TernaryOpStore; +import jd.core.model.instruction.bytecode.instruction.TernaryOperator; +import jd.core.model.instruction.bytecode.instruction.UnaryOperatorInstruction; +import jd.core.model.instruction.fast.FastConstants; +import jd.core.model.instruction.fast.instruction.FastDeclaration; +import jd.core.model.instruction.fast.instruction.FastSynchronized; +import jd.core.model.instruction.fast.instruction.FastTestList; +import jd.core.model.instruction.fast.instruction.FastTry; + + +/* + * Utilis� par TernaryOpReconstructor + */ +public class ReplaceInstructionVisitor +{ + private int offset; + private Instruction newInstruction; + private Instruction oldInstruction; + + public ReplaceInstructionVisitor(int offset, Instruction newInstruction) + { + init(offset, newInstruction); + } + + public void init(int offset, Instruction newInstruction) + { + this.offset = offset; + this.newInstruction = newInstruction; + this.oldInstruction = null; + } + + public void visit(Instruction instruction) + { + switch (instruction.opcode) + { + case ByteCodeConstants.ARRAYLENGTH: + { + ArrayLength al = (ArrayLength)instruction; + if (al.arrayref.offset == this.offset) + { + this.oldInstruction = al.arrayref; + al.arrayref = this.newInstruction; + } + else + { + visit(al.arrayref); + } + } + break; + case ByteCodeConstants.AASTORE: + case ByteCodeConstants.ARRAYSTORE: + { + ArrayStoreInstruction asi = (ArrayStoreInstruction)instruction; + if (asi.arrayref.offset == this.offset) + { + this.oldInstruction = asi.arrayref; + asi.arrayref = this.newInstruction; + } + else + { + visit(asi.arrayref); + + if (this.oldInstruction == null) + { + if (asi.indexref.offset == this.offset) + { + this.oldInstruction = asi.indexref; + asi.indexref = this.newInstruction; + } + else + { + visit(asi.indexref); + + if (this.oldInstruction == null) + { + if (asi.valueref.offset == this.offset) + { + this.oldInstruction = asi.valueref; + asi.valueref = this.newInstruction; + } + else + { + visit(asi.valueref); + } + } + } + } + } + } + break; + case ByteCodeConstants.ASSERT: + { + AssertInstruction ai = (AssertInstruction)instruction; + if (ai.test.offset == this.offset) + { + this.oldInstruction = ai.test; + ai.test = this.newInstruction; + } + else + { + visit(ai.test); + + if ((this.oldInstruction == null) && (ai.msg != null)) + { + if (ai.msg.offset == this.offset) + { + this.oldInstruction = ai.msg; + ai.msg = this.newInstruction; + } + else + { + visit(ai.msg); + } + } + } + } + break; + case ByteCodeConstants.ATHROW: + { + AThrow aThrow = (AThrow)instruction; + if (aThrow.value.offset == this.offset) + { + this.oldInstruction = aThrow.value; + aThrow.value = this.newInstruction; + } + else + { + visit(aThrow.value); + } + } + break; + case ByteCodeConstants.UNARYOP: + { + UnaryOperatorInstruction uoi = (UnaryOperatorInstruction)instruction; + if (uoi.value.offset == this.offset) + { + this.oldInstruction = uoi.value; + uoi.value = this.newInstruction; + } + else + { + visit(uoi.value); + } + } + break; + case ByteCodeConstants.BINARYOP: + case ByteCodeConstants.ASSIGNMENT: + { + BinaryOperatorInstruction boi = (BinaryOperatorInstruction)instruction; + if (boi.value1.offset == this.offset) + { + this.oldInstruction = boi.value1; + boi.value1 = this.newInstruction; + } + else + { + visit(boi.value1); + + if (this.oldInstruction == null) + { + if (boi.value2.offset == this.offset) + { + this.oldInstruction = boi.value2; + boi.value2 = this.newInstruction; + } + else + { + visit(boi.value2); + } + } + } + } + break; + case ByteCodeConstants.CHECKCAST: + { + CheckCast checkCast = (CheckCast)instruction; + if (checkCast.objectref.offset == this.offset) + { + this.oldInstruction = checkCast.objectref; + checkCast.objectref = this.newInstruction; + } + else + { + visit(checkCast.objectref); + } + } + break; + case ByteCodeConstants.STORE: + case ByteCodeConstants.ASTORE: + case ByteCodeConstants.ISTORE: + { + StoreInstruction storeInstruction = (StoreInstruction)instruction; + if (storeInstruction.valueref.offset == this.offset) + { + this.oldInstruction = storeInstruction.valueref; + storeInstruction.valueref = this.newInstruction; + } + else + { + visit(storeInstruction.valueref); + } + } + break; + case ByteCodeConstants.DUPSTORE: + { + DupStore dupStore = (DupStore)instruction; + if (dupStore.objectref.offset == this.offset) + { + this.oldInstruction = dupStore.objectref; + dupStore.objectref = this.newInstruction; + } + else + { + visit(dupStore.objectref); + } + } + break; + case ByteCodeConstants.CONVERT: + case ByteCodeConstants.IMPLICITCONVERT: + { + ConvertInstruction ci = (ConvertInstruction)instruction; + if (ci.value.offset == this.offset) + { + this.oldInstruction = ci.value; + ci.value = this.newInstruction; + } + else + { + visit(ci.value); + } + } + break; + case ByteCodeConstants.IFCMP: + { + IfCmp ifCmp = (IfCmp)instruction; + if (ifCmp.value1.offset == this.offset) + { + this.oldInstruction = ifCmp.value1; + ifCmp.value1 = this.newInstruction; + } + else + { + visit(ifCmp.value1); + + if (this.oldInstruction == null) + { + if (ifCmp.value2.offset == this.offset) + { + this.oldInstruction = ifCmp.value2; + ifCmp.value2 = this.newInstruction; + } + else + { + visit(ifCmp.value2); + } + } + } + } + break; + case ByteCodeConstants.IF: + case ByteCodeConstants.IFXNULL: + { + IfInstruction iff = (IfInstruction)instruction; + if (iff.value.offset == this.offset) + { + this.oldInstruction = iff.value; + iff.value = this.newInstruction; + } + else + { + visit(iff.value); + } + } + break; + case ByteCodeConstants.COMPLEXIF: + { + List branchList = + ((ComplexConditionalBranchInstruction)instruction).instructions; + for (int i=branchList.size()-1; i>=0; --i) + visit(branchList.get(i)); + } + break; + case ByteCodeConstants.INSTANCEOF: + { + InstanceOf instanceOf = (InstanceOf)instruction; + if (instanceOf.objectref.offset == this.offset) + { + this.oldInstruction = instanceOf.objectref; + instanceOf.objectref = this.newInstruction; + } + else + { + visit(instanceOf.objectref); + } + } + break; + case ByteCodeConstants.INVOKEINTERFACE: + case ByteCodeConstants.INVOKESPECIAL: + case ByteCodeConstants.INVOKEVIRTUAL: + { + InvokeNoStaticInstruction insi = + (InvokeNoStaticInstruction)instruction; + if (insi.objectref.offset == this.offset) + { + this.oldInstruction = insi.objectref; + insi.objectref = this.newInstruction; + } + else + { + visit(insi.objectref); + } + } + case ByteCodeConstants.INVOKESTATIC: + { + List list = ((InvokeInstruction)instruction).args; + for (int i=list.size()-1; (i>=0) && (this.oldInstruction == null); --i) + { + Instruction instuction = list.get(i); + if (instuction.offset == this.offset) + { + this.oldInstruction = instuction; + list.set(i, this.newInstruction); + } + else + { + visit(instuction); + } + } + } + break; + case ByteCodeConstants.INVOKENEW: + { + List list = ((InvokeNew)instruction).args; + for (int i=list.size()-1; (i>=0) && (this.oldInstruction == null); --i) + { + Instruction instuction = list.get(i); + if (instuction.offset == this.offset) + { + this.oldInstruction = instuction; + list.set(i, this.newInstruction); + } + else + { + visit(instuction); + } + } + } + break; + case ByteCodeConstants.LOOKUPSWITCH: + { + LookupSwitch ls = (LookupSwitch)instruction; + if (ls.key.offset == this.offset) + { + this.oldInstruction = ls.key; + ls.key = this.newInstruction; + } + else + { + visit(ls.key); + } + } + break; + case ByteCodeConstants.MONITORENTER: + { + MonitorEnter monitorEnter = (MonitorEnter)instruction; + if (monitorEnter.objectref.offset == this.offset) + { + this.oldInstruction = monitorEnter.objectref; + monitorEnter.objectref = this.newInstruction; + } + else + { + visit(monitorEnter.objectref); + } + } + break; + case ByteCodeConstants.MONITOREXIT: + { + MonitorExit monitorExit = (MonitorExit)instruction; + if (monitorExit.objectref.offset == this.offset) + { + this.oldInstruction = monitorExit.objectref; + monitorExit.objectref = this.newInstruction; + } + else + { + visit(monitorExit.objectref); + } + } + break; + case ByteCodeConstants.MULTIANEWARRAY: + { + Instruction[] dimensions = ((MultiANewArray)instruction).dimensions; + for (int i=dimensions.length-1; (i>=0) && (this.oldInstruction == null); --i) + { + if (dimensions[i].offset == this.offset) + { + this.oldInstruction = dimensions[i]; + dimensions[i] = this.newInstruction; + } + else + { + visit(dimensions[i]); + } + } + } + break; + case ByteCodeConstants.NEWARRAY: + { + NewArray newArray = (NewArray)instruction; + if (newArray.dimension.offset == this.offset) + { + this.oldInstruction = newArray.dimension; + newArray.dimension = this.newInstruction; + } + else + { + visit(newArray.dimension); + } + } + break; + case ByteCodeConstants.ANEWARRAY: + { + ANewArray aNewArray = (ANewArray)instruction; + if (aNewArray.dimension.offset == this.offset) + { + this.oldInstruction = aNewArray.dimension; + aNewArray.dimension = this.newInstruction; + } + else + { + visit(aNewArray.dimension); + } + } + break; + case ByteCodeConstants.POP: + { + Pop pop = (Pop)instruction; + if (pop.objectref.offset == this.offset) + { + this.oldInstruction = pop.objectref; + pop.objectref = this.newInstruction; + } + else + { + visit(pop.objectref); + } + } + break; + case ByteCodeConstants.PUTFIELD: + { + PutField putField = (PutField)instruction; + if (putField.objectref.offset == this.offset) + { + this.oldInstruction = putField.objectref; + putField.objectref = this.newInstruction; + } + else + { + visit(putField.objectref); + + if (this.oldInstruction == null) + { + if (putField.valueref.offset == this.offset) + { + this.oldInstruction = putField.valueref; + putField.valueref = this.newInstruction; + } + else + { + visit(putField.valueref); + } + } + } + } + break; + case ByteCodeConstants.PUTSTATIC: + { + PutStatic putStatic = (PutStatic)instruction; + if (putStatic.valueref.offset == this.offset) + { + this.oldInstruction = putStatic.valueref; + putStatic.valueref = this.newInstruction; + } + else + { + visit(putStatic.valueref); + } + } + break; + case ByteCodeConstants.XRETURN: + { + ReturnInstruction ri = (ReturnInstruction)instruction; + if (ri.valueref.offset == this.offset) + { + this.oldInstruction = ri.valueref; + ri.valueref = this.newInstruction; + } + else + { + visit(ri.valueref); + } + } + break; + case ByteCodeConstants.TABLESWITCH: + { + TableSwitch ts = (TableSwitch)instruction; + if (ts.key.offset == this.offset) + { + this.oldInstruction = ts.key; + ts.key = this.newInstruction; + } + else + { + visit(ts.key); + } + } + break; + case ByteCodeConstants.TERNARYOPSTORE: + { + TernaryOpStore tos = (TernaryOpStore)instruction; + if (tos.objectref.offset == this.offset) + { + this.oldInstruction = tos.objectref; + tos.objectref = this.newInstruction; + } + else + { + visit(tos.objectref); + } + } + break; + case ByteCodeConstants.PREINC: + case ByteCodeConstants.POSTINC: + { + IncInstruction ii = (IncInstruction)instruction; + if (ii.value.offset == this.offset) + { + this.oldInstruction = ii.value; + ii.value = this.newInstruction; + } + else + { + visit(ii.value); + } + } + break; + case ByteCodeConstants.GETFIELD: + { + GetField gf = (GetField)instruction; + if (gf.objectref.offset == this.offset) + { + this.oldInstruction = gf.objectref; + gf.objectref = this.newInstruction; + } + else + { + visit(gf.objectref); + } + } + break; + case ByteCodeConstants.INITARRAY: + case ByteCodeConstants.NEWANDINITARRAY: + { + InitArrayInstruction iai = (InitArrayInstruction)instruction; + if (iai.newArray.offset == this.offset) + { + this.oldInstruction = iai.newArray; + iai.newArray = this.newInstruction; + } + else + { + visit(iai.newArray); + + if (iai.values != null) + visit(iai.values); + } + } + break; + case ByteCodeConstants.TERNARYOP: + { + TernaryOperator to = (TernaryOperator)instruction; + if (to.test.offset == this.offset) + { + this.oldInstruction = to.test; + to.test = this.newInstruction; + } + else + { + visit(to.test); + + if (this.oldInstruction == null) + { + if (to.value1.offset == this.offset) + { + this.oldInstruction = to.value1; + to.value1 = this.newInstruction; + } + else + { + visit(to.value1); + + if (this.oldInstruction == null) + { + if (to.value2.offset == this.offset) + { + this.oldInstruction = to.value2; + to.value2 = this.newInstruction; + } + else + { + visit(to.value2); + } + } + } + } + } + } + break; + case FastConstants.TRY: + { + FastTry ft = (FastTry)instruction; + + visit(ft.instructions); + + if (this.oldInstruction == null) + { + if (ft.finallyInstructions != null) + visit(ft.finallyInstructions); + + for (int i=ft.catches.size()-1; (i>=0) && (this.oldInstruction == null); --i) + visit(ft.catches.get(i).instructions); + } + } + break; + case FastConstants.DECLARE: + { + FastDeclaration fd = (FastDeclaration)instruction; + + if (fd.instruction != null) + { + if (fd.instruction.offset == this.offset) + { + this.oldInstruction = fd.instruction; + fd.instruction = this.newInstruction; + } + else + { + visit(fd.instruction); + } + } + } + break; + case FastConstants.SYNCHRONIZED: + { + FastSynchronized fsy = (FastSynchronized)instruction; + + if (fsy.monitor.offset == this.offset) + { + this.oldInstruction = fsy.monitor; + fsy.monitor = this.newInstruction; + } + else + { + visit(fsy.monitor); + + if (this.oldInstruction == null) + visit(fsy.instructions); + } + } + break; + case FastConstants.IF_: + { + FastTestList ftl = (FastTestList)instruction; + + if (ftl.test.offset == this.offset) + { + this.oldInstruction = ftl.test; + ftl.test = this.newInstruction; + } + else + { + visit(ftl.test); + + if ((this.oldInstruction == null) && + (ftl.instructions != null)) + visit(ftl.instructions); + } + } + break; + case ByteCodeConstants.ACONST_NULL: + case ByteCodeConstants.ARRAYLOAD: + case ByteCodeConstants.LOAD: + case ByteCodeConstants.ALOAD: + case ByteCodeConstants.ILOAD: + case ByteCodeConstants.BIPUSH: + case ByteCodeConstants.ICONST: + case ByteCodeConstants.LCONST: + case ByteCodeConstants.FCONST: + case ByteCodeConstants.DCONST: + case ByteCodeConstants.DUPLOAD: + case ByteCodeConstants.GETSTATIC: + case ByteCodeConstants.OUTERTHIS: + case ByteCodeConstants.GOTO: + case ByteCodeConstants.IINC: + case ByteCodeConstants.JSR: + case ByteCodeConstants.LDC: + case ByteCodeConstants.LDC2_W: + case ByteCodeConstants.NEW: + case ByteCodeConstants.NOP: + case ByteCodeConstants.SIPUSH: + case ByteCodeConstants.RET: + case ByteCodeConstants.RETURN: + case ByteCodeConstants.EXCEPTIONLOAD: + case ByteCodeConstants.RETURNADDRESSLOAD: + break; + default: + System.err.println( + "Can not replace code in " + + instruction.getClass().getName() + + ", opcode=" + instruction.opcode); + } + } + + private void visit(List instructions) + { + for (int i=instructions.size()-1; i>=0; --i) + visit(instructions.get(i)); + } + + public Instruction getOldInstruction() + { + return oldInstruction; + } +} diff --git a/src/jd/core/process/analyzer/util/InstructionUtil.java b/src/jd/core/process/analyzer/util/InstructionUtil.java new file mode 100644 index 00000000..488bedff --- /dev/null +++ b/src/jd/core/process/analyzer/util/InstructionUtil.java @@ -0,0 +1,107 @@ +package jd.core.process.analyzer.util; + +import java.util.List; + +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.BranchInstruction; +import jd.core.model.instruction.bytecode.instruction.Instruction; + + + + +public class InstructionUtil +{ + public static Instruction getInstructionAt( + List list, int offset) + { + if ((list == null) || (list.size() == 0)) + return null; + + if (list.get(0).offset >= offset) + return list.get(0); + + int length = list.size(); + + if (length == 1) + return null; + + if (list.get(length-1).offset < offset) + return null; + + int firstIndex = 0; + int lastIndex = length-1; + + while (true) + { + int medIndex = (lastIndex + firstIndex) / 2; + Instruction i = list.get(medIndex); + + if (i.offset < offset) + firstIndex = medIndex+1; + else if (list.get(medIndex-1).offset >= offset) + lastIndex = medIndex-1; + else + return i; + } + } + + public static int getIndexForOffset( + List list, int offset) + { + if (offset < 0) + throw new RuntimeException("offset=" + offset); + + if ((list == null) || (list.size() == 0)) + return -1; + + if (list.get(0).offset >= offset) + return 0; + + int length = list.size(); + + if (length == 1) + return -1; + + if (list.get(length-1).offset < offset) + return -1; + + int firstIndex = 0; + int lastIndex = length-1; + + while (true) + { + int medIndex = (lastIndex + firstIndex) / 2; + Instruction i = list.get(medIndex); + + if (i.offset < offset) + firstIndex = medIndex+1; + else if (list.get(medIndex-1).offset >= offset) + lastIndex = medIndex-1; + else + return medIndex; + } + } + + public static boolean CheckNoJumpToInterval( + List list, int firstIndex, int afterIndex, + int firstOffset, int lastOffset) + { + for (int index=firstIndex; index list, int index, + DupStore dupStore, Instruction newInstruction) + { + ReplaceDupLoadVisitor visitor = + new ReplaceDupLoadVisitor(dupStore, newInstruction); + int length = list.size(); + + for (int i=index; i fieldNames; + private HashSet localNames; + + + public DefaultVariableNameGenerator(ClassFile classFile) + { + this.fieldNames = new HashSet(); + this.localNames = new HashSet(); + + // Add field names + Field[] fields = classFile.getFields(); + + if (fields != null) + { + for (int i=0; i 0) + prefix += "ArrayOf"; + + return generateValidName( + prefix + GetSuffixFromSignature(signature.substring(index)), + appearsOnceFlag); + } + } + + public String generateLocalVariableNameFromSignature( + String signature, boolean appearsOnce) + { + int index = CountDimensionOfArray(signature); + + if (index > 0) + { + return generateValidName( + "arrayOf" + GetSuffixFromSignature(signature.substring(index)), + appearsOnce); + } + else + { + switch (signature.charAt(0)) + { + case 'L' : + String s = FormatSignature(signature); + + if (s.equals("String")) + return generateValidName("str", appearsOnce); + + return generateValidName("local" + s, appearsOnce); + case 'B' : return generateValidName("b", appearsOnce); + case 'C' : return generateValidName("c", appearsOnce); + case 'D' : return generateValidName("d", appearsOnce); + case 'F' : return generateValidName("f", appearsOnce); + case 'I' : return generateValidIntName(appearsOnce); + case 'J' : return generateValidName("l", appearsOnce); + case 'S' : return generateValidName("s", appearsOnce); + case 'Z' : return generateValidName("bool", appearsOnce); + default: + // DEBUG + new Throwable( + "NameGenerator.generateParameterNameFromSignature: " + + "invalid signature '" + signature + "'") + .printStackTrace(); + // DEBUG + return "?"; + } + } + } + + private static int CountDimensionOfArray(String signature) + { + int index = 0; + int length = signature.length(); + + // Comptage du nombre de dimensions : '[[?' ou '[L[?;' + if (signature.charAt(index) == '[') + { + while (++index < length) + { + if ((signature.charAt(index) == 'L') && + (index+1 < length) && + (signature.charAt(index+1) == '[')) + { + index++; + length--; + } + else if (signature.charAt(index) != '[') + { + break; + } + } + } + + return index; + } + + private static String GetSuffixFromSignature(String signature) + { + switch (signature.charAt(0)) + { + case 'L' : return FormatSignature(signature); + case 'B' : return "Byte"; + case 'C' : return "Char"; + case 'D' : return "Double"; + case 'F' : return "Float"; + case 'I' : return "Int"; + case 'J' : return "Long"; + case 'S' : return "Short"; + case 'Z' : return "Boolean"; + case '[' : return "Array"; + case 'T' : return FormatTemplate(signature); + default: + // DEBUG + new Throwable("NameGenerator.generateParameterNameFromSignature: invalid signature '" + signature + "'").printStackTrace(); + // DEBUG + return "?"; + } + } + + private static String FormatSignature(String signature) + { + // cut 'L' and ';' + signature = signature.substring(1, signature.length()-1); + + int index = signature.indexOf(StringConstants.INTERNAL_BEGIN_TEMPLATE); + if (index != -1) + signature = signature.substring(0, index); + + index = signature.lastIndexOf(StringConstants.INTERNAL_INNER_SEPARATOR); + if (index != -1) + signature = signature.substring(index+1); + + index = signature.lastIndexOf(StringConstants.INTERNAL_PACKAGE_SEPARATOR); + if (index != -1) + signature = signature.substring(index+1); + + /* if (Character.isUpperCase(signature.charAt(0))) */ + return signature; + + /* return Character.toUpperCase(signature.charAt(0)) + signature.substring(1); */ + } + + private static String FormatTemplate(String signature) + { + return signature.substring(1, signature.length()-1); + } + + private String generateValidName(String name, boolean appearsOnceFlag) + { + if (Character.isUpperCase(name.charAt(0))) + name = Character.toLowerCase(name.charAt(0)) + name.substring(1); + + if (appearsOnceFlag) + if (!this.fieldNames.contains(name) && + !this.localNames.contains(name)) + { + this.localNames.add(name); + return name; + } + + for (int index=1; true; index++) + { + String newName = name + index; + + if (!this.fieldNames.contains(newName) && + !this.localNames.contains(newName)) + { + this.localNames.add(newName); + return newName; + } + } + } + + private String generateValidIntName(boolean appearsOnce) + { + if (!this.fieldNames.contains("i") && !this.localNames.contains("i")) + { + this.localNames.add("i"); + return "i"; + } + + if (!this.fieldNames.contains("j") && !this.localNames.contains("j")) + { + this.localNames.add("j"); + return "j"; + } + + if (!this.fieldNames.contains("k") && !this.localNames.contains("k")) + { + this.localNames.add("k"); + return "k"; + } + + if (!this.fieldNames.contains("m") && !this.localNames.contains("m")) + { + this.localNames.add("m"); + return "m"; + } + + if (!this.fieldNames.contains("n") && !this.localNames.contains("n")) + { + this.localNames.add("n"); + return "n"; + } + + return generateValidName("i", false); + } +} diff --git a/src/jd/core/process/analyzer/variable/VariableNameGenerator.java b/src/jd/core/process/analyzer/variable/VariableNameGenerator.java new file mode 100644 index 00000000..d2d694ed --- /dev/null +++ b/src/jd/core/process/analyzer/variable/VariableNameGenerator.java @@ -0,0 +1,14 @@ +package jd.core.process.analyzer.variable; + + +public interface VariableNameGenerator +{ + public void clearLocalNames(); + + public String generateParameterNameFromSignature( + String signature, boolean appearsOnceFlag, + boolean varargsFlag, int anonymousClassDepth); + + public String generateLocalVariableNameFromSignature( + String signature, boolean appearsOnce); +} diff --git a/src/jd/core/process/deserializer/AnnotationDeserializer.java b/src/jd/core/process/deserializer/AnnotationDeserializer.java new file mode 100644 index 00000000..887a8a79 --- /dev/null +++ b/src/jd/core/process/deserializer/AnnotationDeserializer.java @@ -0,0 +1,103 @@ +package jd.core.process.deserializer; + +import java.io.DataInput; +import java.io.IOException; + +import jd.core.model.classfile.attribute.Annotation; +import jd.core.model.classfile.attribute.ElementValue; +import jd.core.model.classfile.attribute.ElementValueAnnotationValue; +import jd.core.model.classfile.attribute.ElementValueArrayValue; +import jd.core.model.classfile.attribute.ElementValueClassInfo; +import jd.core.model.classfile.attribute.ElementValueContants; +import jd.core.model.classfile.attribute.ElementValueEnumConstValue; +import jd.core.model.classfile.attribute.ElementValuePair; +import jd.core.model.classfile.attribute.ElementValuePrimitiveType; + + +public class AnnotationDeserializer +{ + public static Annotation[] Deserialize(DataInput di) + throws IOException + { + int num_annotations = di.readUnsignedShort(); + if (num_annotations == 0) + return null; + + Annotation[] annotations = new Annotation[num_annotations]; + + for (int i=0; i innerClassFiles = new ArrayList(length); + + for (int i=0; i layoutBlockList) + { + if (attributes == null) + return; + + int attributesLength = attributes.length; + ArrayList annotations = + new ArrayList(attributesLength); + + for (int i=0; i 0) + { + layoutBlockList.add(new AnnotationsLayoutBlock( + classFile, annotations)); + } + } +} diff --git a/src/jd/core/process/layouter/ClassFileLayouter.java b/src/jd/core/process/layouter/ClassFileLayouter.java new file mode 100644 index 00000000..0b0d74b2 --- /dev/null +++ b/src/jd/core/process/layouter/ClassFileLayouter.java @@ -0,0 +1,3640 @@ +package jd.core.process.layouter; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.ClassFileConstants; +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.Field; +import jd.core.model.classfile.Field.ValueAndMethod; +import jd.core.model.classfile.Method; +import jd.core.model.classfile.attribute.AttributeSignature; +import jd.core.model.classfile.constant.ConstantFieldref; +import jd.core.model.classfile.constant.ConstantNameAndType; +import jd.core.model.instruction.bytecode.instruction.GetStatic; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.InvokeNew; +import jd.core.model.layout.block.BlockLayoutBlock; +import jd.core.model.layout.block.ByteCodeLayoutBlock; +import jd.core.model.layout.block.CommentDeprecatedLayoutBlock; +import jd.core.model.layout.block.CommentErrorLayoutBlock; +import jd.core.model.layout.block.ExtendsSuperInterfacesLayoutBlock; +import jd.core.model.layout.block.ExtendsSuperTypeLayoutBlock; +import jd.core.model.layout.block.FieldNameLayoutBlock; +import jd.core.model.layout.block.FragmentLayoutBlock; +import jd.core.model.layout.block.ImplementsInterfacesLayoutBlock; +import jd.core.model.layout.block.ImportsLayoutBlock; +import jd.core.model.layout.block.InnerTypeBodyBlockEndLayoutBlock; +import jd.core.model.layout.block.InnerTypeBodyBlockStartLayoutBlock; +import jd.core.model.layout.block.LayoutBlock; +import jd.core.model.layout.block.LayoutBlockConstants; +import jd.core.model.layout.block.MarkerLayoutBlock; +import jd.core.model.layout.block.MethodBodyBlockEndLayoutBlock; +import jd.core.model.layout.block.MethodBodyBlockStartLayoutBlock; +import jd.core.model.layout.block.MethodBodySingleLineBlockEndLayoutBlock; +import jd.core.model.layout.block.MethodNameLayoutBlock; +import jd.core.model.layout.block.MethodStaticLayoutBlock; +import jd.core.model.layout.block.PackageLayoutBlock; +import jd.core.model.layout.block.SeparatorLayoutBlock; +import jd.core.model.layout.block.SubListLayoutBlock; +import jd.core.model.layout.block.ThrowsLayoutBlock; +import jd.core.model.layout.block.TypeBodyBlockEndLayoutBlock; +import jd.core.model.layout.block.TypeBodyBlockStartLayoutBlock; +import jd.core.model.layout.block.TypeNameLayoutBlock; +import jd.core.model.layout.section.LayoutSection; +import jd.core.model.reference.Reference; +import jd.core.model.reference.ReferenceMap; +import jd.core.preferences.Preferences; +import jd.core.process.layouter.visitor.InstructionSplitterVisitor; +import jd.core.process.layouter.visitor.MaxLineNumberVisitor; +import jd.core.util.ClassFileUtil; +import jd.core.util.SignatureUtil; +import jd.core.util.StringConstants; +import jd.core.util.TypeNameUtil; + +public class ClassFileLayouter { + + public static int Layout( + Preferences preferences, + ReferenceMap referenceMap, + ClassFile classFile, + ArrayList layoutBlockList) + { + int maxLineNumber = CreateBlocks( + preferences, referenceMap, classFile, layoutBlockList); + + // "layoutBlockList" contient une structure lineaire classee dans + // l'ordre naturel sans prendre les contraintes d'alignement. + + if ((maxLineNumber != Instruction.UNKNOWN_LINE_NUMBER) && + preferences.getRealignmentLineNumber()) + { + LayoutBlocks(layoutBlockList); + } + + return maxLineNumber; + } + + private static int CreateBlocks( + Preferences preferences, + ReferenceMap referenceMap, + ClassFile classFile, + ArrayList layoutBlockList) + { + boolean separator = true; + + // Layout package statement + String internalPackageName = classFile.getInternalPackageName(); + if ((internalPackageName != null) && (internalPackageName.length() > 0)) + { + layoutBlockList.add(new PackageLayoutBlock(classFile)); + layoutBlockList.add( + new SeparatorLayoutBlock(LayoutBlockConstants.SEPARATOR, 2)); + separator = false; + } + + // Layout import statements + int importCount = GetImportCount(referenceMap, classFile); + if (importCount > 0) + { + layoutBlockList.add(new ImportsLayoutBlock( + classFile, importCount-1)); + layoutBlockList.add(new SeparatorLayoutBlock( + LayoutBlockConstants.SEPARATOR_AFTER_IMPORTS, 2)); + separator = false; + } + + if (separator) + { + layoutBlockList.add(new SeparatorLayoutBlock( + LayoutBlockConstants.SEPARATOR_AT_BEGINING, 0)); + } + + // Layout class + return CreateBlocksForClass(preferences, classFile, layoutBlockList); + } + + private static int GetImportCount( + ReferenceMap referenceMap, ClassFile classFile) + { + Collection collection = referenceMap.values(); + + if (collection.size() > 0) + { + int importCount = 0; + String internalPackageName = classFile.getInternalPackageName(); + Iterator iterator = collection.iterator(); + + // Filtrage + while (iterator.hasNext()) + { + String internalReferencePackageName = + TypeNameUtil.InternalTypeNameToInternalPackageName( + iterator.next().getInternalName()); + + // No import for same package classes + if (internalReferencePackageName.equals(internalPackageName)) + { + continue; + } + + // No import for 'java/lang' classes + if (internalReferencePackageName.equals( + StringConstants.INTERNAL_JAVA_LANG_PACKAGE_NAME)) + { + continue; + } + + importCount++; + } + + return importCount; + } + else + { + return 0; + } + } + + private static int CreateBlocksForClass( + Preferences preferences, + ClassFile classFile, + List layoutBlockList) + { + MarkerLayoutBlock tmslb = new MarkerLayoutBlock( + LayoutBlockConstants.TYPE_MARKER_START, classFile); + layoutBlockList.add(tmslb); + + boolean displayExtendsOrImplementsFlag = + CreateBlocksForHeader(classFile, layoutBlockList); + + TypeBodyBlockStartLayoutBlock bbslb = new TypeBodyBlockStartLayoutBlock(); + layoutBlockList.add(bbslb); + + int layoutBlockListLength = layoutBlockList.size(); + + int maxLineNumber = CreateBlocksForBody( + preferences, classFile, + layoutBlockList, displayExtendsOrImplementsFlag); + + if (layoutBlockListLength == layoutBlockList.size()) + { + // Classe vide. Transformation du bloc 'BodyBlockStartLayoutBlock' + if (displayExtendsOrImplementsFlag) + bbslb.transformToStartEndBlock(1); + else + bbslb.transformToStartEndBlock(0); + } + else + { + TypeBodyBlockEndLayoutBlock bbelb = new TypeBodyBlockEndLayoutBlock(); + bbslb.other = bbelb; + bbelb.other = bbslb; + layoutBlockList.add(bbelb); + } + + MarkerLayoutBlock tmelb = new MarkerLayoutBlock( + LayoutBlockConstants.TYPE_MARKER_END, classFile); + tmslb.other = tmelb; + tmelb.other = tmslb; + layoutBlockList.add(tmelb); + + return maxLineNumber; + } + + private static boolean CreateBlocksForHeader( + ClassFile classFile, List layoutBlockList) + { + boolean displayExtendsOrImplementsFlag = false; + + if (classFile.containsAttributeDeprecated() && + !classFile.containsAnnotationDeprecated(classFile)) + { + layoutBlockList.add(new CommentDeprecatedLayoutBlock()); + } + + // Affichage des attributs de la classe + //LayoutAttributes( + // layoutBlockList, classFile, classFile.getAttributes()); + + // Affichage des annotations de la classe + AnnotationLayouter.CreateBlocksForAnnotations( + classFile, classFile.getAttributes(), layoutBlockList); + + // Affichage de la classe, de l'interface, de l'enum ou de l'annotation + // Check annotation + AttributeSignature as = classFile.getAttributeSignature(); + if (as == null) + { + layoutBlockList.add(new TypeNameLayoutBlock(classFile)); + + if ((classFile.access_flags & ClassFileConstants.ACC_ANNOTATION) != 0) + { + // Annotation + } + else if ((classFile.access_flags & ClassFileConstants.ACC_ENUM) != 0) + { + // Enum + // Interfaces + displayExtendsOrImplementsFlag = + CreateBlocksForInterfacesImplements( + classFile, layoutBlockList); + } + else if ((classFile.access_flags & ClassFileConstants.ACC_INTERFACE) != 0) + { + // Interface + // Super interface + int[] interfaceIndexes = classFile.getInterfaces(); + if ((interfaceIndexes != null) && (interfaceIndexes.length > 0)) + { + displayExtendsOrImplementsFlag = true; + layoutBlockList.add( + new ExtendsSuperInterfacesLayoutBlock(classFile)); + } + } + else + { + // Class + // Super class + String internalSuperClassName = classFile.getSuperClassName(); + if ((internalSuperClassName != null) && + !StringConstants.INTERNAL_OBJECT_CLASS_NAME.equals(internalSuperClassName)) + { + displayExtendsOrImplementsFlag = true; + layoutBlockList.add( + new ExtendsSuperTypeLayoutBlock(classFile)); + } + + // Interfaces + displayExtendsOrImplementsFlag |= + CreateBlocksForInterfacesImplements( + classFile, layoutBlockList); + } + } + else + { + // Signature contenant des notations generiques + ConstantPool constants = classFile.getConstantPool(); + String signature = constants.getConstantUtf8(as.signature_index); + displayExtendsOrImplementsFlag = + SignatureLayouter.CreateLayoutBlocksForClassSignature( + classFile, signature, layoutBlockList); + } + + return displayExtendsOrImplementsFlag; + } + + private static boolean CreateBlocksForInterfacesImplements( + ClassFile classFile, List layoutBlockList) + { + int[] interfaceIndexes = classFile.getInterfaces(); + + if ((interfaceIndexes != null) && (interfaceIndexes.length > 0)) + { + layoutBlockList.add( + new ImplementsInterfacesLayoutBlock(classFile)); + + return true; + } + else + { + return false; + } + } + + public static int CreateBlocksForBodyOfAnonymousClass( + Preferences preferences, + ClassFile classFile, + List layoutBlockList) + { + InnerTypeBodyBlockStartLayoutBlock ibbslb = + new InnerTypeBodyBlockStartLayoutBlock(); + layoutBlockList.add(ibbslb); + + int layoutBlockListLength = layoutBlockList.size(); + + int maxLineNumber = CreateBlocksForBody( + preferences, classFile, layoutBlockList, false); + + if (layoutBlockListLength == layoutBlockList.size()) + { + // Classe vide. Transformation du bloc 'BodyBlockStartLayoutBlock' + ibbslb.transformToStartEndBlock(); + } + else + { + InnerTypeBodyBlockEndLayoutBlock ibbelb = + new InnerTypeBodyBlockEndLayoutBlock(); + ibbslb.other = ibbelb; + ibbelb.other = ibbslb; + layoutBlockList.add(ibbelb); + } + + return maxLineNumber; + } + + private static int CreateBlocksForBody( + Preferences preferences, + ClassFile classFile, + List layoutBlockList, + boolean displayExtendsOrImplementsFlag) + { + CreateBlockForEnumValues(preferences, classFile, layoutBlockList); + + List sortedFieldBlockList = + CreateSortedBlocksForFields(preferences, classFile); + List sortedMethodBlockList = + CreateSortedBlocksForMethods(preferences, classFile); + List sortedInnerClassBlockList = + CreateSortedBlocksForInnerClasses(preferences, classFile); + + return MergeBlocks( + layoutBlockList, sortedFieldBlockList, + sortedMethodBlockList, sortedInnerClassBlockList); + } + + private static void CreateBlockForEnumValues( + Preferences preferences, + ClassFile classFile, + List layoutBlockList) + { + List values = classFile.getEnumValues(); + + if (values != null) + { + int valuesLength = values.size(); + + if (valuesLength > 0) + { + ConstantPool constants = classFile.getConstantPool(); + Field[] fields = classFile.getFields(); + int fieldsLength = fields.length; + ArrayList enumValues = + new ArrayList(fieldsLength); + + InstructionSplitterVisitor visitor = + new InstructionSplitterVisitor(); + + // Pour chaque valeur, recherche du l'attribut d'instance, puis + // du constructeur + for (int i=0; i 0) + { + Field field = fields[j]; + + if ((field.name_index != cnat.name_index) || + (field.descriptor_index != cnat.descriptor_index)) + continue; + + ValueAndMethod vam = field.getValueAndMethod(); + InvokeNew invokeNew = (InvokeNew)vam.getValue(); + + invokeNew.transformToEnumValue(getStatic); + + enumValues.add(invokeNew); + break; + } + } + + int length = enumValues.size(); + + if (length > 0) + { + // Affichage des valeurs + InvokeNew enumValue = enumValues.get(0); + + visitor.start( + preferences, layoutBlockList, classFile, + classFile.getStaticMethod(), enumValue); + visitor.visit(enumValue); + visitor.end(); + + for (int i=1; i CreateSortedBlocksForFields( + Preferences preferences, ClassFile classFile) + { + Field[] fields = classFile.getFields(); + + if (fields == null) + { + return Collections.emptyList(); + } + else + { + // Creation des 'FieldLayoutBlock' + int length = fields.length; + ArrayList sortedFieldBlockList = + new ArrayList(length); + + InstructionSplitterVisitor visitor = + new InstructionSplitterVisitor(); + + for (int i=0; i subLayoutBlockList = + new ArrayList(6); + + MarkerLayoutBlock fmslb = new MarkerLayoutBlock( + LayoutBlockConstants.FIELD_MARKER_START, classFile); + subLayoutBlockList.add(fmslb); + +// WriteAttributes( +// spw, referenceMap, classFile, field.getAttributes()); + + if (field.containsAttributeDeprecated() && + !field.containsAnnotationDeprecated(classFile)) + { + subLayoutBlockList.add(new CommentDeprecatedLayoutBlock()); + } + + AnnotationLayouter.CreateBlocksForAnnotations( + classFile, field.getAttributes(), subLayoutBlockList); + + subLayoutBlockList.add(new FieldNameLayoutBlock(classFile, field)); + + int firstLineNumber = Instruction.UNKNOWN_LINE_NUMBER; + int lastLineNumber = Instruction.UNKNOWN_LINE_NUMBER; + int preferedLineNumber = LayoutBlockConstants.UNLIMITED_LINE_COUNT; + + if (field.getValueAndMethod() != null) + { + ValueAndMethod valueAndMethod = field.getValueAndMethod(); + Instruction value = valueAndMethod.getValue(); + Method method = valueAndMethod.getMethod(); + + firstLineNumber = value.lineNumber; + lastLineNumber = MaxLineNumberVisitor.visit(value); + preferedLineNumber = lastLineNumber - firstLineNumber; + + // Affichage des instructions d'initialisation des valeurs + visitor.start( + preferences, subLayoutBlockList, classFile, method, value); + visitor.visit(value); + visitor.end(); + + subLayoutBlockList.add(new FragmentLayoutBlock( + LayoutBlockConstants.FRAGMENT_SEMICOLON)); + } + + MarkerLayoutBlock fmelb = new MarkerLayoutBlock( + LayoutBlockConstants.FIELD_MARKER_END, classFile); + fmslb.other = fmelb; + fmelb.other = fmslb; + subLayoutBlockList.add(fmelb); + + sortedFieldBlockList.add(new SubListLayoutBlock( + LayoutBlockConstants.SUBLIST_FIELD, + subLayoutBlockList, firstLineNumber, + lastLineNumber, preferedLineNumber)); + } + + return SortBlocks(sortedFieldBlockList); + } + } + + /** + * @return liste de sequences de 'LayoutBlock' + * Sequence produite pour chaque methode: + * - MethodBlockStartLayoutBlock + * - CommentDeprecatedLayoutBlock ? + * - AnnotationsLayoutBlock ? + * - MethodLayoutBlock + * - ThrowsLayoutBlock ? + * - StatementsBlockStartLayoutBlock ? + * - StatementsLayoutBlock * + * - StatementsBlockEndLayoutBlock ? + * - MethodBlockEndLayoutBlock + */ + private static List CreateSortedBlocksForMethods( + Preferences preferences, ClassFile classFile) + { + Method[] methods = classFile.getMethods(); + + if (methods == null) + { + return Collections.emptyList(); + } + else + { + // Creation des 'MethodLayoutBlock' + ConstantPool constants = classFile.getConstantPool(); + boolean multipleConstructorFlag = + ClassFileUtil.ContainsMultipleConstructor(classFile); + int length = methods.length; + ArrayList sortedMethodBlockList = + new ArrayList(length); + boolean showDefaultConstructor = + preferences.getShowDefaultConstructor(); + + JavaSourceLayouter javaSourceLayouter = new JavaSourceLayouter(); + + for (int i=0; i subLayoutBlockList = + new ArrayList(30); + + MarkerLayoutBlock mmslb = new MarkerLayoutBlock( + LayoutBlockConstants.METHOD_MARKER_START, classFile); + subLayoutBlockList.add(mmslb); + +// WriteAttributes( +// spw, referenceMap, classFile, method.getAttributes()); + + if (method.containsError()) + { + subLayoutBlockList.add(new CommentErrorLayoutBlock()); + } + + if (method.containsAttributeDeprecated() && + !method.containsAnnotationDeprecated(classFile)) + { + subLayoutBlockList.add(new CommentDeprecatedLayoutBlock()); + } + + AnnotationLayouter.CreateBlocksForAnnotations( + classFile, method.getAttributes(), subLayoutBlockList); + + // Information utilisee par 'PrintWriter' pour afficher un ';' + // apres les methodes sans code. Evite d'instancier un object + // 'EmptyCodeLayoutBlock'. + boolean nullCodeFlag = (method.getCode() == null); + boolean displayThrowsFlag = false; + + if (method.name_index == constants.classConstructorIndex) + { + subLayoutBlockList.add(new MethodStaticLayoutBlock(classFile)); + } + else + { + if (method.getExceptionIndexes() == null) + { + subLayoutBlockList.add(new MethodNameLayoutBlock( + classFile, method, signature, + descriptorFlag, nullCodeFlag)); + } + else + { + subLayoutBlockList.add(new MethodNameLayoutBlock( + classFile, method, signature, + descriptorFlag, false)); + + subLayoutBlockList.add(new ThrowsLayoutBlock( + classFile, method, nullCodeFlag)); + + displayThrowsFlag = true; + } + } + + int firstLineNumber = Instruction.UNKNOWN_LINE_NUMBER; + int lastLineNumber = Instruction.UNKNOWN_LINE_NUMBER; + int preferedLineNumber = LayoutBlockConstants.UNLIMITED_LINE_COUNT; + + if (nullCodeFlag == false) + { + // DEBUG // + if (method.containsError()) + { + MethodBodyBlockStartLayoutBlock mbbslb = + new MethodBodyBlockStartLayoutBlock(); + subLayoutBlockList.add(mbbslb); + subLayoutBlockList.add( + new ByteCodeLayoutBlock(classFile, method)); + MethodBodyBlockEndLayoutBlock mbbelb = + new MethodBodyBlockEndLayoutBlock(); + subLayoutBlockList.add(mbbelb); + mbbslb.other = mbbelb; + mbbelb.other = mbbslb; + } + // DEBUG // + else + { + List list = method.getFastNodes(); + + MethodBodyBlockStartLayoutBlock mbbslb = + new MethodBodyBlockStartLayoutBlock(); + subLayoutBlockList.add(mbbslb); + + int subLayoutBlockListLength = subLayoutBlockList.size(); + boolean singleLine = false; + + if (list.size() > 0) + { + try + { + int beforeIndex = subLayoutBlockList.size(); + singleLine = javaSourceLayouter.createBlocks( + preferences, subLayoutBlockList, + classFile, method, list); + int afterIndex = subLayoutBlockList.size(); + + firstLineNumber = SearchFirstLineNumber( + subLayoutBlockList, beforeIndex, afterIndex); + lastLineNumber = SearchLastLineNumber( + subLayoutBlockList, beforeIndex, afterIndex); + } + catch (Exception e) + { + // DEBUG e.printStackTrace(); + // Erreur durant l'affichage => Retrait de tous + // les blocs + int currentLength = subLayoutBlockList.size(); + while (currentLength > subLayoutBlockListLength) + subLayoutBlockList.remove(--currentLength); + + subLayoutBlockList.add( + new ByteCodeLayoutBlock(classFile, method)); + } + } + + if (subLayoutBlockListLength == subLayoutBlockList.size()) + { + // Bloc vide d'instructions. Transformation du bloc + // 'StatementBlockStartLayoutBlock' + if (displayThrowsFlag) + mbbslb.transformToStartEndBlock(1); + else + mbbslb.transformToStartEndBlock(0); + } + else if (singleLine) + { + mbbslb.transformToSingleLineBlock(); + MethodBodySingleLineBlockEndLayoutBlock mbssbelb = + new MethodBodySingleLineBlockEndLayoutBlock(); + mbbslb.other = mbssbelb; + mbssbelb.other = mbbslb; + subLayoutBlockList.add(mbssbelb); + } + else + { + MethodBodyBlockEndLayoutBlock mbbelb = + new MethodBodyBlockEndLayoutBlock(); + mbbslb.other = mbbelb; + mbbelb.other = mbbslb; + subLayoutBlockList.add(mbbelb); + } + } // if (method.containsError()) else + } // if (nullCodeFlag == false) + + MarkerLayoutBlock mmelb = new MarkerLayoutBlock( + LayoutBlockConstants.METHOD_MARKER_END, classFile); + mmslb.other = mmelb; + mmelb.other = mmslb; + subLayoutBlockList.add(mmelb); + + sortedMethodBlockList.add(new SubListLayoutBlock( + LayoutBlockConstants.SUBLIST_METHOD, + subLayoutBlockList, firstLineNumber, + lastLineNumber, preferedLineNumber)); + } + + return SortBlocks(sortedMethodBlockList); + } + } + + private static List CreateSortedBlocksForInnerClasses( + Preferences preferences, ClassFile classFile) + { + ArrayList innerClassFiles = classFile.getInnerClassFiles(); + + if (innerClassFiles == null) + { + return Collections.emptyList(); + } + else + { + int length = innerClassFiles.size(); + ArrayList sortedInnerClassBlockList = + new ArrayList(length); + + for (int i=0; i innerClassLayoutBlockList = + new ArrayList(100); + + CreateBlocksForClass( + preferences, innerClassFile, innerClassLayoutBlockList); + + int afterIndex = innerClassLayoutBlockList.size(); + + int firstLineNumber = SearchFirstLineNumber( + innerClassLayoutBlockList, 0, afterIndex); + int lastLineNumber = SearchLastLineNumber( + innerClassLayoutBlockList, 0, afterIndex); + + int preferedLineCount = LayoutBlockConstants.UNLIMITED_LINE_COUNT; + if ((firstLineNumber != Instruction.UNKNOWN_LINE_NUMBER) && + (lastLineNumber != Instruction.UNKNOWN_LINE_NUMBER)) + { + preferedLineCount = lastLineNumber-firstLineNumber; + } + + sortedInnerClassBlockList.add(new SubListLayoutBlock( + LayoutBlockConstants.SUBLIST_INNER_CLASS, + innerClassLayoutBlockList, firstLineNumber, + lastLineNumber, preferedLineCount)); + } + + return SortBlocks(sortedInnerClassBlockList); + } + } + + private static int SearchFirstLineNumber( + List layoutBlockList, int firstIndex, int afterIndex) + { + for (int index=firstIndex; index layoutBlockList, int firstIndex, int afterIndex) + { + while (afterIndex-- > firstIndex) + { + int lastLineNumber = layoutBlockList.get(afterIndex).lastLineNumber; + if (lastLineNumber != Instruction.UNKNOWN_LINE_NUMBER) + return lastLineNumber; + } + + return Instruction.UNKNOWN_LINE_NUMBER; + } + + private static List SortBlocks( + List blockList) + { + // Detection de l'ordre de generation des champs par le compilateur: + // ascendant (1), descendant (2) ou aleatoire (3) + int length = blockList.size(); + int lineNumber = Instruction.UNKNOWN_LINE_NUMBER; + int order = 0; + + for (int i=0; i newLineNumber) + { + order = 3; // Aleatoire + break; + } + } + else if (order == 2) // Desc + { + if (lineNumber < newLineNumber) + { + order = 3; // Aleatoire + break; + } + } + } + + lineNumber = newLineNumber; + } + } + + // Trie + switch (order) + { + case 2: // Desc + Collections.reverse(blockList); + break; + case 3: // Aleatoire + for (int i=0; i List SortBlocks(List blockList) + { + // Detection de l'ordre de generation des champs par le compilateur: + // ascendant (1), descendant (2) ou aleatoire (3) + int length = blockList.size(); + int lineNumber = Instruction.UNKNOWN_LINE_NUMBER; + int order = 0; + + for (int i=0; i newLineNumber) + { + order = 3; // Aleatoire + break; + } + } + else if (order == 2) // Desc + { + if (lineNumber < newLineNumber) + { + order = 3; // Aleatoire + break; + } + } + } + + lineNumber = newLineNumber; + } + } + + // Trie + switch (order) + { + case 2: // Desc + Collections.reverse(blockList); + break; + case 3: // Aleatoire + // Tri par ordre croissant, les blocs sans numero de ligne + // sont places a la fin. + Collections.sort(blockList, new LayoutBlockComparator()); + break; + } + + return blockList; + } */ + + /* Premiere phase du realignement, + * 3 jeux de cartes, + * Conserver l'ordre naturel jusqu'a une impossibilite: + * Copie des blocs sans numero de ligne des champs au plus tot + * Copie des blocs sans numero de ligne des methodes et des classes internes au plus tard + */ + private static int MergeBlocks( + List layoutBlockList, + List sortedFieldBlockList, + List sortedMethodBlockList, + List sortedInnerClassBlockList) + { + int maxLineNumber = Instruction.UNKNOWN_LINE_NUMBER; + + Collections.reverse(sortedFieldBlockList); + Collections.reverse(sortedMethodBlockList); + Collections.reverse(sortedInnerClassBlockList); + + // Recherche du bloc ayant un numero de ligne defini + int minLineNumberMethod = + SearchMinimalLineNumber(sortedMethodBlockList); + int minLineNumberInnerClass = + SearchMinimalLineNumber(sortedInnerClassBlockList); + + // Fusion des jeux de cartes + // 1) Champs + while (sortedFieldBlockList.size() > 0) + { + if (minLineNumberMethod == Instruction.UNKNOWN_LINE_NUMBER) + { + if (minLineNumberInnerClass == Instruction.UNKNOWN_LINE_NUMBER) + { + // Copie de tout dans l'ordre naturel + maxLineNumber = MergeFieldBlockList( + layoutBlockList, sortedFieldBlockList, maxLineNumber); + break; + } + else + { + // Copie des champs avec et sans numero de ligne + maxLineNumber = ExclusiveMergeFieldBlockList( + layoutBlockList, sortedFieldBlockList, + minLineNumberInnerClass, maxLineNumber); + // Copie de toutes les methodes sans numero de ligne + maxLineNumber = MergeBlockList( + layoutBlockList, sortedMethodBlockList, maxLineNumber); + // Copie des classes internes jusqu'a l'inner classe ayant + // le plus petit numero de ligne + maxLineNumber = InclusiveMergeBlockList( + layoutBlockList, sortedInnerClassBlockList, + minLineNumberInnerClass, maxLineNumber); + minLineNumberInnerClass = + SearchMinimalLineNumber(sortedInnerClassBlockList); + } + } + else + { + if ((minLineNumberInnerClass == Instruction.UNKNOWN_LINE_NUMBER) || + (minLineNumberMethod < minLineNumberInnerClass)) + { + // Copie des champs avec et sans numero de ligne + maxLineNumber = ExclusiveMergeFieldBlockList( + layoutBlockList, sortedFieldBlockList, + minLineNumberMethod, maxLineNumber); + // Copie des methodes jusqu'a la methode ayant le plus + // petit numero de ligne + maxLineNumber = InclusiveMergeBlockList( + layoutBlockList, sortedMethodBlockList, + minLineNumberMethod, maxLineNumber); + minLineNumberMethod = + SearchMinimalLineNumber(sortedMethodBlockList); + } + else + { + // Copie des champs avec et sans numero de ligne + maxLineNumber = ExclusiveMergeFieldBlockList( + layoutBlockList, sortedFieldBlockList, + minLineNumberInnerClass, maxLineNumber); + // Copie des methodes avec et sans numero de ligne + maxLineNumber = ExclusiveMergeMethodOrInnerClassBlockList( + layoutBlockList, sortedMethodBlockList, + minLineNumberInnerClass, maxLineNumber); + // Copie des classes internes jusqu'a l'inner classe ayant + // le plus petit numero de ligne + maxLineNumber = InclusiveMergeBlockList( + layoutBlockList, sortedInnerClassBlockList, + minLineNumberInnerClass, maxLineNumber); + minLineNumberInnerClass = + SearchMinimalLineNumber(sortedInnerClassBlockList); + } + } + } + + // 2) Methodes + while (sortedMethodBlockList.size() > 0) + { + if (minLineNumberInnerClass == Instruction.UNKNOWN_LINE_NUMBER) + { + maxLineNumber = MergeBlockList( + layoutBlockList, sortedMethodBlockList, maxLineNumber); + break; + } + else + { + // Copie des methodes avec et sans numero de ligne + maxLineNumber = ExclusiveMergeMethodOrInnerClassBlockList( + layoutBlockList, sortedMethodBlockList, + minLineNumberInnerClass, maxLineNumber); + // Copie des classes internes jusqu'a l'inner classe ayant le + // plus petit numero de ligne + maxLineNumber = InclusiveMergeBlockList( + layoutBlockList, sortedInnerClassBlockList, + minLineNumberInnerClass, maxLineNumber); + minLineNumberInnerClass = + SearchMinimalLineNumber(sortedInnerClassBlockList); + } + } + + // 3) Classes internes + maxLineNumber = MergeBlockList( + layoutBlockList, sortedInnerClassBlockList, maxLineNumber); + + return maxLineNumber; + } + + private static int ExclusiveMergeMethodOrInnerClassBlockList( + List destination, + List source, + int minLineNumber, int maxLineNumber) + { + byte lastTag = destination.get(destination.size()-1).tag; + int index = source.size(); + + while (index > 0) + { + SubListLayoutBlock sllb = source.get(index-1); + int lineNumber = sllb.lastLineNumber; + + if ((lineNumber != Instruction.UNKNOWN_LINE_NUMBER) && + (lineNumber >= minLineNumber)) + break; + + // Add separator + switch (lastTag) + { + case LayoutBlockConstants.FIELD_MARKER_END: + destination.add( + new SeparatorLayoutBlock(LayoutBlockConstants.SEPARATOR, 1)); + break; +// case LayoutBlockConstants.SEPARATOR_BEFORE_OR_AFTER_BLOCK: + case LayoutBlockConstants.TYPE_BODY_BLOCK_START: + case LayoutBlockConstants.INNER_TYPE_BODY_BLOCK_START: + case LayoutBlockConstants.METHOD_BODY_BLOCK_START: + case LayoutBlockConstants.METHOD_BODY_SINGLE_LINE_BLOCK_START: + case LayoutBlockConstants.STATEMENTS_BLOCK_START: + case LayoutBlockConstants.SWITCH_BLOCK_START: + case LayoutBlockConstants.SEPARATOR: + break; + default: + destination.add( + new SeparatorLayoutBlock(LayoutBlockConstants.SEPARATOR, 2)); + break; + } + + // Move item + destination.addAll(sllb.subList); + + // Store last line number + int lastLineNumber = sllb.lastLineNumber; + if (lastLineNumber != Instruction.UNKNOWN_LINE_NUMBER) + { + if ((maxLineNumber == Instruction.UNKNOWN_LINE_NUMBER) || + (maxLineNumber < lastLineNumber)) + { + maxLineNumber = lastLineNumber; + } + } + + source.remove(--index); + + // Store last tag + lastTag = LayoutBlockConstants.UNDEFINED; + } + + return maxLineNumber; + } + + private static int ExclusiveMergeFieldBlockList( + List destination, + List source, + int minLineNumber, int maxLineNumber) + { + byte lastTag = destination.get(destination.size()-1).tag; + int index = source.size(); + + while (index > 0) + { + SubListLayoutBlock sllb = source.get(index-1); + int lineNumber = sllb.lastLineNumber; + + if ((lineNumber != Instruction.UNKNOWN_LINE_NUMBER) && + (lineNumber >= minLineNumber)) + break; + + // Add separator + switch (lastTag) + { + case LayoutBlockConstants.FIELD_MARKER_END: + destination.add( + new SeparatorLayoutBlock(LayoutBlockConstants.SEPARATOR, 1)); + break; +// case LayoutBlockConstants.SEPARATOR_BEFORE_OR_AFTER_BLOCK: + case LayoutBlockConstants.TYPE_BODY_BLOCK_START: + case LayoutBlockConstants.INNER_TYPE_BODY_BLOCK_START: + case LayoutBlockConstants.METHOD_BODY_BLOCK_START: + case LayoutBlockConstants.METHOD_BODY_SINGLE_LINE_BLOCK_START: + case LayoutBlockConstants.STATEMENTS_BLOCK_START: + case LayoutBlockConstants.SWITCH_BLOCK_START: + case LayoutBlockConstants.SEPARATOR: + break; + default: + destination.add( + new SeparatorLayoutBlock(LayoutBlockConstants.SEPARATOR, 2)); + break; + } + + // Move item + source.remove(--index); + destination.addAll(sllb.subList); + + // Store last line number + int lastLineNumber = sllb.lastLineNumber; + if (lastLineNumber != Instruction.UNKNOWN_LINE_NUMBER) + { + if ((maxLineNumber == Instruction.UNKNOWN_LINE_NUMBER) || + (maxLineNumber < lastLineNumber)) + { + maxLineNumber = lastLineNumber; + } + } + + // Store last tag + lastTag = LayoutBlockConstants.FIELD_MARKER_END; + } + + return maxLineNumber; + } + + private static int InclusiveMergeBlockList( + List destination, + List source, + int minLineNumber, int maxLineNumber) + { + byte lastTag = destination.get(destination.size()-1).tag; + int index = source.size(); + + // Deplacement + while (index > 0) + { + SubListLayoutBlock sllb = source.get(index-1); + int lineNumber = sllb.lastLineNumber; + + if ((lineNumber != Instruction.UNKNOWN_LINE_NUMBER) && + (lineNumber > minLineNumber)) + break; + + // Add separator + switch (lastTag) + { +// case LayoutBlockConstants.SEPARATOR_BEFORE_OR_AFTER_BLOCK: + case LayoutBlockConstants.TYPE_BODY_BLOCK_START: + case LayoutBlockConstants.INNER_TYPE_BODY_BLOCK_START: + case LayoutBlockConstants.METHOD_BODY_BLOCK_START: + case LayoutBlockConstants.METHOD_BODY_SINGLE_LINE_BLOCK_START: + case LayoutBlockConstants.STATEMENTS_BLOCK_START: + case LayoutBlockConstants.SWITCH_BLOCK_START: + case LayoutBlockConstants.SEPARATOR: + break; + default: + destination.add( + new SeparatorLayoutBlock(LayoutBlockConstants.SEPARATOR, 2)); + break; + } + + // Move item + destination.addAll(sllb.subList); + + // Store last line number + int lastLineNumber = sllb.lastLineNumber; + if (lastLineNumber != Instruction.UNKNOWN_LINE_NUMBER) + { + if ((maxLineNumber == Instruction.UNKNOWN_LINE_NUMBER) || + (maxLineNumber < lastLineNumber)) + { + maxLineNumber = lastLineNumber; + } + } + + source.remove(--index); + + if (lineNumber == minLineNumber) + break; + + // Store last tag + lastTag = LayoutBlockConstants.UNDEFINED; + } + + return maxLineNumber; + } + + private static int MergeBlockList( + List destination, + List source, + int maxLineNumber) + { + byte lastTag = destination.get(destination.size()-1).tag; + int index = source.size(); + + while (index-- > 0) + { + // Add separator + switch (lastTag) + { +// case LayoutBlockConstants.SEPARATOR_BEFORE_OR_AFTER_BLOCK: + case LayoutBlockConstants.TYPE_BODY_BLOCK_START: + case LayoutBlockConstants.INNER_TYPE_BODY_BLOCK_START: + case LayoutBlockConstants.METHOD_BODY_BLOCK_START: + case LayoutBlockConstants.METHOD_BODY_SINGLE_LINE_BLOCK_START: + case LayoutBlockConstants.STATEMENTS_BLOCK_START: + case LayoutBlockConstants.SWITCH_BLOCK_START: + case LayoutBlockConstants.SEPARATOR: + break; + default: + destination.add(new SeparatorLayoutBlock( + LayoutBlockConstants.SEPARATOR, 2)); + break; + } + + // Move item + SubListLayoutBlock sllb = source.remove(index); + destination.addAll(sllb.subList); + + // Store last line number + int lastLineNumber = sllb.lastLineNumber; + if (lastLineNumber != Instruction.UNKNOWN_LINE_NUMBER) + { + if ((maxLineNumber == Instruction.UNKNOWN_LINE_NUMBER) || + (maxLineNumber < lastLineNumber)) + { + maxLineNumber = lastLineNumber; + } + } + + // Store last tag + lastTag = LayoutBlockConstants.UNDEFINED; + } + + return maxLineNumber; + } + + private static int MergeFieldBlockList( + List destination, + List source, + int maxLineNumber) + { + byte lastTag = destination.get(destination.size()-1).tag; + int index = source.size(); + + while (index-- > 0) + { + // Add separator + switch (lastTag) + { + case LayoutBlockConstants.FIELD_MARKER_END: + destination.add( + new SeparatorLayoutBlock(LayoutBlockConstants.SEPARATOR, 1)); + break; +// case LayoutBlockConstants.SEPARATOR_BEFORE_OR_AFTER_BLOCK: + case LayoutBlockConstants.TYPE_BODY_BLOCK_START: + case LayoutBlockConstants.INNER_TYPE_BODY_BLOCK_START: + case LayoutBlockConstants.METHOD_BODY_BLOCK_START: + case LayoutBlockConstants.METHOD_BODY_SINGLE_LINE_BLOCK_START: + case LayoutBlockConstants.STATEMENTS_BLOCK_START: + case LayoutBlockConstants.SWITCH_BLOCK_START: + case LayoutBlockConstants.SEPARATOR: + break; + default: + destination.add(new SeparatorLayoutBlock( + LayoutBlockConstants.SEPARATOR, 2)); + break; + } + + // Move item + SubListLayoutBlock sllb = source.remove(index); + destination.addAll(sllb.subList); + + // Store last line number + int lastLineNumber = sllb.lastLineNumber; + if (lastLineNumber != Instruction.UNKNOWN_LINE_NUMBER) + { + if ((maxLineNumber == Instruction.UNKNOWN_LINE_NUMBER) || + (maxLineNumber < lastLineNumber)) + { + maxLineNumber = lastLineNumber; + } + } + + // Store last tag + lastTag = LayoutBlockConstants.FIELD_MARKER_END; + } + + return maxLineNumber; + } + + /* + * La liste est classee en ordre inverse + */ + private static int SearchMinimalLineNumber(List list) + { + int index = list.size(); + + while (index-- > 0) + { + int lineNumber = list.get(index).lastLineNumber; + if (lineNumber != Instruction.UNKNOWN_LINE_NUMBER) + return lineNumber; + } + + return Instruction.UNKNOWN_LINE_NUMBER; + } + + private static void LayoutBlocks(ArrayList layoutBlockList) + { + // DEBUG // long time0 = System.currentTimeMillis(); + + // Initialize + ArrayList layoutSectionList = + new ArrayList(); + + CreateSections(layoutBlockList, layoutSectionList); + InitializeBlocks(layoutBlockList, layoutSectionList); + + int layoutCount = 20; + + do + { + // Layout + LayoutSections(layoutBlockList, layoutSectionList); + + // Score + ScoreSections(layoutBlockList, layoutSectionList); + + // Slice + if (SliceDownBlocks(layoutBlockList, layoutSectionList) == false) + break; + + ResetLineCounts(layoutBlockList, layoutSectionList); + } + while (layoutCount-- > 0); + + // DEBUG // System.err.println("LayoutBlocks: Nbr de boucles: " + (20-layoutCount)); + + layoutCount = 20; + + do + { + // Layout + LayoutSections(layoutBlockList, layoutSectionList); + + // Score + ScoreSections(layoutBlockList, layoutSectionList); + + // Slice + if (SliceUpBlocks(layoutBlockList, layoutSectionList) == false) + break; + + ResetLineCounts(layoutBlockList, layoutSectionList); + } + while (layoutCount-- > 0); + + // DEBUG // System.err.println("LayoutBlocks: Nbr de boucles: " + (20-layoutCount)); + + // DEBUG // long time1 = System.currentTimeMillis(); + // DEBUG // System.err.println("LayoutBlocks: Temps: " + (time1-time0) + "ms"); + } + + private static void CreateSections( + ArrayList layoutBlockList, + ArrayList layoutSectionList) + { + int blockLength = layoutBlockList.size(); + + // Layout + int layoutSectionListSize = 0; + int firstBlockIndex = 0; + int firstLineNumber = 1; + boolean containsError = false; + + for (int blockIndex=1; blockIndex lb.firstLineNumber) + containsError = true; + layoutSectionList.add(new LayoutSection( + layoutSectionListSize++, + firstBlockIndex, blockIndex-1, + firstLineNumber, lb.firstLineNumber, + containsError)); + firstBlockIndex = blockIndex+1; + firstLineNumber = lb.lastLineNumber; + containsError = false; + } + } + + if (firstBlockIndex < blockLength-1) + { + layoutSectionList.add(new LayoutSection( + layoutSectionListSize++, + firstBlockIndex, blockLength-1, + firstLineNumber, Instruction.UNKNOWN_LINE_NUMBER, + containsError)); + } + } + + private static void InitializeBlocks( + ArrayList layoutBlockList, + ArrayList layoutSectionList) + { + // Initialize indexes & sections + int blockIndex = 0; + int sectionLength = layoutSectionList.size(); + + for (int sectionIndex=0; sectionIndex layoutBlockList, + ArrayList layoutSectionList) + { + // Initialize indexes & sections + int sectionLength = layoutSectionList.size(); + + for (int sectionIndex=0; sectionIndex layoutBlockList, + ArrayList layoutSectionList) + { + // Layout sections + int sectionLength = layoutSectionList.size(); + + if (sectionLength > 0) + { + sectionLength--; + + int layoutCount = 5; + boolean redo; + + do + { + redo = false; + + // Mise en page avec heuristiques + for (int sectionIndex=0; sectionIndex currentLineCount) + { + ExpandBlocksWithHeuristics( + layoutBlockList, section.firstBlockIndex, section.lastBlockIndex, + originalLineCount-currentLineCount); + redo = true; + } + else if (currentLineCount > originalLineCount) + { + CompactBlocksWithHeuristics( + layoutBlockList, section.firstBlockIndex, section.lastBlockIndex, + currentLineCount-originalLineCount); + redo = true; + } + } + } + + // Pas de mise en page de la derniere section + layoutSectionList.get(sectionLength).relayout = false; + } + while (redo && (layoutCount-- > 0)); + + // Derniere mise en page si les precedentes tentatives ont echouees + if (redo) + { + for (int sectionIndex=0; sectionIndex currentLineCount) + { + ExpandBlocks( + layoutBlockList, section.firstBlockIndex, section.lastBlockIndex, + originalLineCount-currentLineCount); + } + else if (currentLineCount > originalLineCount) + { + CompactBlocks( + layoutBlockList, section.firstBlockIndex, section.lastBlockIndex, + currentLineCount-originalLineCount); + } + } + } + + // Pas de mise en page de la derniere section + layoutSectionList.get(sectionLength).relayout = false; + } + } + } + + private static int GetLineCount( + ArrayList layoutBlockList, int firstIndex, int lastIndex) + { + int sum = 0; + + for (int index=firstIndex; index<=lastIndex; index++) + { + int lineCount = layoutBlockList.get(index).lineCount; + if (lineCount != LayoutBlockConstants.UNLIMITED_LINE_COUNT) + sum += lineCount; + } + + return sum; + } + + private static void CompactBlocksWithHeuristics( + ArrayList layoutBlockList, + int firstIndex, int lastIndex, int delta) + { + int oldDelta; + + do + { + oldDelta = delta; + + // Compact separator + for (int i=lastIndex; (i>=firstIndex) && (delta>0); i--) + { + LayoutBlock lb = layoutBlockList.get(i); + + switch (lb.tag) + { + case LayoutBlockConstants.SEPARATOR: + case LayoutBlockConstants.SEPARATOR_OF_STATEMENTS: + if (lb.lineCount > 2) + { + lb.lineCount--; + delta--; + } + break; + } + } + } + while ((delta>0) && (oldDelta>delta)); + + do + { + oldDelta = delta; + + // Compact implements & throws + for (int i=lastIndex; (i>=firstIndex) && (delta>0); i--) + { + LayoutBlock lb = layoutBlockList.get(i); + + switch (lb.tag) + { + case LayoutBlockConstants.IMPLEMENTS_INTERFACES: + case LayoutBlockConstants.GENERIC_IMPLEMENTS_INTERFACES: + case LayoutBlockConstants.THROWS: + if (lb.lineCount > 0) + { + lb.lineCount--; + delta--; + } + break; + } + } + + // Compact extends + for (int i=lastIndex; (i>=firstIndex) && (delta>0); i--) + { + LayoutBlock lb = layoutBlockList.get(i); + + switch (lb.tag) + { + case LayoutBlockConstants.EXTENDS_SUPER_TYPE: + case LayoutBlockConstants.EXTENDS_SUPER_INTERFACES: + case LayoutBlockConstants.GENERIC_EXTENDS_SUPER_TYPE: + case LayoutBlockConstants.GENERIC_EXTENDS_SUPER_INTERFACES: + if (lb.lineCount > 0) + { + lb.lineCount--; + delta--; + } + break; + } + } + } + while ((delta>0) && (oldDelta>delta)); + + // Compact imports + for (int i=lastIndex; (i>=firstIndex) && (delta>0); i--) + { + LayoutBlock lb = layoutBlockList.get(i); + + switch (lb.tag) + { + case LayoutBlockConstants.IMPORTS: + if (lb.lineCount > 0) + { + if (lb.lineCount >= delta) + { + lb.lineCount -= delta; + delta = 0; + } + else + { + delta -= lb.lineCount; + lb.lineCount = 0; + } + } + break; + } + } + + do + { + oldDelta = delta; + + // Compact debut de bloc des methodes + for (int i=lastIndex; (i>=firstIndex) && (delta>0); i--) + { + LayoutBlock lb = layoutBlockList.get(i); + + switch (lb.tag) + { + case LayoutBlockConstants.STATEMENTS_BLOCK_START: + case LayoutBlockConstants.SINGLE_STATEMENT_BLOCK_START: + case LayoutBlockConstants.SWITCH_BLOCK_START: + case LayoutBlockConstants.METHOD_BODY_BLOCK_START: + case LayoutBlockConstants.METHOD_BODY_SINGLE_LINE_BLOCK_START: + case LayoutBlockConstants.INNER_TYPE_BODY_BLOCK_START: + case LayoutBlockConstants.TYPE_BODY_BLOCK_START: + if ((lb.lineCount > 1) && + (lb.lineCount > lb.minimalLineCount)) + { + lb.lineCount--; + delta--; + } + } + } + } + while ((delta>0) && (oldDelta>delta)); + + do + { + oldDelta = delta; + + // Compact separator + for (int i=lastIndex; (i>=firstIndex) && (delta>0); i--) + { + LayoutBlock lb = layoutBlockList.get(i); + + switch (lb.tag) + { + /* TENTATIVE case LayoutBlockConstants.SEPARATOR: */ + case LayoutBlockConstants.SEPARATOR_OF_STATEMENTS: + if (lb.lineCount > 1) + { + lb.lineCount--; + delta--; + } + break; + } + } + } + while ((delta>0) && (oldDelta>delta)); + + do + { + oldDelta = delta; + + // Compact fin de bloc des methodes + for (int i=lastIndex; (i>=firstIndex) && (delta>0); i--) + { + LayoutBlock lb = layoutBlockList.get(i); + + switch (lb.tag) + { + case LayoutBlockConstants.STATEMENTS_BLOCK_END: + case LayoutBlockConstants.SINGLE_STATEMENT_BLOCK_END: + case LayoutBlockConstants.SWITCH_BLOCK_END: + case LayoutBlockConstants.METHOD_BODY_BLOCK_END: + case LayoutBlockConstants.METHOD_BODY_SINGLE_LINE_BLOCK_END: + case LayoutBlockConstants.INNER_TYPE_BODY_BLOCK_END: + case LayoutBlockConstants.TYPE_BODY_BLOCK_END: + if ((lb.lineCount > 1) && + (lb.lineCount > lb.minimalLineCount)) + { + // Compact end block + lb.lineCount--; + delta--; + } + } + } + } + while ((delta>0) && (oldDelta>delta)); + + do + { + oldDelta = delta; + + // Compact separator + for (int i=lastIndex; (i>=firstIndex) && (delta>0); i--) + { + LayoutBlock lb = layoutBlockList.get(i); + + switch (lb.tag) + { + case LayoutBlockConstants.FRAGMENT_CASE: + case LayoutBlockConstants.FRAGMENT_CASE_ENUM: + case LayoutBlockConstants.FRAGMENT_CASE_STRING: + if (lb.lineCount > 0) + { + lb.lineCount--; + delta--; + } + break; + } + } + } + while ((delta>0) && (oldDelta>delta)); + + do + { + oldDelta = delta; + + // Compact fin de bloc des methodes + for (int i=firstIndex; (i<=lastIndex) && (delta>0); i++) + { + LayoutBlock lb = layoutBlockList.get(i); + + switch (lb.tag) + { + case LayoutBlockConstants.SINGLE_STATEMENT_BLOCK_END: + if (lb.lineCount > lb.minimalLineCount) + { + // Compact end block + lb.lineCount--; + delta--; + } + } + } + } + while ((delta>0) && (oldDelta>delta)); + + do + { + oldDelta = delta; + + // Compact separator + for (int i=lastIndex; (i>=firstIndex) && (delta>0); i--) + { + LayoutBlock lb = layoutBlockList.get(i); + + switch (lb.tag) + { + case LayoutBlockConstants.CASE_BLOCK_START: + case LayoutBlockConstants.CASE_BLOCK_END: + if (lb.lineCount > 0) + { + lb.lineCount--; + delta--; + } + break; + } + } + } + while ((delta>0) && (oldDelta>delta)); + + do + { + oldDelta = delta; + + // Compact fin de bloc des methodes + for (int i=lastIndex; (i>=firstIndex) && (delta>0); i--) + { + LayoutBlock lb = layoutBlockList.get(i); + + switch (lb.tag) + { + case LayoutBlockConstants.METHOD_BODY_SINGLE_LINE_BLOCK_START: + case LayoutBlockConstants.METHOD_BODY_SINGLE_LINE_BLOCK_END: + if (lb.lineCount > lb.minimalLineCount) + { + BlockLayoutBlock blb = (BlockLayoutBlock)lb; + + // Compact end block + lb.lineCount--; + delta--; + + if (lb.lineCount <= 1) + { + // Compact start block + if (blb.section == blb.other.section) + { + if (blb.other.lineCount > delta) + { + blb.other.lineCount -= delta; + delta = 0; + } + else + { + delta -= blb.other.lineCount; + blb.other.lineCount = 0; + } + } + else + { + blb.other.section.relayout = true; + blb.other.lineCount = 0; + } + } + } + } + } + } + while ((delta>0) && (oldDelta>delta)); + + do + { + oldDelta = delta; + + // Compact debut de bloc des methodes + for (int i=lastIndex; (i>=firstIndex) && (delta>0); i--) + { + LayoutBlock lb = layoutBlockList.get(i); + + switch (lb.tag) + { + case LayoutBlockConstants.STATEMENTS_BLOCK_START: + case LayoutBlockConstants.SWITCH_BLOCK_START: + case LayoutBlockConstants.METHOD_BODY_BLOCK_START: + case LayoutBlockConstants.INNER_TYPE_BODY_BLOCK_START: + case LayoutBlockConstants.TYPE_BODY_BLOCK_START: + if (lb.lineCount > lb.minimalLineCount) + { + // Compact start block + lb.lineCount--; + delta--; + } + break; + case LayoutBlockConstants.SINGLE_STATEMENT_BLOCK_START: + if (lb.lineCount > lb.minimalLineCount) + { + // Compact start block + lb.lineCount--; + delta--; + + if (lb.lineCount == 0) + { + BlockLayoutBlock blb = (BlockLayoutBlock)lb; + + // Compact end block + if (blb.section == blb.other.section) + { + if (blb.other.lineCount > delta) + { + blb.other.lineCount -= delta; + delta = 0; + } + else + { + delta -= blb.other.lineCount; + blb.other.lineCount = 0; + } + } + else + { + blb.other.section.relayout = true; + blb.other.lineCount = 0; + } + } + } + break; + } + } + + // Compact fin de bloc des methodes + for (int i=lastIndex; (i>=firstIndex) && (delta>0); i--) + { + LayoutBlock lb = layoutBlockList.get(i); + + switch (lb.tag) + { + case LayoutBlockConstants.STATEMENTS_BLOCK_END: + case LayoutBlockConstants.SWITCH_BLOCK_END: + case LayoutBlockConstants.METHOD_BODY_BLOCK_END: + case LayoutBlockConstants.INNER_TYPE_BODY_BLOCK_END: + case LayoutBlockConstants.TYPE_BODY_BLOCK_END: + if (lb.lineCount > lb.minimalLineCount) + { +// BlockLayoutBlock blb = (BlockLayoutBlock)lb; + + // Compact end block + lb.lineCount--; + delta--; + +// if (lb.lineCount <= 1) +// { +// // Compact start block +// if (blb.section == blb.other.section) +// { +// if (blb.other.lineCount > delta) +// { +// blb.other.lineCount -= delta; +// delta = 0; +// } +// else +// { +// delta -= blb.other.lineCount; +// blb.other.lineCount = 0; +// } +// } +// else +// { +// blb.other.section.relayout = true; +// blb.other.lineCount = 0; +// } +// } + } + } + } + } + while ((delta>0) && (oldDelta>delta)); + + do + { + oldDelta = delta; + + // Compact separator + for (int i=lastIndex; (i>=firstIndex) && (delta>0); i--) + { + LayoutBlock lb = layoutBlockList.get(i); + + switch (lb.tag) + { + case LayoutBlockConstants.SEPARATOR: + case LayoutBlockConstants.SEPARATOR_OF_STATEMENTS: + if (lb.lineCount > 0) + { + lb.lineCount--; + delta--; + } + break; + } + } + } + while ((delta>0) && (oldDelta>delta)); + + do + { + oldDelta = delta; + + // Compact separator + for (int i=lastIndex; (i>=firstIndex) && (delta>0); i--) + { + LayoutBlock lb = layoutBlockList.get(i); + + switch (lb.tag) + { + case LayoutBlockConstants.COMMENT_ERROR: + if (lb.lineCount > 0) + { + lb.lineCount--; + delta--; + } + break; + } + } + } + while ((delta>0) && (oldDelta>delta)); + +// // Si les heuristiques n'ont pas ete suffisantes... +// do +// { +// oldDelta = delta; +// +// // Compact block +// for (int i=lastIndex; (i>=firstIndex) && (delta>0); i--) +// { +// LayoutBlock lb = layoutBlockList.get(i); +// +// if (lb.lineCount > lb.minimalLineCount) +// { +// lb.lineCount--; +// delta--; +// } +// } +// } +// while ((delta>0) && (oldDelta>delta)); + } + + private static void ExpandBlocksWithHeuristics( + ArrayList layoutBlockList, + int firstIndex, int lastIndex, int delta) + { + int oldDelta; + + do + { + oldDelta = delta; + + // Expand "implements types" + for (int i=firstIndex; (i<=lastIndex) && (delta>0); i++) + { + LayoutBlock lb = layoutBlockList.get(i); + + switch (lb.tag) + { + case LayoutBlockConstants.IMPLEMENTS_INTERFACES: + case LayoutBlockConstants.EXTENDS_SUPER_INTERFACES: + case LayoutBlockConstants.GENERIC_IMPLEMENTS_INTERFACES: + case LayoutBlockConstants.GENERIC_EXTENDS_SUPER_INTERFACES: + if (lb.lineCount < lb.maximalLineCount) + { + lb.lineCount++; + delta--; + } + break; + } + } + + // Expand "extends super type" + for (int i=firstIndex; (i<=lastIndex) && (delta>0); i++) + { + LayoutBlock lb = layoutBlockList.get(i); + + switch (lb.tag) + { + case LayoutBlockConstants.EXTENDS_SUPER_TYPE: + case LayoutBlockConstants.GENERIC_EXTENDS_SUPER_TYPE: + if (lb.lineCount < lb.maximalLineCount) + { + lb.lineCount++; + delta--; + } + break; + } + } + + // Expand separator after imports + for (int i=firstIndex; (i<=lastIndex) && (delta>0); i++) + { + LayoutBlock lb = layoutBlockList.get(i); + + switch (lb.tag) + { + case LayoutBlockConstants.SEPARATOR_AT_BEGINING: + case LayoutBlockConstants.SEPARATOR_AFTER_IMPORTS: + lb.lineCount += delta; + delta = 0; + break; + } + } + } + while ((delta>0) && (oldDelta>delta)); + + do + { + oldDelta = delta; + + for (int i=firstIndex; (i<=lastIndex) && (delta>0); i++) + { + LayoutBlock lb = layoutBlockList.get(i); + + switch (lb.tag) + { + case LayoutBlockConstants.FOR_BLOCK_START: + if (lb.lineCount < lb.maximalLineCount) + { + lb.lineCount++; + delta--; + } + break; + } + } + } + while ((delta>0) && (oldDelta>delta)); + + do + { + oldDelta = delta; + + for (int i=lastIndex; (i>=firstIndex) && (delta>0); i--) + { + LayoutBlock lb = layoutBlockList.get(i); + + switch (lb.tag) + { + case LayoutBlockConstants.CASE_BLOCK_END: + if (lb.lineCount == 0) + { + lb.lineCount++; + delta--; + } + break; + } + } + } + while ((delta>0) && (oldDelta>delta)); + + do + { + oldDelta = delta; + + // Expand fin de bloc des methodes + for (int i=firstIndex; (i<=lastIndex) && (delta>0); i++) + { + LayoutBlock lb = layoutBlockList.get(i); + + switch (lb.tag) + { + case LayoutBlockConstants.INNER_TYPE_BODY_BLOCK_END: + case LayoutBlockConstants.TYPE_BODY_BLOCK_END: + case LayoutBlockConstants.METHOD_BODY_BLOCK_END: + case LayoutBlockConstants.STATEMENTS_BLOCK_END: // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + case LayoutBlockConstants.SINGLE_STATEMENT_BLOCK_END: + case LayoutBlockConstants.SWITCH_BLOCK_END: + if (lb.lineCount == 0) + { + BlockLayoutBlock blb = (BlockLayoutBlock)lb; + + // Expand end block + lb.lineCount++; + delta--; + + // Expand start block + if (blb.other.lineCount == 0) + { + if (blb.section == blb.other.section) + { + if (delta > 0) + { + blb.other.lineCount++; + delta--; + } + } + else + { + blb.other.section.relayout = true; + blb.other.lineCount = 1; + } + } + } + } + } + + // Expand debut de bloc du corps des classes internes + for (int i=firstIndex; (i<=lastIndex) && (delta>0); i++) + { + LayoutBlock lb = layoutBlockList.get(i); + + switch (lb.tag) + { + case LayoutBlockConstants.INNER_TYPE_BODY_BLOCK_START: + case LayoutBlockConstants.TYPE_BODY_BLOCK_START: + case LayoutBlockConstants.METHOD_BODY_BLOCK_START: + case LayoutBlockConstants.STATEMENTS_BLOCK_START: + case LayoutBlockConstants.SWITCH_BLOCK_START: + if (lb.lineCount == 0) + { + BlockLayoutBlock blb = (BlockLayoutBlock)lb; + + // Expand start block + lb.lineCount++; + delta--; + // Expand end block + if (blb.section == blb.other.section) + { + int d = 2 - blb.other.lineCount; + + if (d > delta) + { + blb.other.lineCount += delta; + delta = 0; + } + else + { + delta -= d; + blb.other.lineCount = 2; + } + } + else + { + blb.other.section.relayout = true; + blb.other.lineCount = 2; + } + } + } + } + } + while ((delta>0) && (oldDelta>delta)); + + do + { + oldDelta = delta; + + // Expand separator 1 + for (int i=firstIndex; (i<=lastIndex) && (delta>0); i++) + { + LayoutBlock lb = layoutBlockList.get(i); + + switch (lb.tag) + { + case LayoutBlockConstants.SEPARATOR: + case LayoutBlockConstants.SEPARATOR_OF_STATEMENTS: + { + lb.lineCount++; + delta--; + } + break; + } + } + } + while ((delta>0) && (oldDelta>delta)); + + do + { + oldDelta = delta; + + for (int i=lastIndex; (i>=firstIndex) && (delta>0); i--) + { + LayoutBlock lb = layoutBlockList.get(i); + + switch (lb.tag) + { + case LayoutBlockConstants.CASE_BLOCK_END: + if (lb.lineCount < lb.maximalLineCount) + { + lb.lineCount++; + delta--; + } + break; + } + } + } + while ((delta>0) && (oldDelta>delta)); + + do + { + oldDelta = delta; + + // Compact fin de bloc des methodes + for (int i=firstIndex; (i<=lastIndex) && (delta>0); i++) + { + LayoutBlock lb = layoutBlockList.get(i); + + switch (lb.tag) + { + case LayoutBlockConstants.INNER_TYPE_BODY_BLOCK_END: + case LayoutBlockConstants.TYPE_BODY_BLOCK_END: + case LayoutBlockConstants.METHOD_BODY_SINGLE_LINE_BLOCK_END: + case LayoutBlockConstants.METHOD_BODY_BLOCK_END: + case LayoutBlockConstants.STATEMENTS_BLOCK_END: + case LayoutBlockConstants.SINGLE_STATEMENT_BLOCK_END: + case LayoutBlockConstants.SWITCH_BLOCK_END: + if (lb.lineCount < lb.maximalLineCount) + { + // BlockLayoutBlock blb = (BlockLayoutBlock)lb; + + // Expand end block + lb.lineCount++; + delta--; +// if (delta < 2) +// { +// lb.lineCount += delta; +// delta = 0; +// } +// else +// { +// delta -= 2 - lb.lineCount; +// lb.lineCount = 2; +// } + + // // Expand start block + // if (blb.other.lineCount == 0) + // { + // if (blb.section == blb.other.section) + // { + // if (delta > 0) + // { + // blb.other.lineCount++; + // delta--; + // } + // } + // else + // { + // blb.other.section.relayout = true; + // blb.other.lineCount = 1; + // } + // } + } + } + } + + // Expand debut de bloc du corps des classes internes + for (int i=firstIndex; (i<=lastIndex) && (delta>0); i++) + { + LayoutBlock lb = layoutBlockList.get(i); + + switch (lb.tag) + { + case LayoutBlockConstants.INNER_TYPE_BODY_BLOCK_START: + case LayoutBlockConstants.TYPE_BODY_BLOCK_START: + case LayoutBlockConstants.METHOD_BODY_SINGLE_LINE_BLOCK_START: + case LayoutBlockConstants.METHOD_BODY_BLOCK_START: + case LayoutBlockConstants.STATEMENTS_BLOCK_START: + case LayoutBlockConstants.SINGLE_STATEMENT_BLOCK_START: + case LayoutBlockConstants.SWITCH_BLOCK_START: + if (lb.lineCount < lb.maximalLineCount) + { + BlockLayoutBlock blb = (BlockLayoutBlock)lb; + + // Expand start block + lb.lineCount++; + delta--; + + if ((lb.lineCount > 1) && (blb.other.lineCount == 0)) + { + // Expand end block + if (blb.section == blb.other.section) // yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy + { + if (delta > 0) + { + blb.other.lineCount = 1; + delta--; + } + } + else + { + blb.other.section.relayout = true; + blb.other.lineCount = 1; + } + } + } + } + } + } + while ((delta>0) && (oldDelta>delta)); + +// do +// { +// oldDelta = delta; +// +// // Expand +// for (int i=firstIndex; (i<=lastIndex) && (delta>0); i++) +// { +// LayoutBlock lb = layoutBlockList.get(i); +// +// if (lb.lineCount < lb.maximalLineCount) +// { +// lb.lineCount++; +// delta--; +// } +// } +// } +// while ((delta>0) && (oldDelta>delta)); + } + + private static void CompactBlocks( + ArrayList layoutBlockList, + int firstIndex, int lastIndex, int delta) + { + int oldDelta; + + do + { + oldDelta = delta; + + for (int i=lastIndex; (i>=firstIndex) && (delta>0); i--) + { + LayoutBlock lb = layoutBlockList.get(i); + + if (lb.lineCount > lb.minimalLineCount) + { + lb.lineCount--; + delta--; + } + } + } + while ((delta>0) && (oldDelta>delta)); + } + + private static void ExpandBlocks( + ArrayList layoutBlockList, + int firstIndex, int lastIndex, int delta) + { + int oldDelta; + + do + { + oldDelta = delta; + + for (int i=firstIndex; (i<=lastIndex) && (delta>0); i++) + { + LayoutBlock lb = layoutBlockList.get(i); + + if (lb.lineCount < lb.maximalLineCount) + { + lb.lineCount++; + delta--; + } + } + } + while ((delta>0) && (oldDelta>delta)); + } + + /* + * Score = sum( + * - (separator.lineCount)^2 + * + (sum(block.lineCount==0)) + * ) + */ + private static void ScoreSections( + ArrayList layoutBlockList, + ArrayList layoutSectionList) + { + int sectionLength = layoutSectionList.size(); + + if (sectionLength > 0) + { + sectionLength--; + + for (int sectionIndex=0; sectionIndex 0) + { + score += sumScore*sumScore; + sumScore = 0; + } + } + else if (lb.lineCount > lb.preferedLineCount) + { + int delta = lb.lineCount - lb.preferedLineCount; + score -= delta*delta; + } + } + } + + score += sumScore*sumScore; + + // DEBUG // System.err.println("score = " + score); + section.score = score; + } + } + + // DEBUG // System.err.println(); + } + + /** + * @param layoutBlockList + * @param layoutSectionList + * @return true si des bloques ont ete deplaces + */ + private static boolean SliceDownBlocks( + ArrayList layoutBlockList, + ArrayList layoutSectionList) + { + // Identifier la section avec le plus haut score c.a.d. la section + // sur laquelle il faut relacher des contraintes. + int sectionLenght = layoutSectionList.size(); + + ArrayList sortedLayoutSectionList = + new ArrayList(sectionLenght); + sortedLayoutSectionList.addAll(layoutSectionList); + + Collections.sort(sortedLayoutSectionList); + + for (int sectionSourceIndex = 0; + sectionSourceIndex < sectionLenght; + sectionSourceIndex++) + { + // Section source + LayoutSection lsSource = + sortedLayoutSectionList.get(sectionSourceIndex); + + if (lsSource.score <= 0) + break; + + if (SliceDownBlocks( + layoutBlockList, layoutSectionList, + sectionSourceIndex, lsSource)) + return true; + } + + return false; + } + + private static boolean SliceUpBlocks( + ArrayList layoutBlockList, + ArrayList layoutSectionList) + { + // Identifier la section avec le plus haut score c.a.d. la section + // sur laquelle il faut relacher des contraintes. + int sectionLenght = layoutSectionList.size(); + + ArrayList sortedLayoutSectionList = + new ArrayList(sectionLenght); + sortedLayoutSectionList.addAll(layoutSectionList); + + Collections.sort(sortedLayoutSectionList); + + for (int sectionSourceIndex = 0; + sectionSourceIndex < sectionLenght; + sectionSourceIndex++) + { + // Section source + LayoutSection lsSource = + sortedLayoutSectionList.get(sectionSourceIndex); + + if (lsSource.score <= 0) + break; + + if (SliceUpBlocks( + layoutBlockList, layoutSectionList, + sectionSourceIndex, lsSource)) + return true; + } + + return false; + } + + /** + * @param layoutBlockList + * @param layoutSectionList + * @param lsSource + * @return true si des bloques ont ete deplaces + */ + private static boolean SliceDownBlocks( + ArrayList layoutBlockList, + ArrayList layoutSectionList, + int sectionSourceIndex, LayoutSection lsSource) + { + // Slice down. Detect type of last block + int firstBlockIndex = lsSource.firstBlockIndex; + int blockIndex; + + for (blockIndex = lsSource.lastBlockIndex; + blockIndex >= firstBlockIndex; + blockIndex--) + { + LayoutBlock lb = layoutBlockList.get(blockIndex); + + switch (lb.tag) + { + case LayoutBlockConstants.TYPE_MARKER_START: + // Found + // Slice last method block + if (SliceDownBlocks( + layoutBlockList, layoutSectionList, + sectionSourceIndex, blockIndex, lsSource, + LayoutBlockConstants.METHOD_MARKER_START, + LayoutBlockConstants.METHOD_MARKER_END)) + return true; + // Slice last field block + if (SliceDownBlocks( + layoutBlockList, layoutSectionList, + sectionSourceIndex, blockIndex, lsSource, + LayoutBlockConstants.FIELD_MARKER_START, + LayoutBlockConstants.FIELD_MARKER_END)) + return true; + + break; + case LayoutBlockConstants.FIELD_MARKER_START: + // Found + // Slice last inner class block + if (SliceDownBlocks( + layoutBlockList, layoutSectionList, + sectionSourceIndex, blockIndex, lsSource, + LayoutBlockConstants.TYPE_MARKER_START, + LayoutBlockConstants.TYPE_MARKER_END)) + return true; + // Slice last method block + if (SliceDownBlocks( + layoutBlockList, layoutSectionList, + sectionSourceIndex, blockIndex, lsSource, + LayoutBlockConstants.METHOD_MARKER_START, + LayoutBlockConstants.METHOD_MARKER_END)) + return true; + + break; + case LayoutBlockConstants.METHOD_MARKER_START: + // Found + // Slice last inner class block + if (SliceDownBlocks( + layoutBlockList, layoutSectionList, + sectionSourceIndex, blockIndex, lsSource, + LayoutBlockConstants.TYPE_MARKER_START, + LayoutBlockConstants.TYPE_MARKER_END)) + return true; + // Slice last field block + if (SliceDownBlocks( + layoutBlockList, layoutSectionList, + sectionSourceIndex, blockIndex, lsSource, + LayoutBlockConstants.FIELD_MARKER_START, + LayoutBlockConstants.FIELD_MARKER_END)) + return true; + + break; + } + } + + return false; + } + + /** + * @param layoutBlockList + * @param layoutSectionList + * @param sectionSourceIndex + * @param firstBlockIndex + * @param blockIndex + * @param markerStartTag + * @param markerEndTag + * @return true si des bloques ont ete deplaces + */ + private static boolean SliceDownBlocks( + ArrayList layoutBlockList, + ArrayList layoutSectionList, + int sectionSourceIndex, int blockIndex, + LayoutSection lsSource, int markerStartTag, int markerEndTag) + { + // Rechercher le dernier block de type 'tag' + int firstBlockIndex = lsSource.firstBlockIndex; + + while (firstBlockIndex < blockIndex) + { + LayoutBlock lb = layoutBlockList.get(--blockIndex); + + if (lb.tag == markerEndTag) + { + // Tag de marqueur de fin trouv�. + MarkerLayoutBlock mlb = (MarkerLayoutBlock)lb; + + if (mlb.section != mlb.other.section) + { + // Le marqueur de d�but et le marqueur de fin ne font pas + // parti de la m�me section -> l'un des blocs entre eux deux + // a un numero de ligne connu -> blocs indeplacables. + return false; + } + if (mlb.other.index <= firstBlockIndex) + { + // Le marqueur de debut est avant la limite. + return false; + } + + // Trouv�. + + // -- 1 ----------------------------------------------------- // + int lastEndTagBlockIndex = blockIndex; + + // Rechercher du nombre de blocs a deplacer => + // Trouver le premier block de type 'tag' sans numero de ligne + int counter = 1; + + blockIndex = mlb.other.index; + + while (firstBlockIndex < blockIndex) + { + lb = layoutBlockList.get(--blockIndex); + + if ((lb.tag == LayoutBlockConstants.TYPE_BODY_BLOCK_START) /* || + (lb.tag == LayoutBlockConstants.SEPARATOR_BEFORE_OR_AFTER_BLOCK) */) + { + break; + } + else if (lb.tag == markerEndTag) + { + // Tag de marqueur de fin trouv�. + mlb = (MarkerLayoutBlock)lb; + + if (mlb.section != mlb.other.section) + { + // Le marqueur de d�but et le marqueur de fin ne font pas + // parti de la m�me section -> l'un des blocs entre eux deux + // a un numero de ligne connu -> blocs indeplacables. + break; + } + if (mlb.other.index <= firstBlockIndex) + { + // Le marqueur de debut est avant la limite. + break; + } + + counter++; + blockIndex = mlb.other.index; + } + else if ((lb.tag == LayoutBlockConstants.FIELD_MARKER_END) || + (lb.tag == LayoutBlockConstants.METHOD_MARKER_END) || + (lb.tag == LayoutBlockConstants.TYPE_MARKER_END)) + { + break; + } + } + + // Un ou plusieurs blocs a deplacer trouv�s. + + // Rechercher de l'index d'insertion => + // Trouver la section ayant le score le plus bas jusqu'a la + // section contenant un block de type 'tag' ayant un numero + // de ligne defini + int blockLenght = layoutBlockList.size(); + blockIndex = lastEndTagBlockIndex; + + int lowerScore = lsSource.score; + int lowerScoreBlockIndex = blockIndex; + + while (++blockIndex < blockLenght) + { + lb = layoutBlockList.get(blockIndex); + + if ((lb.tag == LayoutBlockConstants.TYPE_BODY_BLOCK_END) || +// (lb.tag == LayoutBlockConstants.SEPARATOR_BEFORE_OR_AFTER_BLOCK) || + (lb.tag == markerStartTag)) + { + // Fin de corps ou debut d'un bloc + if (lowerScore > lb.section.score) + { + lowerScore = lb.section.score; + lowerScoreBlockIndex = blockIndex; + } + + // Impossible de deplacer un bloc au dessus + // - d'une fin de corps + // - d'un autre du meme type + // => On s'arrete. + break; + } + else if ((lb.tag == LayoutBlockConstants.FIELD_MARKER_START) || + (lb.tag == LayoutBlockConstants.METHOD_MARKER_START) || + (lb.tag == LayoutBlockConstants.TYPE_MARKER_START)) + { + // Debut d'un bloc d'un type different + if ((lb.section != null) && + (lowerScore > lb.section.score)) + { + lowerScore = lb.section.score; + lowerScoreBlockIndex = blockIndex; + } + + blockIndex = ((MarkerLayoutBlock)lb).other.index; + } + } + + if (lowerScore != lsSource.score) + { + // Trouv�. + + // -- 2 ------------------------------------------------- // + + // Rechercher de l'index de debut du bloc de type 'tag' + // counter/2 en partant de 'lastEndTagBlockIndex' + counter = (counter + 1) / 2; + int firstStartTagBlockIndex = + blockIndex = lastEndTagBlockIndex; + + while (firstBlockIndex < blockIndex) + { + lb = layoutBlockList.get(blockIndex); + + if ((lb.tag == LayoutBlockConstants.TYPE_BODY_BLOCK_START) /* || + (lb.tag == LayoutBlockConstants.SEPARATOR_BEFORE_OR_AFTER_BLOCK)*/) + { + break; + } + else if (lb.tag == markerEndTag) + { + firstStartTagBlockIndex = blockIndex = + ((MarkerLayoutBlock)lb).other.index; + + if (--counter == 0) + break; + } + + blockIndex--; + } + + // Trouv�. + + // -- 3 ------------------------------------------------- // + + // Deplacer la moitier des blocks de type 'tag' de + // 'firstStartTagBlockIndex' a 'lastEndTagBlockIndex' + // vers 'lowerScoreBlockIndex' + + LayoutBlock insertionLayoutBlock = + layoutBlockList.get(lowerScoreBlockIndex); + LayoutSection lsTarget = insertionLayoutBlock.section; + + // Remove blocks + int sourceDeltaIndex = + lastEndTagBlockIndex - firstStartTagBlockIndex + 1; + ArrayList layoutBlockListToMove = + new ArrayList(sourceDeltaIndex); + + for (blockIndex=lastEndTagBlockIndex; + blockIndex>=firstStartTagBlockIndex; + blockIndex--) + { + lb = layoutBlockList.remove(blockIndex); + + // Update section attribute + lb.section = lsTarget; + + layoutBlockListToMove.add(lb); + } + + Collections.reverse(layoutBlockListToMove); + + // Remove separator after blocks if exists + if (layoutBlockList.get(blockIndex+1).tag == + LayoutBlockConstants.SEPARATOR) + { + layoutBlockList.remove(blockIndex+1); + sourceDeltaIndex++; } + + // Modify separator brefore blocks if exists + if (layoutBlockList.get(blockIndex).tag == + LayoutBlockConstants.SEPARATOR) + { + layoutBlockList.get(blockIndex).preferedLineCount = 2; + } + + // Blocs pas encore inser�s. + lowerScoreBlockIndex -= sourceDeltaIndex; + + int targetDeltaIndex = 0; + + if ((insertionLayoutBlock.tag == LayoutBlockConstants.TYPE_BODY_BLOCK_END) /*|| + (insertionLayoutBlock.tag == LayoutBlockConstants.SEPARATOR_BEFORE_OR_AFTER_BLOCK)*/) + { + // Insert new separator before blocks + int preferedLineCount = 2; + + if ((markerEndTag == LayoutBlockConstants.FIELD_MARKER_END) && + (layoutBlockList.get(lowerScoreBlockIndex-1).tag == + LayoutBlockConstants.FIELD_MARKER_END)) + { + preferedLineCount = 1; + } + + layoutBlockList.add( + lowerScoreBlockIndex, + new SeparatorLayoutBlock( + LayoutBlockConstants.SEPARATOR, + preferedLineCount)); + + targetDeltaIndex++; + } + else + { + // Update separator before blocks + LayoutBlock beforeLayoutBlock = + layoutBlockList.get(lowerScoreBlockIndex-1); + + int preferedLineCount = 2; + + if ((markerEndTag == LayoutBlockConstants.FIELD_MARKER_END) && + (layoutBlockList.get(lowerScoreBlockIndex-2).tag == + LayoutBlockConstants.FIELD_MARKER_END)) + { + preferedLineCount = 1; + } + + beforeLayoutBlock.preferedLineCount = preferedLineCount; + } + + // Insert blocks + int layoutBlockListToMoveSize = layoutBlockListToMove.size(); + + layoutBlockList.addAll( + lowerScoreBlockIndex+targetDeltaIndex, + layoutBlockListToMove); + + targetDeltaIndex += layoutBlockListToMoveSize; + + // Add separator after blocks + if ((insertionLayoutBlock.tag != LayoutBlockConstants.TYPE_BODY_BLOCK_END) /*&& + (insertionLayoutBlock.tag != LayoutBlockConstants.SEPARATOR_BEFORE_OR_AFTER_BLOCK)*/) + { + int preferedLineCount = 2; + + if (markerStartTag == LayoutBlockConstants.FIELD_MARKER_START) + { + preferedLineCount = 1; + } + + layoutBlockList.add( + lowerScoreBlockIndex+targetDeltaIndex, + new SeparatorLayoutBlock( + LayoutBlockConstants.SEPARATOR, + preferedLineCount)); + + targetDeltaIndex++; + } + + // -- 4 ------------------------------------------------- // + + // Update indexes of sections + lsSource.lastBlockIndex -= sourceDeltaIndex; + + for (int sectionIndex=lsSource.index+1; + sectionIndex<=lsTarget.index-1; + sectionIndex++) + { + LayoutSection ls = layoutSectionList.get(sectionIndex); + ls.firstBlockIndex -= sourceDeltaIndex; + ls.lastBlockIndex -= sourceDeltaIndex; + } + + lsTarget.firstBlockIndex -= sourceDeltaIndex; + + int delta = sourceDeltaIndex - targetDeltaIndex; + + if (delta != 0) + { + lsTarget.lastBlockIndex -= delta; + + // Update indexes of last sections + for (int sectionIndex=layoutSectionList.size()-1; + sectionIndex>lsTarget.index; + sectionIndex--) + { + LayoutSection ls = layoutSectionList.get(sectionIndex); + ls.firstBlockIndex -= delta; + ls.lastBlockIndex -= delta; + } + } + + // Update index of blocks + blockLenght = layoutBlockList.size(); + + for (blockIndex=firstStartTagBlockIndex; + blockIndex layoutBlockList, + ArrayList layoutSectionList, + int sectionSourceIndex, LayoutSection lsSource) + { + // Slice up. Detect type of last block + int lastBlockIndex = lsSource.lastBlockIndex; + int blockIndex; + + for (blockIndex = lsSource.firstBlockIndex; + blockIndex <= lastBlockIndex; + blockIndex++) + { + LayoutBlock lb = layoutBlockList.get(blockIndex); + + switch (lb.tag) + { + case LayoutBlockConstants.TYPE_MARKER_END: + // Found + // Slice last method block + // Slice last field block + if (SliceUpBlocks( + layoutBlockList, layoutSectionList, + sectionSourceIndex, blockIndex, lsSource, + LayoutBlockConstants.FIELD_MARKER_START, + LayoutBlockConstants.FIELD_MARKER_END)) + return true; + if (SliceUpBlocks( + layoutBlockList, layoutSectionList, + sectionSourceIndex, blockIndex, lsSource, + LayoutBlockConstants.METHOD_MARKER_START, + LayoutBlockConstants.METHOD_MARKER_END)) + return true; + + return false; + case LayoutBlockConstants.FIELD_MARKER_END: + // Found + // Slice last method block + if (SliceUpBlocks( + layoutBlockList, layoutSectionList, + sectionSourceIndex, blockIndex, lsSource, + LayoutBlockConstants.METHOD_MARKER_START, + LayoutBlockConstants.METHOD_MARKER_END)) + return true; + // Slice last inner class block + if (SliceUpBlocks( + layoutBlockList, layoutSectionList, + sectionSourceIndex, blockIndex, lsSource, + LayoutBlockConstants.TYPE_MARKER_START, + LayoutBlockConstants.TYPE_MARKER_END)) + return true; + + return false; + case LayoutBlockConstants.METHOD_MARKER_END: + // Found + // Slice last field block + if (SliceUpBlocks( + layoutBlockList, layoutSectionList, + sectionSourceIndex, blockIndex, lsSource, + LayoutBlockConstants.FIELD_MARKER_START, + LayoutBlockConstants.FIELD_MARKER_END)) + return true; + // Slice last inner class block + if (SliceUpBlocks( + layoutBlockList, layoutSectionList, + sectionSourceIndex, blockIndex, lsSource, + LayoutBlockConstants.TYPE_MARKER_START, + LayoutBlockConstants.TYPE_MARKER_END)) + return true; + + return false; + } + } + + return false; + } + + /** + * @param layoutBlockList + * @param layoutSectionList + * @param sectionSourceIndex + * @param firstBlockIndex + * @param blockIndex + * @param markerStartTag + * @param markerEndTag + * @return true si des bloques ont ete deplaces + */ + private static boolean SliceUpBlocks( + ArrayList layoutBlockList, + ArrayList layoutSectionList, + int sectionSourceIndex, int blockIndex, + LayoutSection lsSource, int markerStartTag, int markerEndTag) + { + // Rechercher le premier block de type 'tag' + int lastBlockIndex = lsSource.lastBlockIndex; + + while (blockIndex < lastBlockIndex) + { + LayoutBlock lb = layoutBlockList.get(++blockIndex); + + if (lb.tag == markerStartTag) + { + // Tag de marqueur de debut trouv�. + MarkerLayoutBlock mlb = (MarkerLayoutBlock)lb; + + if (mlb.section != mlb.other.section) + { + // Le marqueur de d�but et le marqueur de fin ne font pas + // parti de la m�me section -> l'un des blocs entre eux deux + // a un numero de ligne connu -> blocs indeplacables. + return false; + } + if (mlb.other.index >= lastBlockIndex) + { + // Le marqueur de fin est apres la limite. + return false; + } + + // Trouv�. + + // -- 1 ----------------------------------------------------- // + int firstStartTagBlockIndex = blockIndex; + + // Rechercher du nombre de blocs a deplacer => + // Trouver le dernier block de type 'tag' sans numero de ligne + int counter = 1; + + blockIndex = mlb.other.index; + + while (blockIndex < lastBlockIndex) + { + lb = layoutBlockList.get(++blockIndex); + + if ((lb.tag == LayoutBlockConstants.TYPE_BODY_BLOCK_END) /*|| + (lb.tag == LayoutBlockConstants.SEPARATOR_BEFORE_OR_AFTER_BLOCK)*/) + { + break; + } + else if (lb.tag == markerStartTag) + { + // Tag de marqueur de fin trouv�. + mlb = (MarkerLayoutBlock)lb; + + if (mlb.section != mlb.other.section) + { + // Le marqueur de d�but et le marqueur de fin ne font pas + // parti de la m�me section -> l'un des blocs entre eux deux + // a un numero de ligne connu -> blocs indeplacables. + break; + } + if (mlb.other.index >= lastBlockIndex) + { + // Le marqueur de debut est avant la limite. + break; + } + + counter++; + blockIndex = mlb.other.index; + } + else if ((lb.tag == LayoutBlockConstants.FIELD_MARKER_START) || + (lb.tag == LayoutBlockConstants.METHOD_MARKER_START) || + (lb.tag == LayoutBlockConstants.TYPE_MARKER_START)) + { + break; + } + } + + // Un ou plusieurs blocs a deplacer trouv�s. + + // Rechercher de l'index d'insertion => + // Trouver la section ayant le score le plus bas jusqu'a la + // section contenant un block de type 'tag' ayant un numero + // de ligne defini + blockIndex = firstStartTagBlockIndex; + + int lowerScore = lsSource.score; + int lowerScoreBlockIndex = blockIndex; + + while (blockIndex-- > 0) + { + lb = layoutBlockList.get(blockIndex); + + if ((lb.tag == LayoutBlockConstants.TYPE_BODY_BLOCK_START) || +// (lb.tag == LayoutBlockConstants.SEPARATOR_BEFORE_OR_AFTER_BLOCK) || + (lb.tag == markerEndTag)) + { + // debut de corps ou fin d'un bloc + if (lowerScore > lb.section.score) + { + lowerScore = lb.section.score; + lowerScoreBlockIndex = blockIndex; + } + + // Impossible de deplacer un bloc au dessus + // - d'un debut de corps + // - d'un autre du meme type + // => On s'arrete. + break; + } + else if ((lb.tag == LayoutBlockConstants.FIELD_MARKER_END) || + (lb.tag == LayoutBlockConstants.METHOD_MARKER_END) || + (lb.tag == LayoutBlockConstants.TYPE_MARKER_END)) + { + // Fin d'un bloc d'un type different + if ((lb.section != null) && + (lowerScore > lb.section.score)) + { + lowerScore = lb.section.score; + lowerScoreBlockIndex = blockIndex; + } + + blockIndex = ((MarkerLayoutBlock)lb).other.index; + } + } + + if (lowerScore != lsSource.score) + { + // Trouv�. + + // -- 2 ------------------------------------------------- // + + // Rechercher de l'index de debut du bloc de type 'tag' + // counter/2 en partant de 'lastEndTagBlockIndex' + counter = (counter + 1) / 2; + int lastEndTagBlockIndex = + blockIndex = firstStartTagBlockIndex; + + while (blockIndex > 0) + { + lb = layoutBlockList.get(blockIndex); + + if ((lb.tag == LayoutBlockConstants.TYPE_BODY_BLOCK_END) /*|| + (lb.tag == LayoutBlockConstants.SEPARATOR_BEFORE_OR_AFTER_BLOCK)*/) + { + break; + } + else if (lb.tag == markerStartTag) + { + lastEndTagBlockIndex = blockIndex = + ((MarkerLayoutBlock)lb).other.index; + + if (--counter == 0) + break; + } + + blockIndex++; + } + + // Trouv�. + + // -- 3 ------------------------------------------------- // + + // Deplacer la moitier des blocks de type 'tag' de + // 'firstStartTagBlockIndex' a 'lastEndTagBlockIndex' + // vers 'lowerScoreBlockIndex' + + LayoutBlock insertionLayoutBlock = + layoutBlockList.get(lowerScoreBlockIndex); + LayoutSection lsTarget = insertionLayoutBlock.section; + + // Remove blocks + int sourceDeltaIndex = + lastEndTagBlockIndex - firstStartTagBlockIndex + 1; + ArrayList layoutBlockListToMove = + new ArrayList(sourceDeltaIndex); + + for (blockIndex=lastEndTagBlockIndex; + blockIndex>=firstStartTagBlockIndex; + blockIndex--) + { + lb = layoutBlockList.remove(blockIndex); + + // Update section attribute + lb.section = lsTarget; + + layoutBlockListToMove.add(lb); + } + + Collections.reverse(layoutBlockListToMove); + + // Remove separator after blocks if exists + if (layoutBlockList.get(blockIndex+1).tag == + LayoutBlockConstants.SEPARATOR) + { + layoutBlockList.remove(blockIndex+1); + sourceDeltaIndex++; + } + + // Modify separator brefore blocks if exists + if (layoutBlockList.get(blockIndex).tag == + LayoutBlockConstants.SEPARATOR) + { + layoutBlockList.get(blockIndex).preferedLineCount = 2; + } + + // Blocs pas encore inser�s. + lowerScoreBlockIndex++; + + int targetDeltaIndex = 0; + + if ((insertionLayoutBlock.tag != LayoutBlockConstants.TYPE_BODY_BLOCK_START) /*&& + (insertionLayoutBlock.tag != LayoutBlockConstants.SEPARATOR_BEFORE_OR_AFTER_BLOCK)*/) + { + // Insert new separator before blocks + int preferedLineCount = 2; + + if (markerEndTag == LayoutBlockConstants.FIELD_MARKER_END) + { + preferedLineCount = 1; + } + + layoutBlockList.add( + lowerScoreBlockIndex, + new SeparatorLayoutBlock( + LayoutBlockConstants.SEPARATOR, + preferedLineCount)); + + targetDeltaIndex++; + } + + // Insert blocks + int layoutBlockListToMoveSize = layoutBlockListToMove.size(); + + layoutBlockList.addAll( + lowerScoreBlockIndex+targetDeltaIndex, + layoutBlockListToMove); + + targetDeltaIndex += layoutBlockListToMoveSize; + + // Update separator after blocks + if ((insertionLayoutBlock.tag == LayoutBlockConstants.TYPE_BODY_BLOCK_START) /*|| + (insertionLayoutBlock.tag == LayoutBlockConstants.SEPARATOR_BEFORE_OR_AFTER_BLOCK)*/) + { + // Insert new separator after blocks + int preferedLineCount = 2; + + if ((markerEndTag == LayoutBlockConstants.FIELD_MARKER_END) && + (layoutBlockList.get(lowerScoreBlockIndex+targetDeltaIndex).tag == + LayoutBlockConstants.FIELD_MARKER_END)) + { + preferedLineCount = 1; + } + + layoutBlockList.add( + lowerScoreBlockIndex+targetDeltaIndex, + new SeparatorLayoutBlock( + LayoutBlockConstants.SEPARATOR, + preferedLineCount)); + + targetDeltaIndex++; + } + else + { + // Update separator after blocks + LayoutBlock afterLayoutBlock = + layoutBlockList.get(lowerScoreBlockIndex+targetDeltaIndex); + + int preferedLineCount = 2; + + if ((markerStartTag == LayoutBlockConstants.FIELD_MARKER_START) && + (layoutBlockList.get(lowerScoreBlockIndex+targetDeltaIndex+1).tag == + LayoutBlockConstants.FIELD_MARKER_START)) + { + preferedLineCount = 1; + } + + afterLayoutBlock.preferedLineCount = preferedLineCount; + } + + // -- 4 ------------------------------------------------- // + + // Update indexes of sections + lsTarget.lastBlockIndex += targetDeltaIndex; + + for (int sectionIndex=lsTarget.index+1; + sectionIndex<=lsSource.index-1; + sectionIndex++) + { + LayoutSection ls = layoutSectionList.get(sectionIndex); + ls.firstBlockIndex += targetDeltaIndex; + ls.lastBlockIndex += targetDeltaIndex; + } + + lsSource.firstBlockIndex += targetDeltaIndex; + + int delta = sourceDeltaIndex - targetDeltaIndex; + + if (delta != 0) + { + lsSource.lastBlockIndex -= delta; + + // Update indexes of last sections + for (int sectionIndex=layoutSectionList.size()-1; + sectionIndex>lsSource.index; + sectionIndex--) + { + LayoutSection ls = layoutSectionList.get(sectionIndex); + ls.firstBlockIndex -= delta; + ls.lastBlockIndex -= delta; + } + } + + // Update index of blocks + int blockLenght = layoutBlockList.size(); + + for (blockIndex=lowerScoreBlockIndex; + blockIndex layoutBlockList, LayoutSection section) + { + section.relayout = true; + + int lastBlockIndex = section.lastBlockIndex; + + for (int blockIndex=section.firstBlockIndex; + blockIndex layoutBlockList, ClassFile classFile, + Method method, List list) + { + int length = list.size(); + boolean singleLine = false; + + for (int index=0; index 0) + { + layoutBlockList.add(new SeparatorLayoutBlock( + LayoutBlockConstants.SEPARATOR_OF_STATEMENTS, 1)); + } + + switch (instruction.opcode) + { + case FastConstants.WHILE: + createBlockForFastTestList( + preferences, LayoutBlockConstants.FRAGMENT_WHILE, + layoutBlockList, classFile, method, + (FastTestList)instruction, true); + break; + case FastConstants.DO_WHILE: + createBlocksForDoWhileLoop( + preferences, layoutBlockList, classFile, + method, (FastTestList)instruction); + break; + case FastConstants.INFINITE_LOOP: + createBlocksForInfiniteLoop( + preferences, layoutBlockList, classFile, + method, (FastList)instruction); + break; + case FastConstants.FOR: + createBlocksForForLoop( + preferences, layoutBlockList, classFile, + method, (FastFor)instruction); + break; + case FastConstants.FOREACH: + createBlockForFastForEach( + preferences, layoutBlockList, classFile, + method, (FastForEach)instruction); + break; + case FastConstants.IF_: + createBlockForFastTestList( + preferences, LayoutBlockConstants.FRAGMENT_IF, + layoutBlockList, classFile, method, + (FastTestList)instruction, true); + break; + case FastConstants.IF_ELSE: + FastTest2Lists ft2l = (FastTest2Lists)instruction; + createBlocksForIfElse( + preferences, layoutBlockList, classFile, method, + ft2l, ShowSingleInstructionBlock(ft2l)); + break; + case FastConstants.IF_CONTINUE: + case FastConstants.IF_BREAK: + createBlocksForIfContinueOrBreak( + preferences, layoutBlockList, classFile, + method, (FastInstruction)instruction); + break; + case FastConstants.IF_LABELED_BREAK: + createBlocksForIfLabeledBreak( + preferences, layoutBlockList, classFile, + method, (FastInstruction)instruction); + break; +// case FastConstants.GOTO_CONTINUE: +// CreateBlocksForGotoContinue(layoutBlockList); +// case FastConstants.GOTO_BREAK: +// CreateBlocksForGotoBreak(layoutBlockList); +// break; + case FastConstants.GOTO_LABELED_BREAK: + CreateBlocksForGotoLabeledBreak( + layoutBlockList, classFile, method, + (FastInstruction)instruction); + break; + case FastConstants.SWITCH: + createBlocksForSwitch( + preferences, layoutBlockList, classFile, method, + (FastSwitch)instruction, LayoutBlockConstants.FRAGMENT_CASE); + break; + case FastConstants.SWITCH_ENUM: + createBlocksForSwitchEnum( + preferences, layoutBlockList, classFile, method, + (FastSwitch)instruction); + break; + case FastConstants.SWITCH_STRING: + createBlocksForSwitch( + preferences, layoutBlockList, classFile, method, + (FastSwitch)instruction, + LayoutBlockConstants.FRAGMENT_CASE_STRING); + break; + case FastConstants.TRY: + createBlocksForTry( + preferences, layoutBlockList, classFile, + method, (FastTry)instruction); + break; + case FastConstants.SYNCHRONIZED: + createBlocksForSynchronized( + preferences, layoutBlockList, classFile, + method, (FastSynchronized)instruction); + break; + case FastConstants.LABEL: + createBlocksForLabel( + preferences, layoutBlockList, classFile, method, + (FastLabel)instruction); + break; + case FastConstants.DECLARE: + if (((FastDeclaration)instruction).instruction == null) + { + layoutBlockList.add(new DeclareLayoutBlock( + classFile, method, instruction)); + break; + } + default: + if (length == 1) + { + int min = instruction.lineNumber; + if (min != Instruction.UNKNOWN_LINE_NUMBER) + { + int max = MaxLineNumberVisitor.visit(instruction); + singleLine = (min == max); + } + } + + index = createBlockForInstructions( + preferences, layoutBlockList, + classFile, method, list, index); + break; + } + } + + return singleLine; + } + + private void createBlockForFastTestList( + Preferences preferences, + byte tag, List layoutBlockList, ClassFile classFile, + Method method, FastTestList ftl, boolean showSingleInstructionBlock) + { + layoutBlockList.add(new FragmentLayoutBlock(tag)); + + createBlockForInstruction( + preferences, layoutBlockList, classFile, method, ftl.test); + + layoutBlockList.add(new FragmentLayoutBlock( + LayoutBlockConstants.FRAGMENT_RIGHT_ROUND_BRACKET)); + + createBlockForSubList( + preferences, layoutBlockList, classFile, method, + ftl.instructions, showSingleInstructionBlock, 1); + } + + private void createBlocksForIfElse( + Preferences preferences, + List layoutBlockList, ClassFile classFile, Method method, + FastTest2Lists ft2l, boolean showSingleInstructionBlock) + { + layoutBlockList.add(new FragmentLayoutBlock( + LayoutBlockConstants.FRAGMENT_IF)); + + createBlockForInstruction( + preferences, layoutBlockList, classFile, method, ft2l.test); + + layoutBlockList.add(new FragmentLayoutBlock( + LayoutBlockConstants.FRAGMENT_RIGHT_ROUND_BRACKET)); + + List instructions = ft2l.instructions; + + if (instructions.size() == 1) + { + switch (instructions.get(0).opcode) + { + case FastConstants.IF_: + case FastConstants.IF_ELSE: + createBlockForSubList( + preferences, layoutBlockList, classFile, + method, instructions, false, 2); + break; + default: + createBlockForSubList( + preferences, layoutBlockList, classFile, method, + instructions, showSingleInstructionBlock, 2); + break; + } + } + else + { + createBlockForSubList( + preferences, layoutBlockList, classFile, method, + instructions, showSingleInstructionBlock, 2); + } + + List instructions2 = ft2l.instructions2; + + if (instructions2.size() == 1) + { + Instruction instruction = instructions2.get(0); + + // Write 'else if' + switch (instruction.opcode) + { + case FastConstants.IF_: + layoutBlockList.add(new FragmentLayoutBlock( + LayoutBlockConstants.FRAGMENT_ELSE_SPACE)); + + createBlockForFastTestList( + preferences, LayoutBlockConstants.FRAGMENT_IF, layoutBlockList, + classFile, method, (FastTestList)instruction, + showSingleInstructionBlock); + return; + case FastConstants.IF_ELSE: + layoutBlockList.add(new FragmentLayoutBlock( + LayoutBlockConstants.FRAGMENT_ELSE_SPACE)); + + createBlocksForIfElse( + preferences, layoutBlockList, classFile, method, + (FastTest2Lists)instruction, showSingleInstructionBlock); + return; + } + } + + layoutBlockList.add(new FragmentLayoutBlock( + LayoutBlockConstants.FRAGMENT_ELSE)); + + createBlockForSubList( + preferences, layoutBlockList, classFile, method, + instructions2, showSingleInstructionBlock, 1); + } + + // Show single instruction block ? + private static boolean ShowSingleInstructionBlock(FastTest2Lists ifElse) + { + for (;;) + { + List instructions = ifElse.instructions; + if ((instructions != null) && (instructions.size() >= 2)) + return false; + + int instructions2Size = ifElse.instructions2.size(); + + if (instructions2Size == 0) + return true; + + if (instructions2Size >= 2) + return false; + + if (instructions2Size == 1) + { + Instruction instruction = ifElse.instructions2.get(0); + + if (instruction.opcode == FastConstants.IF_) + { + instructions = ((FastTestList)instruction).instructions; + return (instructions == null) || (instructions.size() < 2); + } + else if (instruction.opcode == FastConstants.IF_ELSE) + { + ifElse = (FastTest2Lists)instruction; + } + else + { + return true; + } + } + } + } + + private void createBlocksForDoWhileLoop( + Preferences preferences, List layoutBlockList, + ClassFile classFile, Method method, FastTestList ftl) + { + layoutBlockList.add(new FragmentLayoutBlock( + LayoutBlockConstants.FRAGMENT_DO)); + + createBlockForSubList( + preferences, layoutBlockList, classFile, + method, ftl.instructions, false, 1); + + layoutBlockList.add(new FragmentLayoutBlock( + LayoutBlockConstants.FRAGMENT_WHILE)); + + createBlockForInstruction( + preferences, layoutBlockList, classFile, method, ftl.test); + + layoutBlockList.add(new FragmentLayoutBlock( + LayoutBlockConstants.FRAGMENT_RIGHT_ROUND_BRACKET_SEMICOLON)); + } + + private void createBlocksForInfiniteLoop( + Preferences preferences, + List layoutBlockList, ClassFile classFile, + Method method, FastList fl) + { + layoutBlockList.add(new FragmentLayoutBlock( + LayoutBlockConstants.FRAGMENT_INFINITE_LOOP)); + + createBlockForSubList( + preferences, layoutBlockList, classFile, + method, fl.instructions, false, 1); + } + + private void createBlocksForForLoop( + Preferences preferences, List layoutBlockList, + ClassFile classFile, Method method, FastFor ff) + { + layoutBlockList.add(new FragmentLayoutBlock( + LayoutBlockConstants.FRAGMENT_FOR)); + + if (ff.init != null) + { + BlockLayoutBlock sblb = new BlockLayoutBlock( + LayoutBlockConstants.FOR_BLOCK_START, 0); + layoutBlockList.add(sblb); + + createBlockForInstruction( + preferences, layoutBlockList, classFile, method, ff.init); + + BlockLayoutBlock eblb = new BlockLayoutBlock( + LayoutBlockConstants.FOR_BLOCK_END, 0); + sblb.other = eblb; + eblb.other = sblb; + layoutBlockList.add(eblb); + } + + if (ff.test == null) + { + layoutBlockList.add(new FragmentLayoutBlock( + LayoutBlockConstants.FRAGMENT_SEMICOLON)); + } + else + { + layoutBlockList.add(new FragmentLayoutBlock( + LayoutBlockConstants.FRAGMENT_SEMICOLON_SPACE)); + + BlockLayoutBlock sblb = new BlockLayoutBlock( + LayoutBlockConstants.FOR_BLOCK_START, + 0, LayoutBlockConstants.UNLIMITED_LINE_COUNT, 0); + layoutBlockList.add(sblb); + + createBlockForInstruction( + preferences, layoutBlockList, classFile, method, ff.test); + + BlockLayoutBlock eblb = new BlockLayoutBlock( + LayoutBlockConstants.FOR_BLOCK_END, 0); + sblb.other = eblb; + eblb.other = sblb; + layoutBlockList.add(eblb); + } + + + if (ff.inc == null) + { + layoutBlockList.add(new FragmentLayoutBlock( + LayoutBlockConstants.FRAGMENT_SEMICOLON)); + } + else + { + layoutBlockList.add(new FragmentLayoutBlock( + LayoutBlockConstants.FRAGMENT_SEMICOLON_SPACE)); + + BlockLayoutBlock sblb = new BlockLayoutBlock( + LayoutBlockConstants.FOR_BLOCK_START, + 0, LayoutBlockConstants.UNLIMITED_LINE_COUNT, 0); + layoutBlockList.add(sblb); + + createBlockForInstruction( + preferences, layoutBlockList, classFile, method, ff.inc); + + BlockLayoutBlock eblb = new BlockLayoutBlock( + LayoutBlockConstants.FOR_BLOCK_END, 0); + sblb.other = eblb; + eblb.other = sblb; + layoutBlockList.add(eblb); + } + + layoutBlockList.add(new FragmentLayoutBlock( + LayoutBlockConstants.FRAGMENT_RIGHT_ROUND_BRACKET)); + + createBlockForSubList( + preferences, layoutBlockList, classFile, + method, ff.instructions, true, 1); + } + + private void createBlockForFastForEach( + Preferences preferences, List layoutBlockList, + ClassFile classFile, Method method, FastForEach ffe) + { + layoutBlockList.add(new FragmentLayoutBlock( + LayoutBlockConstants.FRAGMENT_FOR)); + + createBlockForInstruction( + preferences, layoutBlockList, classFile, method, ffe.variable); + + layoutBlockList.add(new FragmentLayoutBlock( + LayoutBlockConstants.FRAGMENT_SPACE_COLON_SPACE)); + + createBlockForInstruction( + preferences, layoutBlockList, classFile, method, ffe.values); + + layoutBlockList.add(new FragmentLayoutBlock( + LayoutBlockConstants.FRAGMENT_RIGHT_ROUND_BRACKET)); + + createBlockForSubList( + preferences, layoutBlockList, classFile, + method, ffe.instructions, true, 1); + } + + private void createBlocksForIfContinueOrBreak( + Preferences preferences, List layoutBlockList, + ClassFile classFile, Method method, FastInstruction fi) + { + layoutBlockList.add(new FragmentLayoutBlock( + LayoutBlockConstants.FRAGMENT_IF)); + + createBlockForInstruction( + preferences, layoutBlockList, classFile, method, fi.instruction); + + layoutBlockList.add(new FragmentLayoutBlock( + LayoutBlockConstants.FRAGMENT_RIGHT_ROUND_BRACKET)); + + SingleStatementBlockStartLayoutBlock ssbslb = + new SingleStatementBlockStartLayoutBlock(); + layoutBlockList.add(ssbslb); + + if (fi.opcode == FastConstants.IF_CONTINUE) + { + layoutBlockList.add(new FragmentLayoutBlock( + LayoutBlockConstants.FRAGMENT_CONTINUE)); + } + else + { + layoutBlockList.add(new FragmentLayoutBlock( + LayoutBlockConstants.FRAGMENT_BREAK)); + } + + SingleStatementBlockEndLayoutBlock ssbelb = + new SingleStatementBlockEndLayoutBlock(1); + ssbslb.other = ssbelb; + ssbelb.other = ssbslb; + layoutBlockList.add(ssbelb); + } + + private void createBlocksForIfLabeledBreak( + Preferences preferences, List layoutBlockList, + ClassFile classFile, Method method, FastInstruction fi) + { + layoutBlockList.add(new FragmentLayoutBlock( + LayoutBlockConstants.FRAGMENT_IF)); + + createBlockForInstruction( + preferences, layoutBlockList, classFile, method, fi.instruction); + + layoutBlockList.add(new FragmentLayoutBlock( + LayoutBlockConstants.FRAGMENT_RIGHT_ROUND_BRACKET)); + + SingleStatementBlockStartLayoutBlock ssbslb = + new SingleStatementBlockStartLayoutBlock(); + layoutBlockList.add(ssbslb); + + BranchInstruction bi = (BranchInstruction)fi.instruction; + + layoutBlockList.add(new OffsetLayoutBlock( + LayoutBlockConstants.FRAGMENT_LABELED_BREAK, + Instruction.UNKNOWN_LINE_NUMBER, + Instruction.UNKNOWN_LINE_NUMBER, + 0, 0, 0, + bi.GetJumpOffset())); + + SingleStatementBlockEndLayoutBlock ssbelb = + new SingleStatementBlockEndLayoutBlock(1); + ssbslb.other = ssbelb; + ssbelb.other = ssbslb; + layoutBlockList.add(ssbelb); + } + + private static void CreateBlocksForGotoLabeledBreak( + List layoutBlockList, ClassFile classFile, + Method method, FastInstruction fi) + { + BranchInstruction bi = (BranchInstruction)fi.instruction; + + layoutBlockList.add(new OffsetLayoutBlock( + LayoutBlockConstants.FRAGMENT_LABELED_BREAK, + Instruction.UNKNOWN_LINE_NUMBER, + Instruction.UNKNOWN_LINE_NUMBER, + 0, 0, 0, + bi.GetJumpOffset())); + } + + private void createBlocksForSwitch( + Preferences preferences, + List layoutBlockList, ClassFile classFile, + Method method, FastSwitch fs, byte tagCase) + { + layoutBlockList.add(new FragmentLayoutBlock( + LayoutBlockConstants.FRAGMENT_SWITCH)); + + createBlockForInstruction( + preferences, layoutBlockList, classFile, method, fs.test); + + layoutBlockList.add(new FragmentLayoutBlock( + LayoutBlockConstants.FRAGMENT_RIGHT_ROUND_BRACKET)); + + BlockLayoutBlock sbslb = new SwitchBlockStartLayoutBlock(); + layoutBlockList.add(sbslb); + + Pair[] pairs = fs.pairs; + int length = pairs.length; + int firstIndex = 0; + + for (int i=0; i instructions = pair.getInstructions(); + + // Do'nt write default case on last position with empty + // instructions list. + if (pair.isDefault() && last) + { + if (instructions == null) + break; + if (instructions.size() == 0) + break; + if ((instructions.size() == 1) && + (instructions.get(0).opcode == FastConstants.GOTO_BREAK)) + break; + } + + if (instructions != null) + { + layoutBlockList.add(new CaseLayoutBlock( + tagCase, classFile, method, fs, firstIndex, i)); + firstIndex = i+1; + + layoutBlockList.add(new CaseBlockStartLayoutBlock()); + createBlocks( + preferences, layoutBlockList, classFile, method, instructions); + layoutBlockList.add(new CaseBlockEndLayoutBlock()); + } + } + + BlockLayoutBlock sbelb = new SwitchBlockEndLayoutBlock(); + sbslb.other = sbelb; + sbelb.other = sbslb; + layoutBlockList.add(sbelb); + } + + private void createBlocksForSwitchEnum( + Preferences preferences, + List layoutBlockList, ClassFile classFile, + Method method, FastSwitch fs) + { + layoutBlockList.add(new FragmentLayoutBlock( + LayoutBlockConstants.FRAGMENT_SWITCH)); + + Instruction test = fs.test; + + ConstantPool constants = classFile.getConstantPool(); + int switchMapKeyIndex = -1; + + if (test.opcode == ByteCodeConstants.ARRAYLOAD) + { + ArrayLoadInstruction ali = (ArrayLoadInstruction)test; + ConstantNameAndType cnat; + + if (ali.arrayref.opcode == ByteCodeConstants.INVOKESTATIC) + { + // Dans le cas des instructions Switch+Enum d'Eclipse, la cl� de la map + // est l'indexe du nom de la m�thode + // "static int[] $SWITCH_TABLE$basic$data$TestEnum$enum1()". + Invokestatic is = (Invokestatic)ali.arrayref; + ConstantMethodref cmr = constants.getConstantMethodref(is.index); + cnat = constants.getConstantNameAndType(cmr.name_and_type_index); + } + else if (ali.arrayref.opcode == ByteCodeConstants.GETSTATIC) + { + // Dans le cas des instructions Switch+Enum des autres compilateurs, + // la cl� de la map est l'indexe du nom de la classe interne + // "static class 1" contenant le tableau de correspondance + // "$SwitchMap$basic$data$TestEnum$enum1". + GetStatic gs = (GetStatic)ali.arrayref; + ConstantFieldref cfr = constants.getConstantFieldref(gs.index); + cnat = constants.getConstantNameAndType(cfr.name_and_type_index); + } + else + { + throw new RuntimeException(); + } + + switchMapKeyIndex = cnat.name_index; + + Invokevirtual iv = (Invokevirtual)ali.indexref; + + createBlockForInstruction( + preferences, layoutBlockList, classFile, method, iv.objectref); + } + + if (switchMapKeyIndex == -1) + throw new RuntimeException(); + + layoutBlockList.add(new FragmentLayoutBlock( + LayoutBlockConstants.FRAGMENT_RIGHT_ROUND_BRACKET)); + + BlockLayoutBlock sbslb = new SwitchBlockStartLayoutBlock(); + layoutBlockList.add(sbslb); + + Pair[] pairs = fs.pairs; + int length = pairs.length; + int firstIndex = 0; + + for (int i=0; i instructions = pair.getInstructions(); + + // Do'nt write default case on last position with empty + // instructions list. + if (pair.isDefault() && last) + { + if (instructions == null) + break; + if (instructions.size() == 0) + break; + if ((instructions.size() == 1) && + (instructions.get(0).opcode == FastConstants.GOTO_BREAK)) + break; + } + + if (instructions != null) + { + layoutBlockList.add(new CaseEnumLayoutBlock( + classFile, method, fs, firstIndex, i, switchMapKeyIndex)); + firstIndex = i+1; + + layoutBlockList.add(new CaseBlockStartLayoutBlock()); + createBlocks( + preferences, layoutBlockList, classFile, method, instructions); + layoutBlockList.add(new CaseBlockEndLayoutBlock()); + } + } + + BlockLayoutBlock sbelb = new SwitchBlockEndLayoutBlock(); + sbslb.other = sbelb; + sbelb.other = sbslb; + layoutBlockList.add(sbelb); + } + + private void createBlocksForTry( + Preferences preferences, List layoutBlockList, + ClassFile classFile, Method method, FastTry ft) + { + layoutBlockList.add(new FragmentLayoutBlock( + LayoutBlockConstants.FRAGMENT_TRY)); + + createBlockForSubList( + preferences, layoutBlockList, classFile, + method, ft.instructions, false, 2); + + if (ft.catches != null) + { + int length = ft.catches.size(); + + if (length > 0) + { + length--; + + // First catch blocks + for (int i=0; i layoutBlockList, + ClassFile classFile, Method method, FastSynchronized fs) + { + layoutBlockList.add(new FragmentLayoutBlock( + LayoutBlockConstants.FRAGMENT_SYNCHRONIZED)); + + createBlockForInstruction( + preferences, layoutBlockList, classFile, method, fs.monitor); + + layoutBlockList.add(new FragmentLayoutBlock( + LayoutBlockConstants.FRAGMENT_RIGHT_ROUND_BRACKET)); + + createBlockForSubList( + preferences, layoutBlockList, classFile, + method, fs.instructions, false, 1); + } + + private void createBlocksForLabel( + Preferences preferences, + List layoutBlockList, ClassFile classFile, + Method method, FastLabel fl) + { + layoutBlockList.add(new OffsetLayoutBlock( + LayoutBlockConstants.STATEMENT_LABEL, + Instruction.UNKNOWN_LINE_NUMBER, + Instruction.UNKNOWN_LINE_NUMBER, + 0, 0, 0, + fl.offset)); + + Instruction instruction = fl.instruction; + + if (instruction != null) + { + layoutBlockList.add(new SeparatorLayoutBlock( + LayoutBlockConstants.SEPARATOR_OF_STATEMENTS, 1)); + + switch (instruction.opcode) + { + case FastConstants.WHILE: + createBlockForFastTestList( + preferences, LayoutBlockConstants.FRAGMENT_WHILE, + layoutBlockList, classFile, method, + (FastTestList)instruction, true); + break; + case FastConstants.DO_WHILE: + createBlocksForDoWhileLoop( + preferences, layoutBlockList, classFile, method, + (FastTestList)instruction); + break; + case FastConstants.INFINITE_LOOP: + createBlocksForInfiniteLoop( + preferences, layoutBlockList, classFile, + method, (FastList)instruction); + break; + case FastConstants.FOR: + createBlocksForForLoop( + preferences, layoutBlockList, classFile, + method, (FastFor)instruction); + break; + case FastConstants.FOREACH: + createBlockForFastForEach( + preferences, layoutBlockList, classFile, + method, (FastForEach)instruction); + break; + case FastConstants.IF_: + createBlockForFastTestList( + preferences, LayoutBlockConstants.FRAGMENT_IF, + layoutBlockList, classFile, method, + (FastTestList)instruction, true); + break; + case FastConstants.IF_ELSE: + FastTest2Lists ft2l = (FastTest2Lists)instruction; + createBlocksForIfElse( + preferences, layoutBlockList, classFile, method, + ft2l, ShowSingleInstructionBlock(ft2l)); + break; + case FastConstants.IF_CONTINUE: + case FastConstants.IF_BREAK: + createBlocksForIfContinueOrBreak( + preferences, layoutBlockList, classFile, method, + (FastInstruction)instruction); + break; + case FastConstants.IF_LABELED_BREAK: + createBlocksForIfLabeledBreak( + preferences, layoutBlockList, classFile, + method, (FastInstruction)instruction); + break; +// case FastConstants.GOTO_CONTINUE: +// CreateBlocksForGotoContinue(layoutBlockList); +// case FastConstants.GOTO_BREAK: +// CreateBlocksForGotoBreak(layoutBlockList); +// break; + case FastConstants.GOTO_LABELED_BREAK: + CreateBlocksForGotoLabeledBreak( + layoutBlockList, classFile, method, + (FastInstruction)instruction); + break; + case FastConstants.SWITCH: + createBlocksForSwitch( + preferences, layoutBlockList, classFile, method, + (FastSwitch)instruction, LayoutBlockConstants.FRAGMENT_CASE); + break; + case FastConstants.SWITCH_ENUM: + createBlocksForSwitchEnum( + preferences, layoutBlockList, classFile, method, + (FastSwitch)instruction); + break; + case FastConstants.SWITCH_STRING: + createBlocksForSwitch( + preferences, layoutBlockList, classFile, method, + (FastSwitch)instruction, + LayoutBlockConstants.FRAGMENT_CASE_STRING); + break; + case FastConstants.TRY: + createBlocksForTry( + preferences, layoutBlockList, classFile, + method, (FastTry)instruction); + break; + case FastConstants.SYNCHRONIZED: + createBlocksForSynchronized( + preferences, layoutBlockList, classFile, + method, (FastSynchronized)instruction); + break; + case FastConstants.LABEL: + createBlocksForLabel( + preferences, layoutBlockList, classFile, method, + (FastLabel)instruction); + break; + case FastConstants.DECLARE: + if (((FastDeclaration)instruction).instruction == null) + { + layoutBlockList.add(new DeclareLayoutBlock( + classFile, method, instruction)); + break; + } + default: + { + createBlockForInstruction( + preferences, layoutBlockList, classFile, + method, instruction); + layoutBlockList.add(new FragmentLayoutBlock( + LayoutBlockConstants.FRAGMENT_SEMICOLON)); + } + } + } + } + + /** + * @param layoutBlockList + * @param classFile + * @param method + * @param instructions + * @param showSingleInstructionBlock + * @param blockEndPreferedLineCount + * 2 pour les premiers blocks, + * 1 pour le dernier bloc + */ + private void createBlockForSubList( + Preferences preferences, + List layoutBlockList, + ClassFile classFile, + Method method, + List instructions, + boolean showSingleInstructionBlock, + int blockEndPreferedLineCount) + { + if ((instructions == null) || (instructions.size() == 0)) + { + StatementsBlockStartLayoutBlock sbslb = + new StatementsBlockStartLayoutBlock(); + sbslb.transformToStartEndBlock(0); + layoutBlockList.add(sbslb); + } + else + { + if (instructions.size() > 1) + showSingleInstructionBlock = false; + + BlockLayoutBlock sbslb = + showSingleInstructionBlock ? + new SingleStatementBlockStartLayoutBlock() : + new StatementsBlockStartLayoutBlock(); + layoutBlockList.add(sbslb); + + createBlocks( + preferences, layoutBlockList, classFile, method, instructions); + + BlockLayoutBlock sbelb = + showSingleInstructionBlock ? + new SingleStatementBlockEndLayoutBlock(0+1 /* TENTATIVE blockEndPreferedLineCount */) : + new StatementsBlockEndLayoutBlock(blockEndPreferedLineCount); + sbslb.other = sbelb; + sbelb.other = sbslb; + layoutBlockList.add(sbelb); + } + } + + private void createBlockForInstruction( + Preferences preferences, + List layoutBlockList, ClassFile classFile, + Method method, Instruction instruction) + { + this.instructionSplitterVisitor.start( + preferences, layoutBlockList, classFile, method, instruction); + this.instructionSplitterVisitor.visit(instruction); + this.instructionSplitterVisitor.end(); + } + + private int createBlockForInstructions( + Preferences preferences, + List layoutBlockList, ClassFile classFile, + Method method, List list, int index1) + { + int index2 = SkipInstructions(list, index1); + + instructionsSplitterVisitor.start( + preferences, layoutBlockList, classFile, method, list, index1); + + for (int index=index1; index<=index2; index++) + { + instructionsSplitterVisitor.setIndex2(index); + instructionsSplitterVisitor.visit(list.get(index)); + } + + instructionsSplitterVisitor.end(); + + return index2; + } + + private static int SkipInstructions(List list, int index) + { + int length = list.size(); + + while (++index < length) + { + Instruction instruction = list.get(index); + + switch (instruction.opcode) + { + case FastConstants.WHILE: + case FastConstants.DO_WHILE: + case FastConstants.INFINITE_LOOP: + case FastConstants.FOR: + case FastConstants.FOREACH: + case FastConstants.IF_: + case FastConstants.IF_ELSE: + case FastConstants.IF_CONTINUE: + case FastConstants.IF_BREAK: + case FastConstants.IF_LABELED_BREAK: + case FastConstants.GOTO_LABELED_BREAK: + case FastConstants.SWITCH: + case FastConstants.SWITCH_ENUM: + case FastConstants.SWITCH_STRING: + case FastConstants.TRY: + case FastConstants.SYNCHRONIZED: + case FastConstants.LABEL: + return index-1; + case FastConstants.DECLARE: + if (((FastDeclaration)instruction).instruction == null) + return index-1; + } + } + + return length-1; + } +} diff --git a/src/jd/core/process/layouter/LayoutBlockComparator.java b/src/jd/core/process/layouter/LayoutBlockComparator.java new file mode 100644 index 00000000..ccc7cbd5 --- /dev/null +++ b/src/jd/core/process/layouter/LayoutBlockComparator.java @@ -0,0 +1,43 @@ +package jd.core.process.layouter; + +import java.util.Comparator; + +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.layout.block.LayoutBlock; + +/* + * Tri par ordre croissant, les blocs sans numero de ligne sont places a la fin. + */ +public class LayoutBlockComparator implements Comparator +{ + public LayoutBlockComparator() {} + + public int compare(LayoutBlock lb1, LayoutBlock lb2) { + if (lb1.lastLineNumber == Instruction.UNKNOWN_LINE_NUMBER) + { + if (lb2.lastLineNumber == Instruction.UNKNOWN_LINE_NUMBER) + { + // Tri par l'index pour eviter les ecarts de tri entre la + // version Java et C++ + return lb1.index - lb2.index; + } + else + { + // lb1 > lb2 + return 1; + } + } + else + { + if (lb2.lastLineNumber == Instruction.UNKNOWN_LINE_NUMBER) + { + // lb1 < lb2 + return -1; + } + else + { + return lb1.lastLineNumber - lb2.lastLineNumber; + } + } + } +} diff --git a/src/jd/core/process/layouter/SignatureLayouter.java b/src/jd/core/process/layouter/SignatureLayouter.java new file mode 100644 index 00000000..2a6f65bc --- /dev/null +++ b/src/jd/core/process/layouter/SignatureLayouter.java @@ -0,0 +1,108 @@ +package jd.core.process.layouter; + +import java.util.List; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.ClassFileConstants; +import jd.core.model.layout.block.GenericExtendsSuperInterfacesLayoutBlock; +import jd.core.model.layout.block.GenericExtendsSuperTypeLayoutBlock; +import jd.core.model.layout.block.GenericImplementsInterfacesLayoutBlock; +import jd.core.model.layout.block.GenericTypeNameLayoutBlock; +import jd.core.model.layout.block.LayoutBlock; +import jd.core.util.CharArrayUtil; +import jd.core.util.SignatureUtil; +import jd.core.util.StringConstants; + +public class SignatureLayouter +{ + public static boolean CreateLayoutBlocksForClassSignature( + ClassFile classFile, + String signature, + List layoutBlockList) + { + boolean displayExtendsOrImplementsFlag = false; + + char[] caSignature = signature.toCharArray(); + int length = caSignature.length; + int index = 0; + int newIndex; + + layoutBlockList.add(new GenericTypeNameLayoutBlock(classFile, signature)); + + // Affichage des generics + index = SkipGenerics(caSignature, length, index); + + // Affichage de la classe mere + newIndex = SignatureUtil.SkipSignature(caSignature, length, index); + + if (((classFile.access_flags & + (ClassFileConstants.ACC_INTERFACE|ClassFileConstants.ACC_ENUM)) == 0) && + !IsObjectClass(caSignature, index, newIndex)) + { + displayExtendsOrImplementsFlag = true; + layoutBlockList.add( + new GenericExtendsSuperTypeLayoutBlock( + classFile, caSignature, index)); + } + + // Affichage des interfaces ou des super interfaces + if (newIndex < length) + { + displayExtendsOrImplementsFlag = true; + + if ((classFile.access_flags & ClassFileConstants.ACC_INTERFACE) != 0) + { + layoutBlockList.add( + new GenericExtendsSuperInterfacesLayoutBlock( + classFile, caSignature, newIndex)); + } + else + { + layoutBlockList.add( + new GenericImplementsInterfacesLayoutBlock( + classFile, caSignature, newIndex)); + } + } + + return displayExtendsOrImplementsFlag; + } + + private static int SkipGenerics(char[] caSignature, int length, int index) + { + if (caSignature[index] == '<') + { + int depth = 1; + + while (index < length) + { + char c = caSignature[++index]; + + if (c == '<') + { + depth++; + } + else if (c == '>') + { + if (depth > 1) + { + depth--; + } + else + { + index++; + break; + } + } + } + } + + return index; + } + + private static boolean IsObjectClass( + char[] caSignature, int beginIndex, int endIndex) + { + return CharArrayUtil.Substring(caSignature, beginIndex, endIndex) + .equals(StringConstants.INTERNAL_OBJECT_SIGNATURE); + } +} diff --git a/src/jd/core/process/layouter/visitor/BaseInstructionSplitterVisitor.java b/src/jd/core/process/layouter/visitor/BaseInstructionSplitterVisitor.java new file mode 100644 index 00000000..e90e194e --- /dev/null +++ b/src/jd/core/process/layouter/visitor/BaseInstructionSplitterVisitor.java @@ -0,0 +1,271 @@ +package jd.core.process.layouter.visitor; + +import java.util.List; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.constant.ConstantMethodref; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.ANewArray; +import jd.core.model.instruction.bytecode.instruction.AThrow; +import jd.core.model.instruction.bytecode.instruction.ArrayLength; +import jd.core.model.instruction.bytecode.instruction.ArrayLoadInstruction; +import jd.core.model.instruction.bytecode.instruction.ArrayStoreInstruction; +import jd.core.model.instruction.bytecode.instruction.AssertInstruction; +import jd.core.model.instruction.bytecode.instruction.BinaryOperatorInstruction; +import jd.core.model.instruction.bytecode.instruction.CheckCast; +import jd.core.model.instruction.bytecode.instruction.ComplexConditionalBranchInstruction; +import jd.core.model.instruction.bytecode.instruction.ConvertInstruction; +import jd.core.model.instruction.bytecode.instruction.GetField; +import jd.core.model.instruction.bytecode.instruction.IfCmp; +import jd.core.model.instruction.bytecode.instruction.IfInstruction; +import jd.core.model.instruction.bytecode.instruction.IncInstruction; +import jd.core.model.instruction.bytecode.instruction.InitArrayInstruction; +import jd.core.model.instruction.bytecode.instruction.InstanceOf; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.InvokeInstruction; +import jd.core.model.instruction.bytecode.instruction.InvokeNew; +import jd.core.model.instruction.bytecode.instruction.InvokeNoStaticInstruction; +import jd.core.model.instruction.bytecode.instruction.MultiANewArray; +import jd.core.model.instruction.bytecode.instruction.NewArray; +import jd.core.model.instruction.bytecode.instruction.Pop; +import jd.core.model.instruction.bytecode.instruction.PutField; +import jd.core.model.instruction.bytecode.instruction.PutStatic; +import jd.core.model.instruction.bytecode.instruction.ReturnInstruction; +import jd.core.model.instruction.bytecode.instruction.StoreInstruction; +import jd.core.model.instruction.bytecode.instruction.Switch; +import jd.core.model.instruction.bytecode.instruction.TernaryOpStore; +import jd.core.model.instruction.bytecode.instruction.TernaryOperator; +import jd.core.model.instruction.bytecode.instruction.UnaryOperatorInstruction; +import jd.core.model.instruction.fast.FastConstants; +import jd.core.model.instruction.fast.instruction.FastDeclaration; +import jd.core.util.StringConstants; + + +public abstract class BaseInstructionSplitterVisitor +{ + protected ClassFile classFile; + protected ConstantPool constants; + + public BaseInstructionSplitterVisitor() {} + + public void start(ClassFile classFile) + { + this.classFile = classFile; + this.constants = (classFile == null) ? null : classFile.getConstantPool(); + } + + public void visit(Instruction instruction) + { + visit(null, instruction); + } + + protected void visit(Instruction parent, Instruction instruction) + { + switch (instruction.opcode) + { + case ByteCodeConstants.ARRAYLENGTH: + visit(instruction, ((ArrayLength)instruction).arrayref); + break; + case ByteCodeConstants.ARRAYLOAD: + { + ArrayLoadInstruction ali = (ArrayLoadInstruction)instruction; + visit(instruction, ali.arrayref); + visit(instruction, ali.indexref); + } + break; + case ByteCodeConstants.AASTORE: + case ByteCodeConstants.ARRAYSTORE: + { + ArrayStoreInstruction asi = (ArrayStoreInstruction)instruction; + visit(instruction, asi.arrayref); + visit(instruction, asi.indexref); + visit(instruction, asi.valueref); + } + break; + case ByteCodeConstants.ANEWARRAY: + visit(instruction, ((ANewArray)instruction).dimension); + break; + case ByteCodeConstants.ASSERT: + { + AssertInstruction ai = (AssertInstruction)instruction; + visit(instruction, ai.test); + if (ai.msg != null) + visit(instruction, ai.msg); + } + break; + case ByteCodeConstants.ASSIGNMENT: + case ByteCodeConstants.BINARYOP: + { + BinaryOperatorInstruction boi = + (BinaryOperatorInstruction)instruction; + visit(instruction, boi.value1); + visit(instruction, boi.value2); + } + break; + case ByteCodeConstants.ATHROW: + visit(instruction, ((AThrow)instruction).value); + break; + case ByteCodeConstants.UNARYOP: + visit(instruction, ((UnaryOperatorInstruction)instruction).value); + break; + case ByteCodeConstants.CONVERT: + case ByteCodeConstants.IMPLICITCONVERT: + visit(instruction, ((ConvertInstruction)instruction).value); + break; + case ByteCodeConstants.CHECKCAST: + visit(instruction, ((CheckCast)instruction).objectref); + break; + case FastConstants.DECLARE: + { + FastDeclaration fd = (FastDeclaration)instruction; + if (fd.instruction != null) + visit(instruction, fd.instruction); + } + break; + case ByteCodeConstants.GETFIELD: + visit(instruction, ((GetField)instruction).objectref); + break; + case ByteCodeConstants.IF: + case ByteCodeConstants.IFXNULL: + visit(instruction, ((IfInstruction)instruction).value); + break; + case ByteCodeConstants.IFCMP: + { + IfCmp ic = (IfCmp)instruction; + visit(instruction, ic.value1); + visit(instruction, ic.value2); + } + break; + case FastConstants.COMPLEXIF: + { + List branchList = + ((ComplexConditionalBranchInstruction)instruction).instructions; + int lenght = branchList.size(); + for (int i=0; i args = in.args; + int lenght = args.size(); + for (int i=0; i args = ((InvokeInstruction)instruction).args; + int lenght = args.size(); + for (int i=0; i values = iai.values; + int lenght = values.size(); + for (int i=0; i layoutBlockList; + protected Method method; + protected Instruction instruction; + protected int firstLineNumber; + protected int offset1; + + public InstructionSplitterVisitor() {} + + public void start( + Preferences preferences, + List layoutBlockList, ClassFile classFile, + Method method, Instruction instruction) + { + super.start(classFile); + + this.preferences = preferences; + this.layoutBlockList = layoutBlockList; + this.method = method; + this.instruction = instruction; + this.firstLineNumber = MinLineNumberVisitor.visit(instruction); + this.offset1 = 0; + } + + public void end() + { + // S'il reste un fragment d'instruction a traiter... + if ((this.offset1 == 0) || (this.offset1 != this.instruction.offset)) + { + // Add last part of instruction + int lastLineNumber = MaxLineNumberVisitor.visit(instruction); + int preferedLineNumber; + + if ((firstLineNumber != Instruction.UNKNOWN_LINE_NUMBER) && + (lastLineNumber != Instruction.UNKNOWN_LINE_NUMBER)) + { + preferedLineNumber = lastLineNumber-firstLineNumber; + } + else + { + preferedLineNumber = LayoutBlockConstants.UNLIMITED_LINE_COUNT; + } + + layoutBlockList.add(new InstructionLayoutBlock( + LayoutBlockConstants.INSTRUCTION, + this.firstLineNumber, lastLineNumber, + preferedLineNumber, preferedLineNumber, preferedLineNumber, + this.classFile, this.method, this.instruction, + this.offset1, this.instruction.offset)); + } + } + + public void visitAnonymousNewInvoke( + Instruction parent, InvokeNew in, ClassFile innerClassFile) + { + // Add a new part of instruction + int lastLineNumber = MaxLineNumberVisitor.visit(in); + int preferedLineNumber; + + if ((this.firstLineNumber != Instruction.UNKNOWN_LINE_NUMBER) && + (lastLineNumber != Instruction.UNKNOWN_LINE_NUMBER)) + { + preferedLineNumber = lastLineNumber-this.firstLineNumber; + } + else + { + preferedLineNumber = LayoutBlockConstants.UNLIMITED_LINE_COUNT; + } + + this.layoutBlockList.add(new InstructionLayoutBlock( + LayoutBlockConstants.INSTRUCTION, + this.firstLineNumber, lastLineNumber, + preferedLineNumber, preferedLineNumber, preferedLineNumber, + this.classFile, this.method, this.instruction, + this.offset1, in.offset)); + + this.firstLineNumber = parent.lineNumber; + this.offset1 = in.offset; + + // Add blocks for inner class body + ClassFileLayouter.CreateBlocksForBodyOfAnonymousClass( + this.preferences, innerClassFile, this.layoutBlockList); + } +} diff --git a/src/jd/core/process/layouter/visitor/InstructionsSplitterVisitor.java b/src/jd/core/process/layouter/visitor/InstructionsSplitterVisitor.java new file mode 100644 index 00000000..85284949 --- /dev/null +++ b/src/jd/core/process/layouter/visitor/InstructionsSplitterVisitor.java @@ -0,0 +1,180 @@ +package jd.core.process.layouter.visitor; + +import java.util.List; + +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.Method; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.InvokeNew; +import jd.core.model.layout.block.InstructionsLayoutBlock; +import jd.core.model.layout.block.LayoutBlock; +import jd.core.model.layout.block.LayoutBlockConstants; +import jd.core.preferences.Preferences; +import jd.core.process.layouter.ClassFileLayouter; + +public class InstructionsSplitterVisitor extends BaseInstructionSplitterVisitor +{ + protected Preferences preferences; + protected List layoutBlockList; + protected Method method; + protected List list; + protected int firstLineNumber; + protected int maxLineNumber; + protected int initialIndex1; + protected int index1; + protected int index2; + protected int offset1; + + public InstructionsSplitterVisitor() {} + + public void start( + Preferences preferences, + List layoutBlockList, ClassFile classFile, + Method method, List list, int index1) + { + super.start(classFile); + + this.preferences = preferences; + this.layoutBlockList = layoutBlockList; + this.method = method; + this.list = list; + this.firstLineNumber = this.maxLineNumber = + Instruction.UNKNOWN_LINE_NUMBER; + this.initialIndex1 = this.index1 = index1; + this.offset1 = 0; + } + + public void end() + { + int lastOffset = this.list.get(this.index2).offset; + + // S'il reste un fragment d'instruction a traiter... + if ((this.index1 != this.index2) || (this.offset1 != lastOffset)) + { + // Add last part of instruction + int lastLineNumber = Instruction.UNKNOWN_LINE_NUMBER; + + for (int j=index2; j>=index1; j--) + { + Instruction instruction = list.get(j); + if (instruction.lineNumber != Instruction.UNKNOWN_LINE_NUMBER) + { + lastLineNumber = MaxLineNumberVisitor.visit(instruction); + break; + } + } + + addInstructionsLayoutBlock(lastLineNumber, lastOffset); + } + } + + public void setIndex2(int index2) + { + this.index2 = index2; + } + + public void visit(Instruction instruction) + { + if (this.firstLineNumber == Instruction.UNKNOWN_LINE_NUMBER) + { + // Bloc execut� soit lors de la visite de + // - du 1er statement + // - d'un statement qui suit un statement dont la derniere + // instruction est 'AnonymousNewInvoke' + // Assez complexe a comprendre sans exemple sous les yeux + // Methode d'exemple : + // java.io.ObjectInputStream, auditSubclass(...) + int initialFirstLineNumber = + this.list.get(this.initialIndex1).lineNumber; + + if (initialFirstLineNumber != Instruction.UNKNOWN_LINE_NUMBER) + { + // Si la methode possede des numeros de lignes + if (initialFirstLineNumber < instruction.lineNumber) + { + // Cas d'un statement qui suit un statement dont la derniere + // instruction est 'AnonymousNewInvoke' ==> on fait + // commencer le bloc a la ligne precedent. + this.firstLineNumber = instruction.lineNumber - 1; + } + else + { + // Cas du 1er statement + this.firstLineNumber = instruction.lineNumber; + } + } + } + + super.visit(null, instruction); + } + + protected void visit(Instruction parent, Instruction instruction) + { + if (instruction.lineNumber == Instruction.UNKNOWN_LINE_NUMBER) + { + instruction.lineNumber = this.maxLineNumber; + } + else if (this.maxLineNumber == Instruction.UNKNOWN_LINE_NUMBER) + { + this.maxLineNumber = instruction.lineNumber; + } + else if (instruction.lineNumber < this.maxLineNumber) + { + // Modification du numero de ligne fournit dans le fichier CLASS ! + instruction.lineNumber = this.maxLineNumber; + } + + if (this.firstLineNumber == Instruction.UNKNOWN_LINE_NUMBER) + { + // Bloc execut� si une instruction 'AnonymousNewInvoke' vient + // d'etre traitee. + this.firstLineNumber = instruction.lineNumber; + } + + super.visit(parent, instruction); + } + + public void visitAnonymousNewInvoke( + Instruction parent, InvokeNew in, ClassFile innerClassFile) + { + // Add a new part of instruction + addInstructionsLayoutBlock(in.lineNumber, in.offset); + + // Add blocks for inner class body + this.maxLineNumber = + ClassFileLayouter.CreateBlocksForBodyOfAnonymousClass( + this.preferences, innerClassFile, this.layoutBlockList); + + this.firstLineNumber = Instruction.UNKNOWN_LINE_NUMBER; + this.index1 = this.index2; + this.offset1 = in.offset; + } + + protected void addInstructionsLayoutBlock(int lastLineNumber, int lastOffset) + { + int preferedLineCount; + + if ((this.firstLineNumber != Instruction.UNKNOWN_LINE_NUMBER) && + (lastLineNumber != Instruction.UNKNOWN_LINE_NUMBER)) + { + if (lastLineNumber < this.firstLineNumber) + { + // Les instructions newAnonymousClass imbriqu�es n'ont pas de + // num�ros de ligne correctes. Exemple: com.googlecode.dex2jar.v3.Dex2jar + lastLineNumber = this.firstLineNumber; + } + preferedLineCount = lastLineNumber - this.firstLineNumber; + } + else + { + preferedLineCount = LayoutBlockConstants.UNLIMITED_LINE_COUNT; + } + + this.layoutBlockList.add(new InstructionsLayoutBlock( + this.firstLineNumber, lastLineNumber, + preferedLineCount, preferedLineCount, preferedLineCount, + this.classFile, this.method, this.list, + this.index1, this.index2, + this.offset1, lastOffset)); + } +} diff --git a/src/jd/core/process/layouter/visitor/MaxLineNumberVisitor.java b/src/jd/core/process/layouter/visitor/MaxLineNumberVisitor.java new file mode 100644 index 00000000..c73b8294 --- /dev/null +++ b/src/jd/core/process/layouter/visitor/MaxLineNumberVisitor.java @@ -0,0 +1,257 @@ +package jd.core.process.layouter.visitor; + +import java.util.List; + +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.ANewArray; +import jd.core.model.instruction.bytecode.instruction.AThrow; +import jd.core.model.instruction.bytecode.instruction.ArrayLoadInstruction; +import jd.core.model.instruction.bytecode.instruction.ArrayStoreInstruction; +import jd.core.model.instruction.bytecode.instruction.AssertInstruction; +import jd.core.model.instruction.bytecode.instruction.BinaryOperatorInstruction; +import jd.core.model.instruction.bytecode.instruction.CheckCast; +import jd.core.model.instruction.bytecode.instruction.ComplexConditionalBranchInstruction; +import jd.core.model.instruction.bytecode.instruction.ConvertInstruction; +import jd.core.model.instruction.bytecode.instruction.DupStore; +import jd.core.model.instruction.bytecode.instruction.IfCmp; +import jd.core.model.instruction.bytecode.instruction.IfInstruction; +import jd.core.model.instruction.bytecode.instruction.IncInstruction; +import jd.core.model.instruction.bytecode.instruction.InitArrayInstruction; +import jd.core.model.instruction.bytecode.instruction.InstanceOf; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.InvokeInstruction; +import jd.core.model.instruction.bytecode.instruction.InvokeNew; +import jd.core.model.instruction.bytecode.instruction.LookupSwitch; +import jd.core.model.instruction.bytecode.instruction.MonitorEnter; +import jd.core.model.instruction.bytecode.instruction.MonitorExit; +import jd.core.model.instruction.bytecode.instruction.MultiANewArray; +import jd.core.model.instruction.bytecode.instruction.NewArray; +import jd.core.model.instruction.bytecode.instruction.Pop; +import jd.core.model.instruction.bytecode.instruction.PutField; +import jd.core.model.instruction.bytecode.instruction.PutStatic; +import jd.core.model.instruction.bytecode.instruction.ReturnInstruction; +import jd.core.model.instruction.bytecode.instruction.StoreInstruction; +import jd.core.model.instruction.bytecode.instruction.TableSwitch; +import jd.core.model.instruction.bytecode.instruction.TernaryOpStore; +import jd.core.model.instruction.bytecode.instruction.TernaryOperator; +import jd.core.model.instruction.bytecode.instruction.UnaryOperatorInstruction; +import jd.core.model.instruction.fast.FastConstants; +import jd.core.model.instruction.fast.instruction.FastDeclaration; + +public class MaxLineNumberVisitor +{ + public static int visit(Instruction instruction) + { + int maxLineNumber = instruction.lineNumber; + + switch (instruction.opcode) + { + case ByteCodeConstants.ARRAYLOAD: + maxLineNumber = visit(((ArrayLoadInstruction)instruction).indexref); + break; + case ByteCodeConstants.AASTORE: + case ByteCodeConstants.ARRAYSTORE: + maxLineNumber = visit(((ArrayStoreInstruction)instruction).valueref); + break; + case ByteCodeConstants.ASSERT: + { + AssertInstruction ai = (AssertInstruction)instruction; + maxLineNumber = visit((ai.msg == null) ? ai.test : ai.msg); + } + break; + case ByteCodeConstants.ATHROW: + maxLineNumber = visit(((AThrow)instruction).value); + break; + case ByteCodeConstants.UNARYOP: + maxLineNumber = visit(((UnaryOperatorInstruction)instruction).value); + break; + case ByteCodeConstants.BINARYOP: + case ByteCodeConstants.ASSIGNMENT: + maxLineNumber = visit(((BinaryOperatorInstruction)instruction).value2); + break; + case ByteCodeConstants.CHECKCAST: + maxLineNumber = visit(((CheckCast)instruction).objectref); + break; + case ByteCodeConstants.STORE: + case ByteCodeConstants.ASTORE: + case ByteCodeConstants.ISTORE: + maxLineNumber = visit(((StoreInstruction)instruction).valueref); + break; + case ByteCodeConstants.DUPSTORE: + maxLineNumber = visit(((DupStore)instruction).objectref); + break; + case ByteCodeConstants.CONVERT: + case ByteCodeConstants.IMPLICITCONVERT: + maxLineNumber = visit(((ConvertInstruction)instruction).value); + break; + case FastConstants.DECLARE: + { + FastDeclaration fd = (FastDeclaration)instruction; + if (fd.instruction != null) + maxLineNumber = visit(fd.instruction); + } + break; + case ByteCodeConstants.IFCMP: + maxLineNumber = visit(((IfCmp)instruction).value2); + break; + case ByteCodeConstants.IF: + case ByteCodeConstants.IFXNULL: + maxLineNumber = visit(((IfInstruction)instruction).value); + break; + case ByteCodeConstants.COMPLEXIF: + { + List branchList = + ((ComplexConditionalBranchInstruction)instruction).instructions; + maxLineNumber = visit(branchList.get(branchList.size()-1)); + } + break; + case ByteCodeConstants.INSTANCEOF: + maxLineNumber = visit(((InstanceOf)instruction).objectref); + break; + case ByteCodeConstants.INVOKEINTERFACE: + case ByteCodeConstants.INVOKESPECIAL: + case ByteCodeConstants.INVOKEVIRTUAL: + case ByteCodeConstants.INVOKESTATIC: + { + List list = ((InvokeInstruction)instruction).args; + int length = list.size(); + + if (length == 0) + { + maxLineNumber = instruction.lineNumber; + } + else + { + // Correction pour un tres curieux bug : les numeros de + // ligne des parametres ne sont pas toujours en ordre croissant + maxLineNumber = visit(list.get(0)); + + for (int i=length-1; i>0; i--) + { + int lineNumber = visit(list.get(i)); + if (maxLineNumber < lineNumber) + maxLineNumber = lineNumber; + } + } + } + break; + case ByteCodeConstants.INVOKENEW: + case FastConstants.ENUMVALUE: + { + List list = ((InvokeNew)instruction).args; + int length = list.size(); + + if (length == 0) + { + maxLineNumber = instruction.lineNumber; + } + else + { + // Correction pour un tres curieux bug : les numeros de + // ligne des parametres ne sont pas toujours en ordre croissant + maxLineNumber = visit(list.get(0)); + + for (int i=length-1; i>0; i--) + { + int lineNumber = visit(list.get(i)); + if (maxLineNumber < lineNumber) + maxLineNumber = lineNumber; + } + } + } + break; + case ByteCodeConstants.LOOKUPSWITCH: + maxLineNumber = visit(((LookupSwitch)instruction).key); + break; + case ByteCodeConstants.MONITORENTER: + maxLineNumber = visit(((MonitorEnter)instruction).objectref); + break; + case ByteCodeConstants.MONITOREXIT: + maxLineNumber = visit(((MonitorExit)instruction).objectref); + break; + case ByteCodeConstants.MULTIANEWARRAY: + { + Instruction[] dimensions = ((MultiANewArray)instruction).dimensions; + int length = dimensions.length; + if (length > 0) + maxLineNumber = visit(dimensions[length-1]); + } + break; + case ByteCodeConstants.NEWARRAY: + maxLineNumber = visit(((NewArray)instruction).dimension); + break; + case ByteCodeConstants.ANEWARRAY: + maxLineNumber = visit(((ANewArray)instruction).dimension); + break; + case ByteCodeConstants.POP: + maxLineNumber = visit(((Pop)instruction).objectref); + break; + case ByteCodeConstants.PUTFIELD: + maxLineNumber = visit(((PutField)instruction).valueref); + break; + case ByteCodeConstants.PUTSTATIC: + maxLineNumber = visit(((PutStatic)instruction).valueref); + break; + case ByteCodeConstants.XRETURN: + maxLineNumber = visit(((ReturnInstruction)instruction).valueref); + break; + case ByteCodeConstants.TABLESWITCH: + maxLineNumber = visit(((TableSwitch)instruction).key); + break; + case ByteCodeConstants.TERNARYOPSTORE: + maxLineNumber = visit(((TernaryOpStore)instruction).objectref); + break; + case ByteCodeConstants.PREINC: + { + IncInstruction ii = (IncInstruction)instruction; + + switch (ii.count) + { + case -1: + case 1: + maxLineNumber = visit(ii.value); + break; + } + } + break; + case ByteCodeConstants.POSTINC: + { + IncInstruction ii = (IncInstruction)instruction; + + switch (ii.count) + { + case -1: + case 1: + maxLineNumber = instruction.lineNumber; + default: + maxLineNumber = visit(ii.value); + } + } + break; + case ByteCodeConstants.INITARRAY: + case ByteCodeConstants.NEWANDINITARRAY: + { + InitArrayInstruction iai = (InitArrayInstruction)instruction; + int length = iai.values.size(); + if (length > 0) + maxLineNumber = visit(iai.values.get(length-1)); + } + break; + case FastConstants.TERNARYOP: + maxLineNumber = visit(((TernaryOperator)instruction).value2); + break; + } + + // Autre curieux bug : les constantes finales passees en parametres + // peuvent avoir un numero de ligne plus petit que le numero de ligne + // de l'instruction INVOKE* + if (maxLineNumber < instruction.lineNumber) + { + return instruction.lineNumber; + } + else + { + return maxLineNumber; + } + } +} diff --git a/src/jd/core/process/layouter/visitor/MinLineNumberVisitor.java b/src/jd/core/process/layouter/visitor/MinLineNumberVisitor.java new file mode 100644 index 00000000..aa9fe9d3 --- /dev/null +++ b/src/jd/core/process/layouter/visitor/MinLineNumberVisitor.java @@ -0,0 +1,76 @@ +package jd.core.process.layouter.visitor; + +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.ArrayLoadInstruction; +import jd.core.model.instruction.bytecode.instruction.ArrayStoreInstruction; +import jd.core.model.instruction.bytecode.instruction.AssignmentInstruction; +import jd.core.model.instruction.bytecode.instruction.BinaryOperatorInstruction; +import jd.core.model.instruction.bytecode.instruction.IncInstruction; +import jd.core.model.instruction.bytecode.instruction.InstanceOf; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.InvokeNoStaticInstruction; +import jd.core.model.instruction.bytecode.instruction.Pop; +import jd.core.model.instruction.bytecode.instruction.PutField; +import jd.core.model.instruction.bytecode.instruction.TernaryOperator; +import jd.core.model.instruction.fast.FastConstants; + + + +public class MinLineNumberVisitor +{ + public static int visit(Instruction instruction) + { + switch (instruction.opcode) + { + case ByteCodeConstants.ARRAYLOAD: + return visit(((ArrayLoadInstruction)instruction).arrayref); + case ByteCodeConstants.AASTORE: + case ByteCodeConstants.ARRAYSTORE: + return visit(((ArrayStoreInstruction)instruction).arrayref); + case ByteCodeConstants.ASSIGNMENT: + return visit(((AssignmentInstruction)instruction).value1); + case ByteCodeConstants.BINARYOP: + return visit(((BinaryOperatorInstruction)instruction).value1); + case ByteCodeConstants.PREINC: + { + IncInstruction ii = (IncInstruction)instruction; + + switch (ii.count) + { + case -1: + case 1: + return instruction.lineNumber; + default: + return visit(ii.value); + } + } + case ByteCodeConstants.POSTINC: + { + IncInstruction ii = (IncInstruction)instruction; + + switch (ii.count) + { + case -1: + case 1: + return visit(ii.value); + default: + return instruction.lineNumber; + } + } + case ByteCodeConstants.INSTANCEOF: + return visit(((InstanceOf)instruction).objectref); + case ByteCodeConstants.INVOKEINTERFACE: + case ByteCodeConstants.INVOKEVIRTUAL: + case ByteCodeConstants.INVOKESPECIAL: + return visit(((InvokeNoStaticInstruction)instruction).objectref); + case ByteCodeConstants.POP: + return visit(((Pop)instruction).objectref); + case ByteCodeConstants.PUTFIELD: + return visit(((PutField)instruction).objectref); + case FastConstants.TERNARYOP: + return visit(((TernaryOperator)instruction).test); + } + + return instruction.lineNumber; + } +} diff --git a/src/jd/core/process/writer/AnnotationWriter.java b/src/jd/core/process/writer/AnnotationWriter.java new file mode 100644 index 00000000..506e98ed --- /dev/null +++ b/src/jd/core/process/writer/AnnotationWriter.java @@ -0,0 +1,82 @@ +package jd.core.process.writer; + +import jd.core.loader.Loader; +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.attribute.Annotation; +import jd.core.model.classfile.attribute.ElementValuePair; +import jd.core.model.classfile.attribute.ParameterAnnotations; +import jd.core.model.reference.ReferenceMap; +import jd.core.printer.Printer; + + +public class AnnotationWriter +{ + public static void WriteParameterAnnotation( + Loader loader, Printer printer, ReferenceMap referenceMap, + ClassFile classFile, ParameterAnnotations parameterAnnotation) + { + if (parameterAnnotation == null) + return; + + Annotation[] annotations = parameterAnnotation.annotations; + + if (annotations == null) + return; + + for (int i=0; i 0) + { + printer.print('('); + + ConstantPool constants = classFile.getConstantPool(); + String name = constants.getConstantUtf8(evps[0].element_name_index); + + if ((evps.length > 1) || !"value".equals(name)) + { + printer.print(name); + printer.print('='); + } + ElementValueWriter.WriteElementValue( + loader, printer, referenceMap, + classFile, evps[0].element_value); + + for (int j=1; j= 0) + printer.print('+'); + printer.print(soperande); + printer.print(" -> "); + printer.print( + index + soperande - 2); + break; + + case ByteCodeConstants.PUTSTATIC: + case ByteCodeConstants.PUTFIELD: + case ByteCodeConstants.GETSTATIC: + case ByteCodeConstants.OUTERTHIS: + case ByteCodeConstants.GETFIELD: + ioperande = ((code[++index] & 255) << 8) | + (code[++index] & 255); + printer.print(ioperande); + printer.print("\t"); + String fieldName = + GetConstantFieldName(constants, ioperande); + + if (fieldName == null) + { + printer.startOfError(); + printer.print(CORRUPTED_CONSTANT_POOL); + printer.endOfError(); + } + else + { + printer.print(fieldName); + } + break; + + case ByteCodeConstants.INVOKESTATIC: + case ByteCodeConstants.INVOKESPECIAL: + case ByteCodeConstants.INVOKEVIRTUAL: + ioperande = ((code[++index] & 255) << 8) | + (code[++index] & 255); + printer.print(ioperande); + printer.print("\t"); + String methodName = + GetConstantMethodName(constants, ioperande); + + if (methodName == null) + { + printer.startOfError(); + printer.print(CORRUPTED_CONSTANT_POOL); + printer.endOfError(); + } + else + { + printer.print(methodName); + } + break; + + case ByteCodeConstants.NEW: + case ByteCodeConstants.ANEWARRAY: + case ByteCodeConstants.CHECKCAST: + ioperande = ((code[++index] & 255) << 8) | + (code[++index] & 255); + printer.print(ioperande); + printer.print("\t"); + + Constant c = constants.get(ioperande); + + if (c.tag == ConstantConstant.CONSTANT_Class) + { + ConstantClass cc = (ConstantClass)c; + printer.print( + constants.getConstantUtf8(cc.name_index)); + } + else + { + printer.print(CORRUPTED_CONSTANT_POOL); + } + break; + + default: + ioperande = ((code[++index] & 255) << 8) | + (code[++index] & 255); + printer.print(ioperande); + } + break; + default: + switch (opcode) + { + case ByteCodeConstants.MULTIANEWARRAY: + printer.print(" "); + printer.print( + ((code[++index] & 255) << 8) | (code[++index] & 255)); + printer.print(" "); + printer.print(code[++index]); + break; + case ByteCodeConstants.INVOKEINTERFACE: + printer.print(" "); + printer.print( + ((code[++index] & 255) << 8) | (code[++index] & 255)); + printer.print(" "); + printer.print(code[++index]); + printer.print(" "); + printer.print(code[++index]); + break; + case ByteCodeConstants.TABLESWITCH: + // Skip padding + index = ((index+4) & 0xFFFC) - 1; + + printer.print("\tdefault:+"); + + int jump = ((code[++index] & 255) << 24) | + ((code[++index] & 255) << 16) | + ((code[++index] & 255) << 8 ) | + (code[++index] & 255); + + printer.print(jump); + printer.print("->"); + printer.print(offset + jump); + + int low = ((code[++index] & 255) << 24) | + ((code[++index] & 255) << 16) | + ((code[++index] & 255) << 8 ) | + (code[++index] & 255); + int high = ((code[++index] & 255) << 24) | + ((code[++index] & 255) << 16) | + ((code[++index] & 255) << 8 ) | + (code[++index] & 255); + + for (int value=low; value<=high; value++) + { + printer.print(", "); + printer.print(value); + printer.print(":+"); + + jump = ((code[++index] & 255) << 24) | + ((code[++index] & 255) << 16) | + ((code[++index] & 255) << 8 ) | + (code[++index] & 255); + + printer.print(jump); + printer.print("->"); + printer.print(offset + jump); + } + break; + case ByteCodeConstants.LOOKUPSWITCH: + // Skip padding + index = ((index+4) & 0xFFFC) - 1; + + printer.print("\tdefault:+"); + + jump = ((code[++index] & 255) << 24) | + ((code[++index] & 255) << 16) | + ((code[++index] & 255) << 8 ) | + (code[++index] & 255); + + printer.print(jump); + printer.print("->"); + printer.print(offset + jump); + + int npairs = ((code[++index] & 255) << 24) | + ((code[++index] & 255) << 16) | + ((code[++index] & 255) << 8 ) | + (code[++index] & 255); + + for (int i=0; i"); + printer.print(offset + jump); + } + break; + case ByteCodeConstants.WIDE: + index = ByteCodeUtil.NextWideOffset(code, index); + break; + default: + for (int j=ByteCodeConstants.NO_OF_OPERANDS[opcode]; j>0; --j) + { + printer.print(" "); + printer.print(code[++index]); + } + } + } + } + + WriteAttributeNumberTables(printer, method); + WriteAttributeLocalVariableTables( + loader, printer, referenceMap, classFile, method); + WriteCodeExceptions(printer, referenceMap, classFile, method); + + printer.endOfComment(); + } + } + + private static void WriteAttributeNumberTables( + Printer printer, Method method) + { + // Ecriture de la table des numeros de ligne + LineNumber[] lineNumbers = method.getLineNumbers(); + if (lineNumbers != null) + { + printer.endOfLine(); + printer.startOfLine(Instruction.UNKNOWN_LINE_NUMBER); + printer.print("// Line number table:"); + + for (int i=0; i byte code offset #"); + printer.print(lineNumbers[i].start_pc); + } + } + } + + private static void WriteAttributeLocalVariableTables( + Loader loader, Printer printer, ReferenceMap referenceMap, + ClassFile classFile, Method method) + { + // Ecriture de la table des variables locales + LocalVariables localVariables = method.getLocalVariables(); + if (localVariables != null) + { + int length = localVariables.size(); + + printer.endOfLine(); + printer.startOfLine(Instruction.UNKNOWN_LINE_NUMBER); + printer.print("// Local variable table:"); + printer.endOfLine(); + printer.startOfLine(Instruction.UNKNOWN_LINE_NUMBER); + printer.print("// start\tlength\tslot\tname\tsignature"); + + ConstantPool constants = classFile.getConstantPool(); + + for (int i=0; i 0) + { + printer.print(constants.getConstantUtf8(lv.name_index)); + } + else + { + printer.print("???"); + } + + printer.print("\t"); + + if (lv.signature_index > 0) + { + SignatureWriter.WriteSignature( + loader, printer, referenceMap, + classFile, constants.getConstantUtf8(lv.signature_index)); + } + else + { + printer.print("???"); + } + } + } + } + } + + private static void WriteCodeExceptions( + Printer printer, ReferenceMap referenceMap, + ClassFile classFile, Method method) + { + // Ecriture de la table des exceptions + CodeException[] codeExceptions = method.getCodeExceptions(); + if ((codeExceptions != null) && (codeExceptions.length > 0)) + { + printer.endOfLine(); + printer.startOfLine(Instruction.UNKNOWN_LINE_NUMBER); + printer.print("// Exception table:"); + printer.endOfLine(); + printer.startOfLine(Instruction.UNKNOWN_LINE_NUMBER); + printer.print("// from\tto\ttarget\ttype"); + + for (int i=0; i keywords; + + private final static String[] ACCESS_FIELD_NAMES = { + "public", "private", "protected", "static", "final", null, "volatile", + "transient" + }; + + private final static String[] ACCESS_METHOD_NAMES = { + "public", "private", "protected", "static", "final", "synchronized", + null, null, "native", null, "abstract", "strictfp" + }; + + private final static String[] ACCESS_NESTED_CLASS_NAMES = { + "public", "private", "protected", "static", "final" + }; + + private final static String[] ACCESS_NESTED_ENUM_NAMES = { + "public", "private", "protected", "static" + }; + + private Loader loader; + private Printer printer; + private InstructionPrinter instructionPrinter; + private SourceWriterVisitor visitor; + private ReferenceMap referenceMap; + private List layoutBlockList; + private int index; + private boolean addSpace = false; + + public static void Write( + Loader loader, Printer printer, ReferenceMap referenceMap, + int maxLineNumber, int majorVersion, int minorVersion, + List layoutBlockList) + { + ClassFileWriter cfw = new ClassFileWriter( + loader, printer, referenceMap, layoutBlockList); + + cfw.write(maxLineNumber, majorVersion, minorVersion); + } + + private ClassFileWriter( + Loader loader, Printer printer, ReferenceMap referenceMap, + List layoutBlockList) + { + this.loader = loader; + this.printer = printer; + this.instructionPrinter = new InstructionPrinter(printer); + this.visitor = new SourceWriterVisitor( + loader, this.instructionPrinter, referenceMap, keywords); + this.referenceMap = referenceMap; + this.layoutBlockList = layoutBlockList; + this.index = 0; + } + + public void write( + int maxLineNumber, int majorVersion, int minorVersion) + { + int length = layoutBlockList.size(); + + this.printer.start(maxLineNumber, majorVersion, minorVersion); + this.printer.startOfLine(searchFirstLineNumber()); + + while (this.index < length) + { + LayoutBlock lb = this.layoutBlockList.get(this.index++); + + switch (lb.tag) + { + case LayoutBlockConstants.PACKAGE: + writePackage((PackageLayoutBlock)lb); + break; + case LayoutBlockConstants.SEPARATOR_AT_BEGINING: + writeSeparatorAtBegining(lb); + break; + case LayoutBlockConstants.SEPARATOR: + case LayoutBlockConstants.SEPARATOR_OF_STATEMENTS: + case LayoutBlockConstants.SEPARATOR_AFTER_IMPORTS: + writeSeparator(lb); + break; + case LayoutBlockConstants.IMPORTS: + writeImports((ImportsLayoutBlock)lb); + break; + case LayoutBlockConstants.TYPE_MARKER_START: + writeTypeMarkerStart((MarkerLayoutBlock)lb); + break; + case LayoutBlockConstants.TYPE_MARKER_END: + writeTypeMarkerEnd((MarkerLayoutBlock)lb); + break; + case LayoutBlockConstants.FIELD_MARKER_START: + writeFieldMarkerStart((MarkerLayoutBlock)lb); + break; + case LayoutBlockConstants.FIELD_MARKER_END: + writeFieldMarkerEnd((MarkerLayoutBlock)lb); + break; + case LayoutBlockConstants.METHOD_MARKER_START: + writeMethodMarkerStart((MarkerLayoutBlock)lb); + break; + case LayoutBlockConstants.METHOD_MARKER_END: + writeMethodMarkerEnd((MarkerLayoutBlock)lb); + break; + case LayoutBlockConstants.COMMENT_DEPRECATED: + writeCommentDeprecated(lb); + break; + case LayoutBlockConstants.COMMENT_ERROR: + writeCommentError(lb); + break; + case LayoutBlockConstants.ANNOTATIONS: + writeAnnotations((AnnotationsLayoutBlock)lb); + break; + case LayoutBlockConstants.TYPE_NAME: + writeType((TypeNameLayoutBlock)lb); + break; + case LayoutBlockConstants.EXTENDS_SUPER_TYPE: + writeExtendsSuperType((ExtendsSuperTypeLayoutBlock)lb); + break; + case LayoutBlockConstants.EXTENDS_SUPER_INTERFACES: + writeExtendsSuperInterfaces( + (ExtendsSuperInterfacesLayoutBlock)lb); + break; + case LayoutBlockConstants.IMPLEMENTS_INTERFACES: + writeImplementsInterfaces((ImplementsInterfacesLayoutBlock)lb); + break; + case LayoutBlockConstants.GENERIC_TYPE_NAME: + writeGenericType((GenericTypeNameLayoutBlock)lb); + break; + case LayoutBlockConstants.GENERIC_EXTENDS_SUPER_TYPE: + writeGenericExtendsSuperType( + (GenericExtendsSuperTypeLayoutBlock)lb); + break; + case LayoutBlockConstants.GENERIC_EXTENDS_SUPER_INTERFACES: + writeGenericExtendsSuperInterfaces( + (GenericExtendsSuperInterfacesLayoutBlock)lb); + break; + case LayoutBlockConstants.GENERIC_IMPLEMENTS_INTERFACES: + writeGenericImplementsInterfaces( + (GenericImplementsInterfacesLayoutBlock)lb); + break; + case LayoutBlockConstants.TYPE_BODY_BLOCK_START: + case LayoutBlockConstants.INNER_TYPE_BODY_BLOCK_START: + case LayoutBlockConstants.METHOD_BODY_BLOCK_START: + case LayoutBlockConstants.METHOD_BODY_SINGLE_LINE_BLOCK_START: + case LayoutBlockConstants.STATEMENTS_BLOCK_START: + writeStatementBlockStart(lb); + break; + case LayoutBlockConstants.TYPE_BODY_BLOCK_END: + case LayoutBlockConstants.METHOD_BODY_BLOCK_END: + case LayoutBlockConstants.METHOD_BODY_SINGLE_LINE_BLOCK_END: + case LayoutBlockConstants.STATEMENTS_BLOCK_END: + writeStatementsBlockEnd(lb); + break; + case LayoutBlockConstants.INNER_TYPE_BODY_BLOCK_END: + writeStatementsInnerBodyBlockEnd(lb); + break; + case LayoutBlockConstants.TYPE_BODY_BLOCK_START_END: + case LayoutBlockConstants.INNER_TYPE_BODY_BLOCK_START_END: + case LayoutBlockConstants.METHOD_BODY_BLOCK_START_END: + case LayoutBlockConstants.STATEMENTS_BLOCK_START_END: + writeStatementsBlockStartEnd(lb); + break; + case LayoutBlockConstants.SWITCH_BLOCK_START: + writeSwitchBlockStart(lb); + break; + case LayoutBlockConstants.SWITCH_BLOCK_END: + writeSwitchBlockEnd(lb); + break; + case LayoutBlockConstants.CASE_BLOCK_START: + writeCaseBlockStart(lb); + break; + case LayoutBlockConstants.CASE_BLOCK_END: + writeCaseBlockEnd(lb); + break; + case LayoutBlockConstants.FOR_BLOCK_START: + writeForBlockStart(lb); + break; + case LayoutBlockConstants.FOR_BLOCK_END: + writeForBlockEnd(lb); + break; + case LayoutBlockConstants.SINGLE_STATEMENT_BLOCK_START: + writeSingleStatementsBlockStart(lb); + break; + case LayoutBlockConstants.SINGLE_STATEMENT_BLOCK_END: + writeSingleStatementsBlockEnd(lb); + break; + case LayoutBlockConstants.SINGLE_STATEMENTS_BLOCK_START_END: + writeSingleStatementsBlockStartEnd(lb); + break; + case LayoutBlockConstants.FIELD_NAME: + writeField((FieldNameLayoutBlock)lb); + break; + case LayoutBlockConstants.METHOD_STATIC: + writeMethodStatic((MethodStaticLayoutBlock)lb); + break; + case LayoutBlockConstants.METHOD_NAME: + writeMethod((MethodNameLayoutBlock)lb); + break; + case LayoutBlockConstants.THROWS: + writeThrows((ThrowsLayoutBlock)lb); + break; + case LayoutBlockConstants.INSTRUCTION: + writeInstruction((InstructionLayoutBlock)lb); + break; + case LayoutBlockConstants.INSTRUCTIONS: + writeInstructions((InstructionsLayoutBlock)lb); + break; + case LayoutBlockConstants.BYTE_CODE: + writeByteCode((ByteCodeLayoutBlock)lb); + break; + case LayoutBlockConstants.DECLARE: + writeDeclaration((DeclareLayoutBlock)lb); + break; + case LayoutBlockConstants.FRAGMENT_IF: + writeIf(); + break; + case LayoutBlockConstants.FRAGMENT_WHILE: + writeWhile(); + break; + case LayoutBlockConstants.FRAGMENT_FOR: + writeFor(); + break; + case LayoutBlockConstants.FRAGMENT_SWITCH: + writeSwitch(); + break; + case LayoutBlockConstants.FRAGMENT_CASE: + writeCase((CaseLayoutBlock)lb); + break; + case LayoutBlockConstants.FRAGMENT_CASE_ENUM: + writeCaseEnum((CaseEnumLayoutBlock)lb); + break; + case LayoutBlockConstants.FRAGMENT_CASE_STRING: + writeCaseString((CaseLayoutBlock)lb); + break; + case LayoutBlockConstants.FRAGMENT_CATCH: + writeCatch((FastCatchLayoutBlock)lb); + break; + case LayoutBlockConstants.FRAGMENT_SYNCHRONIZED: + writeSynchronized(); + break; + case LayoutBlockConstants.STATEMENT_LABEL: + writeLabel((OffsetLayoutBlock)lb); + break; + case LayoutBlockConstants.FRAGMENT_ELSE: + writeElse(); + break; + case LayoutBlockConstants.FRAGMENT_ELSE_SPACE: + writeElseSpace(); + break; + case LayoutBlockConstants.FRAGMENT_DO: + writeDo(); + break; + case LayoutBlockConstants.FRAGMENT_INFINITE_LOOP: + writeInfiniteLoop(); + break; + case LayoutBlockConstants.FRAGMENT_TRY: + writeTry(); + break; + case LayoutBlockConstants.FRAGMENT_FINALLY: + writeFinally(); + break; + case LayoutBlockConstants.FRAGMENT_CONTINUE: + writeContinue(); + break; + case LayoutBlockConstants.FRAGMENT_BREAK: + writeBreak(); + break; + case LayoutBlockConstants.FRAGMENT_LABELED_BREAK: + writeLabeledBreak((OffsetLayoutBlock)lb); + break; + case LayoutBlockConstants.FRAGMENT_RIGHT_ROUND_BRACKET: + writeRightRoundBracket(); + break; + case LayoutBlockConstants.FRAGMENT_RIGHT_ROUND_BRACKET_SEMICOLON: + writeRightRoundBracketSemicolon(); + break; + case LayoutBlockConstants.FRAGMENT_SEMICOLON: + writeSemicolon(); + break; + case LayoutBlockConstants.FRAGMENT_SEMICOLON_SPACE: + writeSemicolonSpace(); + break; + case LayoutBlockConstants.FRAGMENT_SPACE_COLON_SPACE: + writeSpaceColonSpace(); + break; + case LayoutBlockConstants.FRAGMENT_COMA_SPACE: + writeComaSpace(); + break; + } + } + + this.printer.endOfLine(); + this.printer.end(); + } + + private int searchFirstLineNumber() + { + int i = this.index; + int length = this.layoutBlockList.size(); + + while (i < length) + { + LayoutBlock lb = this.layoutBlockList.get(i++); + + switch (lb.tag) + { + case LayoutBlockConstants.INSTRUCTION: + case LayoutBlockConstants.INSTRUCTIONS: + return lb.firstLineNumber; + case LayoutBlockConstants.SEPARATOR: + case LayoutBlockConstants.SEPARATOR_AT_BEGINING: + case LayoutBlockConstants.SEPARATOR_AFTER_IMPORTS: + case LayoutBlockConstants.SEPARATOR_OF_STATEMENTS: + case LayoutBlockConstants.IMPORTS: + case LayoutBlockConstants.COMMENT_DEPRECATED: + case LayoutBlockConstants.ANNOTATIONS: + case LayoutBlockConstants.EXTENDS_SUPER_TYPE: + case LayoutBlockConstants.EXTENDS_SUPER_INTERFACES: + case LayoutBlockConstants.IMPLEMENTS_INTERFACES: + case LayoutBlockConstants.GENERIC_EXTENDS_SUPER_TYPE: + case LayoutBlockConstants.GENERIC_EXTENDS_SUPER_INTERFACES: + case LayoutBlockConstants.GENERIC_IMPLEMENTS_INTERFACES: + case LayoutBlockConstants.TYPE_BODY_BLOCK_START: + case LayoutBlockConstants.TYPE_BODY_BLOCK_END: + case LayoutBlockConstants.TYPE_BODY_BLOCK_START_END: + case LayoutBlockConstants.INNER_TYPE_BODY_BLOCK_START: + case LayoutBlockConstants.INNER_TYPE_BODY_BLOCK_END: + case LayoutBlockConstants.INNER_TYPE_BODY_BLOCK_START_END: + case LayoutBlockConstants.METHOD_BODY_BLOCK_START: + case LayoutBlockConstants.METHOD_BODY_BLOCK_END: + case LayoutBlockConstants.METHOD_BODY_BLOCK_START_END: + case LayoutBlockConstants.METHOD_BODY_SINGLE_LINE_BLOCK_START: + case LayoutBlockConstants.METHOD_BODY_SINGLE_LINE_BLOCK_END: + case LayoutBlockConstants.STATEMENTS_BLOCK_START: + case LayoutBlockConstants.STATEMENTS_BLOCK_END: + case LayoutBlockConstants.STATEMENTS_BLOCK_START_END: + case LayoutBlockConstants.SINGLE_STATEMENT_BLOCK_START: + case LayoutBlockConstants.SINGLE_STATEMENT_BLOCK_END: + case LayoutBlockConstants.SINGLE_STATEMENTS_BLOCK_START_END: + case LayoutBlockConstants.SWITCH_BLOCK_START: + case LayoutBlockConstants.SWITCH_BLOCK_END: + case LayoutBlockConstants.CASE_BLOCK_START: + case LayoutBlockConstants.CASE_BLOCK_END: + case LayoutBlockConstants.FRAGMENT_CASE: + case LayoutBlockConstants.FRAGMENT_CASE_ENUM: + case LayoutBlockConstants.FRAGMENT_CASE_STRING: + if (lb.lineCount > 0) + return Printer.UNKNOWN_LINE_NUMBER; + break; + } + } + + return Printer.UNKNOWN_LINE_NUMBER; + } + + private void writePackage(PackageLayoutBlock plb) + { + this.printer.printKeyword("package"); + this.printer.print(' '); + String internalPackageName = plb.classFile.getInternalPackageName(); + this.printer.print( + internalPackageName.replace( + StringConstants.INTERNAL_PACKAGE_SEPARATOR, + StringConstants.PACKAGE_SEPARATOR)); + this.printer.print(';'); + } + + private void writeSeparatorAtBegining(LayoutBlock slb) + { + int lineCount = slb.lineCount; + + this.printer.debugStartOfSeparatorLayoutBlock(); + //DEBUG this.printer.print('^'); + + if (lineCount > 0) + { + endOfLine(); + + if (lineCount > 1) + { + this.printer.extraLine(lineCount-1); + } + + this.printer.startOfLine( + searchFirstLineNumber()); + } + + this.printer.debugEndOfSeparatorLayoutBlock( + slb.minimalLineCount, slb.lineCount, slb.maximalLineCount); + } + + private void writeSeparator(LayoutBlock slb) + { + int lineCount = slb.lineCount; + + this.printer.debugStartOfSeparatorLayoutBlock(); + //DEBUG this.printer.print('^'); + + if (lineCount > 0) + { + endOfLine(); + + if (lineCount > 1) + { + this.printer.startOfLine(Printer.UNKNOWN_LINE_NUMBER); + endOfLine(); + + if (lineCount > 2) + { + this.printer.extraLine(lineCount-2); + } + } + + this.printer.startOfLine( + searchFirstLineNumber()); + } + else + { + this.printer.print(' '); + this.addSpace = false; + } + + this.printer.debugEndOfSeparatorLayoutBlock( + slb.minimalLineCount, slb.lineCount, slb.maximalLineCount); + } + + private void writeImports(ImportsLayoutBlock ilb) + { + Collection collection = this.referenceMap.values(); + int length = collection.size(); + + if (length > 0) + { + ClassFile classFile = ilb.classFile; + String internalPackageName = classFile.getInternalPackageName(); + + Iterator iterator = collection.iterator(); + ArrayList references = + new ArrayList(length); + + // Filtrage + while (iterator.hasNext()) + { + Reference reference = iterator.next(); + String internalReferencePackageName = + TypeNameUtil.InternalTypeNameToInternalPackageName( + reference.getInternalName()); + + // No import for same package classes + if (internalReferencePackageName.equals(internalPackageName)) + { + continue; + } + + // No import for 'java/lang' classes + if (internalReferencePackageName.equals( + StringConstants.INTERNAL_JAVA_LANG_PACKAGE_NAME)) + { + // TODO + continue; + } + + references.add(reference); + } + + // Reduction + if (references.size() > 0) + { + int delta = ilb.preferedLineCount - ilb.lineCount; + + if (delta > 0) + { + Collections.sort(references, new ReferenceByCountComparator()); + + int index = references.size(); + + while (delta-- > 0) { + Reference reference = references.remove(--index); + // Modification de 'ReferenceMap' + this.referenceMap.remove(reference.getInternalName()); + } + } + + // Affichage + if (references.size() > 0) + { + Collections.sort( + references, new ReferenceByInternalNameComparator()); + + this.printer.debugStartOfLayoutBlock(); + this.printer.startOfImportStatements(); + iterator = references.iterator(); + + if (iterator.hasNext()) + { + writeImport(iterator.next()); + + while (iterator.hasNext()) + { + endOfLine(); + this.printer.startOfLine(Printer.UNKNOWN_LINE_NUMBER); + writeImport(iterator.next()); + } + } + + this.printer.endOfImportStatements(); + this.printer.debugEndOfLayoutBlock(); + } + } + } + } + + private void writeImport(Reference reference) + { + this.printer.printKeyword("import"); + this.printer.print(' '); + + this.printer.printTypeImport( + reference.getInternalName(), + TypeNameUtil.InternalTypeNameToQualifiedTypeName( + reference.getInternalName())); + +// this.printer.print(':'); +// this.printer.print(reference.getCounter()); + this.printer.print(';'); + } + + private void writeTypeMarkerStart(MarkerLayoutBlock mlb) + { + String internalPath = mlb.classFile.getThisClassName() + StringConstants.CLASS_FILE_SUFFIX; + this.printer.startOfTypeDeclaration(internalPath); + this.printer.debugMarker("<T<"); + } + private void writeTypeMarkerEnd(MarkerLayoutBlock mlb) + { + this.printer.debugMarker(">T>"); + this.printer.endOfTypeDeclaration(); + } + + private void writeFieldMarkerStart(MarkerLayoutBlock mlb) + { + String internalPath = mlb.classFile.getThisClassName() + StringConstants.CLASS_FILE_SUFFIX; + this.printer.startOfTypeDeclaration(internalPath); + this.printer.debugMarker("<F<"); + } + private void writeFieldMarkerEnd(MarkerLayoutBlock mlb) + { + this.printer.debugMarker(">F>"); + this.printer.endOfTypeDeclaration(); + } + + private void writeMethodMarkerStart(MarkerLayoutBlock mlb) + { + String internalPath = mlb.classFile.getThisClassName() + StringConstants.CLASS_FILE_SUFFIX; + this.printer.startOfTypeDeclaration(internalPath); + this.printer.debugMarker("<M<"); + } + private void writeMethodMarkerEnd(MarkerLayoutBlock mlb) + { + this.printer.debugMarker(">M>"); + this.printer.endOfTypeDeclaration(); + } + + private void writeCommentDeprecated(LayoutBlock lb) + { + this.printer.debugStartOfCommentDeprecatedLayoutBlock(); + + switch (lb.lineCount) + { + case 0: + this.printer.startOfJavadoc(); + this.printer.print("/** "); + this.printer.startOfXdoclet(); + this.printer.print("@deprecated"); + this.printer.endOfXdoclet(); + this.printer.print(" */"); + this.printer.endOfJavadoc(); + break; + case 1: + this.printer.startOfJavadoc(); + this.printer.print("/** "); + this.printer.startOfXdoclet(); + this.printer.print("@deprecated"); + this.printer.endOfXdoclet(); + this.printer.print(" */"); + this.printer.endOfJavadoc(); + endOfLine(); + this.printer.startOfLine(searchFirstLineNumber()); + break; + case 2: + this.printer.startOfJavadoc(); + this.printer.print("/**"); + endOfLine(); + this.printer.startOfLine(Printer.UNKNOWN_LINE_NUMBER); + this.printer.print(" * "); + this.printer.startOfXdoclet(); + this.printer.print("@deprecated"); + this.printer.endOfXdoclet(); + this.printer.print(" */"); + this.printer.endOfJavadoc(); + endOfLine(); + this.printer.startOfLine(searchFirstLineNumber()); + break; + case 3: + this.printer.startOfJavadoc(); + this.printer.print("/**"); + endOfLine(); + this.printer.startOfLine(Printer.UNKNOWN_LINE_NUMBER); + this.printer.print(" * "); + this.printer.startOfXdoclet(); + this.printer.print("@deprecated"); + this.printer.endOfXdoclet(); + endOfLine(); + this.printer.startOfLine(Printer.UNKNOWN_LINE_NUMBER); + this.printer.print(" */"); + this.printer.endOfJavadoc(); + endOfLine(); + this.printer.startOfLine(searchFirstLineNumber()); + break; + } + + this.printer.debugEndOfCommentDeprecatedLayoutBlock(); + } + + private void writeCommentError(LayoutBlock lb) + { + this.printer.debugStartOfCommentDeprecatedLayoutBlock(); + + switch (lb.lineCount) + { + case 0: + this.printer.startOfError(); + this.printer.print("/* Error */ "); + this.printer.endOfError(); + break; + case 1: + this.printer.startOfError(); + this.printer.print("/* Error */"); + this.printer.endOfError(); + endOfLine(); + this.printer.startOfLine(searchFirstLineNumber()); + break; + } + + this.printer.debugEndOfCommentDeprecatedLayoutBlock(); + } + + private void writeAnnotations(AnnotationsLayoutBlock alb) + { + ArrayList annotations = alb.annotations; + int length = annotations.size(); + + if (length > 0) + { + this.printer.debugStartOfLayoutBlock(); + + ReferenceMap referenceMap = this.referenceMap; + ClassFile classFile = alb.classFile; + + if (alb.lineCount == 0) + { + for (int i=0; i 0) + { + this.printer.print(' '); + } + else + { + if (--k > 0) + { + endOfLine(); + this.printer.startOfLine( + Printer.UNKNOWN_LINE_NUMBER); + } + j = annotationsByLine; + } + } + + endOfLine(); + this.printer.startOfLine(searchFirstLineNumber()); + } + + this.printer.debugEndOfLayoutBlock(); + } + } + + private void writeType(TypeNameLayoutBlock tdlb) + { + this.printer.debugStartOfLayoutBlock(); + + ClassFile classFile = tdlb.classFile; + + writeAccessAndType(classFile); + + this.printer.printTypeDeclaration( + classFile.getThisClassName(), classFile.getClassName()); + + if (tdlb.lineCount > 0) + { + endOfLine(); + this.printer.startOfLine(searchFirstLineNumber()); + } + + this.printer.debugEndOfLayoutBlock(); + } + + private void writeAccessAndType(ClassFile classFile) + { + // Affichage de la classe, de l'interface, de l'enum ou de l'annotation + // Check annotation + if ((classFile.access_flags & ClassFileConstants.ACC_ANNOTATION) != 0) + { + // Retrait du flags 'abstract' + classFile.access_flags &= ~ClassFileConstants.ACC_ABSTRACT; + } + + // Access : public private static volatile ... + if ((classFile.access_flags & ClassFileConstants.ACC_ENUM) == 0) + { + if (classFile.isAInnerClass()) + writeAccessNestedClass(classFile.access_flags); + else + writeAccessClass(classFile.access_flags); + } + else + { + if (classFile.isAInnerClass()) + writeAccessNestedEnum(classFile.access_flags); + else + writeAccessEnum(classFile.access_flags); + } + + writeType(classFile.access_flags); + this.printer.print(' '); + } + + private void writeAccessNestedClass(int access_flags) + { + for(int i=0; i 0) + { + endOfLine(); + this.printer.indent(); + this.printer.startOfLine(searchFirstLineNumber()); + this.printer.desindent(); + } + else + { + this.printer.print(' '); + } + + ClassFile classFile = stelb.classFile; + + this.printer.printKeyword("extends"); + this.printer.print(' '); + + String signature = SignatureUtil.CreateTypeName(classFile.getSuperClassName()); + SignatureWriter.WriteSignature( + this.loader, this.printer, this.referenceMap, + classFile, signature); + + this.printer.debugEndOfLayoutBlock(); + } + + private void writeExtendsSuperInterfaces( + ExtendsSuperInterfacesLayoutBlock sielb) + { + writeInterfaces(sielb, sielb.classFile, true); + } + + private void writeImplementsInterfaces( + ImplementsInterfacesLayoutBlock iilb) + { + writeInterfaces(iilb, iilb.classFile, false); + } + + private void writeInterfaces( + LayoutBlock lb, ClassFile classFile, boolean extendsKeyword) + { + this.printer.debugStartOfLayoutBlock(); + //DEBUG this.printer.print('^'); + + if (lb.lineCount > 0) + { + endOfLine(); + this.printer.indent(); + this.printer.startOfLine(searchFirstLineNumber()); + this.printer.desindent(); + } + else + { + this.printer.print(' '); + } + + int[] interfaceIndexes = classFile.getInterfaces(); + ConstantPool constants = classFile.getConstantPool(); + + if (extendsKeyword) + { + this.printer.printKeyword("extends"); + } + else + { + this.printer.printKeyword("implements"); + } + + this.printer.print(' '); + + String signature = SignatureUtil.CreateTypeName( + constants.getConstantClassName(interfaceIndexes[0])); + SignatureWriter.WriteSignature( + this.loader, this.printer, this.referenceMap, + classFile, signature); + + for(int i=1; i 0) + { + endOfLine(); + this.printer.indent(); + this.printer.startOfLine(searchFirstLineNumber()); + this.printer.desindent(); + } + else + { + this.printer.print(' '); + } + + this.printer.printKeyword("extends"); + this.printer.print(' '); + + char[] caSignature = gstelb.caSignature; + SignatureWriter.WriteSignature( + this.loader, this.printer, this.referenceMap, gstelb.classFile, + caSignature, caSignature.length, gstelb.signatureIndex); + + this.printer.debugEndOfLayoutBlock(); + } + + private void writeGenericExtendsSuperInterfaces( + GenericExtendsSuperInterfacesLayoutBlock gsielb) + { + writeGenericInterfaces( + gsielb, gsielb.classFile, gsielb.caSignature, + gsielb.signatureIndex, true); + } + + private void writeGenericImplementsInterfaces( + GenericImplementsInterfacesLayoutBlock giilb) + { + writeGenericInterfaces( + giilb, giilb.classFile, giilb.caSignature, + giilb.signatureIndex, false); + } + + private void writeGenericInterfaces( + LayoutBlock lb, ClassFile classFile, char[] caSignature, + int signatureIndex, boolean extendsKeyword) + { + this.printer.debugStartOfLayoutBlock(); + //DEBUG this.printer.print('^'); + + if (lb.lineCount > 0) + { + endOfLine(); + this.printer.indent(); + this.printer.startOfLine(searchFirstLineNumber()); + this.printer.desindent(); + } + else + { + this.printer.print(' '); + } + + if (extendsKeyword) + { + this.printer.printKeyword("extends"); + } + else + { + this.printer.printKeyword("implements"); + } + + this.printer.print(' '); + + int signatureLength = caSignature.length; + signatureIndex = SignatureWriter.WriteSignature( + this.loader, this.printer, this.referenceMap, classFile, + caSignature, signatureLength, signatureIndex); + + while (signatureIndex < signatureLength) + { + this.printer.print(", "); + signatureIndex = SignatureWriter.WriteSignature( + this.loader, this.printer, this.referenceMap, classFile, + caSignature, signatureLength, signatureIndex); + } + + this.printer.debugEndOfLayoutBlock(); + } + + private void writeStatementBlockStart(LayoutBlock lb) + { + this.printer.debugStartOfStatementsBlockLayoutBlock(); + + switch (lb.lineCount) + { + case 0: + /* A { B + */ + this.printer.print(" { "); + this.printer.indent(); + break; + case 1: + /* A { + * B + */ + this.printer.print(" {"); + endOfLine(); + this.printer.indent(); + this.printer.startOfLine(searchFirstLineNumber()); + break; + default: + /* A + * { + * ... + * B + */ + //DEBUG this.printer.print('^'); + endOfLine(); + this.printer.startOfLine(Printer.UNKNOWN_LINE_NUMBER); + this.printer.print('{'); + endOfLine(); + + this.printer.extraLine(lb.lineCount-2); + + this.printer.indent(); + this.printer.startOfLine(searchFirstLineNumber()); + break; + } + + this.printer.debugEndOfStatementsBlockLayoutBlock( + lb.minimalLineCount, lb.lineCount, lb.maximalLineCount); + } + + private void writeSwitchBlockStart(LayoutBlock lb) + { + this.printer.debugStartOfStatementsBlockLayoutBlock(); + + switch (lb.lineCount) + { + case 0: + /* A { B + */ + this.printer.print(" {"); + break; + case 1: + /* A { + * B + */ + this.printer.print(" {"); + endOfLine(); + this.printer.startOfLine(searchFirstLineNumber()); + break; + default: + /* A + * { + * ... + * B + */ + //DEBUG this.printer.print('^'); + endOfLine(); + this.printer.startOfLine(Printer.UNKNOWN_LINE_NUMBER); + this.printer.print('{'); + endOfLine(); + + this.printer.extraLine(lb.lineCount-2); + + this.printer.startOfLine(searchFirstLineNumber()); + break; + } + + this.printer.debugEndOfStatementsBlockLayoutBlock( + lb.minimalLineCount, lb.lineCount, lb.maximalLineCount); + } + + private void writeStatementsBlockEnd(LayoutBlock lb) + { + this.printer.debugStartOfStatementsBlockLayoutBlock(); + + switch (lb.lineCount) + { + case 0: + /* A } B + */ + this.printer.print(" }"); + this.addSpace = true; + this.printer.desindent(); + break; + case 1: + /* A + * } B + */ + //DEBUG this.printer.print('^'); + endOfLine(); + this.printer.desindent(); + this.printer.startOfLine(searchFirstLineNumber()); + this.printer.print('}'); + this.addSpace = true; + break; + default: + /* A + * ... + * } + * B + */ + //DEBUG this.printer.print('^'); + endOfLine(); + this.printer.desindent(); + + this.printer.extraLine(lb.lineCount-2); + + this.printer.startOfLine(Printer.UNKNOWN_LINE_NUMBER); + this.printer.print('}'); + endOfLine(); + this.printer.startOfLine(searchFirstLineNumber()); + this.addSpace = false; + break; + } + + this.printer.debugEndOfStatementsBlockLayoutBlock( + lb.minimalLineCount, lb.lineCount, lb.maximalLineCount); + } + + private void writeStatementsInnerBodyBlockEnd(LayoutBlock lb) + { + this.printer.debugStartOfStatementsBlockLayoutBlock(); + + switch (lb.lineCount) + { + case 0: + /* A }B + */ + this.printer.print(" }"); + this.printer.desindent(); + break; + case 1: + /* A + * }B + */ + //DEBUG this.printer.print('^'); + endOfLine(); + this.printer.desindent(); + this.printer.startOfLine(searchFirstLineNumber()); + this.printer.print('}'); + break; + default: + /* A + * ... + * }B + */ + //DEBUG this.printer.print('^'); + endOfLine(); + this.printer.desindent(); + + this.printer.extraLine(lb.lineCount-1); + + this.printer.startOfLine(searchFirstLineNumber()); + this.printer.print('}'); + break; + } + + this.printer.debugEndOfStatementsBlockLayoutBlock( + lb.minimalLineCount, lb.lineCount, lb.maximalLineCount); + + this.addSpace = false; + } + + private void writeSwitchBlockEnd(LayoutBlock lb) + { + this.printer.debugStartOfStatementsBlockLayoutBlock(); + + switch (lb.lineCount) + { + case 0: + /* A } B + */ + this.printer.print('}'); + this.addSpace = true; + break; + case 1: + /* A} + * B + */ + this.printer.print('}'); + endOfLine(); + this.printer.startOfLine(searchFirstLineNumber()); + this.addSpace = false; + break; + default: + /* A + * ... + * } + * B + */ + //DEBUG this.printer.print('^'); + endOfLine(); + this.printer.desindent(); + + this.printer.extraLine(lb.lineCount-1); + + this.printer.startOfLine(searchFirstLineNumber()); + this.printer.print('}'); + this.addSpace = false; + break; + } + + this.printer.debugEndOfStatementsBlockLayoutBlock( + lb.minimalLineCount, lb.lineCount, lb.maximalLineCount); + } + + private void writeCaseBlockStart(LayoutBlock lb) + { + this.printer.indent(); + this.printer.debugStartOfCaseBlockLayoutBlock(); + //writeSeparator(lb); + { + int lineCount = lb.lineCount; + + //DEBUG this.printer.print('^'); + + if (lineCount > 0) + { + endOfLine(); + + if (lineCount > 1) + { + this.printer.startOfLine(Printer.UNKNOWN_LINE_NUMBER); + endOfLine(); + + if (lineCount > 2) + { + this.printer.extraLine(lineCount-2); + } + } + + this.printer.startOfLine( + searchFirstLineNumber()); + } + else + { + this.printer.print(' '); + } + } + this.printer.debugEndOfCaseBlockLayoutBlock(); + } + + private void writeCaseBlockEnd(LayoutBlock lb) + { + this.printer.desindent(); + this.printer.debugStartOfCaseBlockLayoutBlock(); + //writeSeparator(lb); + { + int lineCount = lb.lineCount; + + //DEBUG this.printer.print('^'); + + if (lineCount > 0) + { + endOfLine(); + + if (lineCount > 1) + { + this.printer.startOfLine(Printer.UNKNOWN_LINE_NUMBER); + endOfLine(); + + if (lineCount > 2) + { + this.printer.extraLine(lineCount-2); + } + } + + this.printer.startOfLine( + searchFirstLineNumber()); + } + else + { + this.printer.print(' '); + } + } + this.printer.debugEndOfCaseBlockLayoutBlock(); + } + + private void writeForBlockStart(LayoutBlock lb) + { + this.printer.indent(); + this.printer.indent(); + this.printer.debugStartOfSeparatorLayoutBlock(); + { + int lineCount = lb.lineCount; + + //DEBUG this.printer.print('^'); + + if (lineCount > 0) + { + endOfLine(); + + if (lineCount > 1) + { + this.printer.startOfLine(Printer.UNKNOWN_LINE_NUMBER); + endOfLine(); + + if (lineCount > 2) + { + this.printer.extraLine(lineCount-2); + } + } + + this.printer.startOfLine( + searchFirstLineNumber()); + } + } + this.printer.debugEndOfSeparatorLayoutBlock( + lb.minimalLineCount, lb.lineCount, lb.maximalLineCount); + } + + private void writeForBlockEnd(LayoutBlock lb) + { + this.printer.desindent(); + this.printer.desindent(); + } + + private void writeStatementsBlockStartEnd(LayoutBlock lb) + { + this.printer.debugStartOfStatementsBlockLayoutBlock(); + + switch (lb.lineCount) + { + case 0: + /* A {} B + */ + this.printer.print(" {}"); + break; + case 1: + /* A + * {} B + */ + //DEBUG this.printer.print('^'); + endOfLine(); + this.printer.startOfLine(searchFirstLineNumber()); + this.printer.print("{}"); + break; + default: + /* A + * {} + * ... + * B + */ + //DEBUG this.printer.print('^'); + endOfLine(); + this.printer.startOfLine(Printer.UNKNOWN_LINE_NUMBER); + this.printer.print("{}"); + endOfLine(); + + this.printer.extraLine(lb.lineCount-1); + + this.printer.startOfLine(searchFirstLineNumber()); + break; + } + + this.printer.debugEndOfStatementsBlockLayoutBlock( + lb.minimalLineCount, lb.lineCount, lb.maximalLineCount); + } + + private void writeSingleStatementsBlockStart(LayoutBlock lb) + { + this.printer.debugStartOfStatementsBlockLayoutBlock(); + + switch (lb.lineCount) + { + case 0: + /* A B + */ + if (((BlockLayoutBlock)lb).other.lineCount > 0) + { + this.printer.print(" {"); + } + + this.printer.print(' '); + this.printer.indent(); + break; + case 1: + /* A { + * B + */ + //DEBUG this.printer.print('^'); + + if (((BlockLayoutBlock)lb).other.lineCount > 0) + { + this.printer.print(" {"); + } + + endOfLine(); + this.printer.indent(); + this.printer.startOfLine(searchFirstLineNumber()); + break; + default: + /* A + * { + * ... + * B + */ + //DEBUG this.printer.print('^'); + endOfLine(); + this.printer.startOfLine(Printer.UNKNOWN_LINE_NUMBER); + this.printer.print('{'); + endOfLine(); + + this.printer.extraLine(lb.lineCount-2); + + this.printer.indent(); + this.printer.startOfLine(searchFirstLineNumber()); + break; + } + + this.printer.debugEndOfStatementsBlockLayoutBlock( + lb.minimalLineCount, lb.lineCount, lb.maximalLineCount); + } + + private void writeSingleStatementsBlockEnd(LayoutBlock lb) + { + this.printer.debugStartOfStatementsBlockLayoutBlock(); + + switch (lb.lineCount) + { + case 0: + /* A B + */ + if (((BlockLayoutBlock)lb).other.lineCount > 1) + { + this.printer.print(" }"); + } + + this.addSpace = true; + this.printer.desindent(); + break; + case 1: + /* A + * } B + */ + //DEBUG this.printer.print('^'); + endOfLine(); + this.printer.desindent(); + this.printer.startOfLine(searchFirstLineNumber()); + this.printer.print('}'); + this.addSpace = true; + break; + default: + /* A + * ... + * } + * B + */ + //DEBUG this.printer.print('^'); + endOfLine(); + this.printer.desindent(); + + this.printer.extraLine(lb.lineCount-2); + + this.printer.startOfLine(Printer.UNKNOWN_LINE_NUMBER); + this.printer.print('}'); + endOfLine(); + this.printer.startOfLine(searchFirstLineNumber()); + this.addSpace = false; + break; + } + + this.printer.debugEndOfStatementsBlockLayoutBlock( + lb.minimalLineCount, lb.lineCount, lb.maximalLineCount); + } + + private void writeSingleStatementsBlockStartEnd(LayoutBlock lb) + { + this.printer.debugStartOfStatementsBlockLayoutBlock(); + + switch (lb.lineCount) + { + case 0: + /* A B + */ + this.printer.print(" ;"); + break; + default: + /* A ; + * ... + * B + */ + this.printer.print(" ;"); + endOfLine(); + + this.printer.extraLine(lb.lineCount-1); + + this.printer.indent(); + this.printer.startOfLine(searchFirstLineNumber()); + break; + } + + this.printer.debugEndOfStatementsBlockLayoutBlock( + lb.minimalLineCount, lb.lineCount, lb.maximalLineCount); + } + + private void writeField(FieldNameLayoutBlock flb) + { + ClassFile classFile = flb.classFile; + Field field = flb.field; + + writeAccessField(field.access_flags); + + ConstantPool constants = classFile.getConstantPool(); + + AttributeSignature as = field.getAttributeSignature(); + int signatureIndex = (as == null) ? + field.descriptor_index : as.signature_index; + + String signature = constants.getConstantUtf8(signatureIndex); + + SignatureWriter.WriteSignature( + this.loader, this.printer, this.referenceMap, + classFile, signature); + this.printer.print(' '); + + String fieldName = constants.getConstantUtf8(field.name_index); + if (keywords.contains(fieldName)) + fieldName = StringConstants.JD_FIELD_PREFIX + fieldName; + + String internalClassName = classFile.getThisClassName(); + String descriptor = constants.getConstantUtf8(field.descriptor_index); + + if ((field.access_flags & ClassFileConstants.ACC_STATIC) != 0) + this.printer.printStaticFieldDeclaration( + internalClassName, fieldName, descriptor); + else + this.printer.printFieldDeclaration( + internalClassName, fieldName, descriptor); + + if (field.getValueAndMethod() != null) + { + this.printer.print(" = "); + // La valeur du champ sera affichee par le bloc + // 'InstructionsLayoutBlock' suivant. + } + else + { + ConstantValue cv = field.getConstantValue(constants); + + if (cv != null) + { + this.printer.print(" = "); + ConstantValueWriter.Write( + this.loader, this.printer, this.referenceMap, + classFile, cv, (byte)signature.charAt(0)); + this.printer.print(';'); + } + else + { + this.printer.print(';'); + } + } + } + + private void writeAccessField(int access_flags) + { + for(int i=0; i 0) + { + endOfLine(); + this.printer.indent(); + this.printer.startOfLine(searchFirstLineNumber()); + this.printer.desindent(); + } + else + { + this.printer.print(' '); + } + + this.printer.printKeyword("throws"); + this.printer.print(' '); + + ClassFile classFile = tlb.classFile; + ConstantPool constants = classFile.getConstantPool(); + int[] exceptionIndexes = tlb.method.getExceptionIndexes(); + int exceptionIndexesLength = exceptionIndexes.length; + + if (exceptionIndexesLength > 0) + { + String firstInternalClassName = + constants.getConstantClassName(exceptionIndexes[0]); + this.printer.print( + SignatureWriter.InternalClassNameToShortClassName( + this.referenceMap, classFile, firstInternalClassName)); + + for (int j=1; j instructions = ilb.instructions; + + while (index <= lastIndex) + { + Instruction instruction = instructions.get(index); + + if ((index > ilb.firstIndex) || (ilb.firstOffset == 0)) + { + this.instructionPrinter.startOfInstruction(); + } + + this.visitor.visit(instruction); + + if ((index < lastIndex) || (ilb.lastOffset == instruction.offset)) + { + // Ne pas afficher de ';' si une instruction n'a pas ete + // entierement ecrite. + this.instructionPrinter.endOfInstruction(); + this.printer.print(';'); + } + + index++; + } + + this.instructionPrinter.release(); + + this.printer.debugEndOfInstructionBlockLayoutBlock(); + } + + private void writeByteCode(ByteCodeLayoutBlock bclb) + { +// this.printer.debugStartOfStatementsBlockLayoutBlock(); +// +// this.printer.startOfError(); +// this.printer.print("byte-code"); +// this.printer.endOfError(); +// +// endOfLine(); +// this.printer.startOfLine(searchFirstLineNumber()); +// +// this.printer.debugEndOfStatementsBlockLayoutBlock( +// bclb.minimalLineCount, bclb.lineCount, bclb.maximalLineCount); + + ByteCodeWriter.Write( + this.loader, this.printer, this.referenceMap, + bclb.classFile, bclb.method); + } + + private void writeDeclaration(DeclareLayoutBlock dlb) + { + this.printer.debugStartOfInstructionBlockLayoutBlock(); + + if (this.addSpace) + { + this.printer.print(" "); + this.addSpace = false; + } + + this.instructionPrinter.init(dlb.firstLineNumber); + this.visitor.init(dlb.classFile, dlb.method, 0, dlb.instruction.offset); + this.instructionPrinter.startOfInstruction(); + this.visitor.visit(dlb.instruction); + this.instructionPrinter.endOfInstruction(); + this.printer.print(';'); + this.instructionPrinter.release(); + + this.printer.debugEndOfInstructionBlockLayoutBlock(); + } + + private void writeIf(/* InstructionLayoutBlock filb */) + { + if (this.addSpace) + { + this.printer.print(" "); + this.addSpace = false; + } + + this.printer.printKeyword("if"); + this.printer.print(" ("); + } + + private void writeWhile(/* InstructionLayoutBlock filb */) + { + if (this.addSpace) + { + this.printer.print(" "); + this.addSpace = false; + } + + this.printer.printKeyword("while"); + this.printer.print(" ("); + } + + private void writeFor() + { + if (this.addSpace) + { + this.printer.print(" "); + this.addSpace = false; + } + + this.printer.printKeyword("for"); + this.printer.print(" ("); + } + + private void writeLabeledBreak(OffsetLayoutBlock olb) + { + if (this.addSpace) + { + this.printer.print(" "); + this.addSpace = false; + } + + this.printer.printKeyword("break"); + this.printer.print(' '); + this.printer.print(FastConstants.LABEL_PREFIX); + this.printer.print(olb.offset); + this.printer.print(';'); + } + + private void writeRightRoundBracket() + { + this.printer.print(')'); + } + + private void writeRightRoundBracketSemicolon() + { + this.printer.print(");"); + } + + private void writeSemicolon() + { + this.printer.print(';'); + } + + private void writeSemicolonSpace() + { + this.printer.print("; "); + } + + private void writeSpaceColonSpace() + { + this.printer.print(" : "); + } + + private void writeComaSpace() + { + this.printer.print(", "); + } + + private void writeSwitch() + { + if (this.addSpace) + { + this.printer.print(" "); + this.addSpace = false; + } + + this.printer.printKeyword("switch"); + this.printer.print(" ("); + } + + private void writeCase(CaseLayoutBlock clb) + { + if (this.addSpace) + { + this.printer.print(" "); + this.addSpace = false; + } + + String signature = clb.fs.test.getReturnedSignature( + clb.classFile.getConstantPool(), clb.method.getLocalVariables()); + char type = (signature == null) ? 'X' : signature.charAt(0); + + FastSwitch.Pair[] pairs = clb.fs.pairs; + int lineCount = clb.lineCount + 1; + int lastIndex = clb.lastIndex; + int caseCount = lastIndex - clb.firstIndex + 1; + + int caseByLine = caseCount / lineCount; + int middleLineCount = caseCount - caseByLine*lineCount; + int middleIndex = clb.firstIndex + middleLineCount*(caseByLine + 1); + int j = caseByLine + 1; + + for (int i=clb.firstIndex; i 0) + { + if ((j == 1) && (i < lastIndex)) + { + endOfLine(); + this.printer.startOfLine(Printer.UNKNOWN_LINE_NUMBER); + j = caseByLine + 1; + } + else + { + j--; + } + } + } + + j = caseByLine; + + for (int i=middleIndex; i<=lastIndex; i++) + { + FastSwitch.Pair pair = pairs[i]; + + if (pair.isDefault()) + { + this.printer.printKeyword("default"); + this.printer.print(": "); + } + else + { + this.printer.printKeyword("case"); + this.printer.print(' '); + + this.printer.debugStartOfInstructionBlockLayoutBlock(); + if (type == 'C') + { + String escapedString = + StringUtil.EscapeCharAndAppendApostrophe( + (char)pair.getKey()); + this.printer.printString( + escapedString, clb.classFile.getThisClassName()); + } + else + { + this.printer.printNumeric(String.valueOf(pair.getKey())); + } + this.printer.debugEndOfInstructionBlockLayoutBlock(); + + this.printer.print(": "); + } + + if (lineCount > 0) + { + if ((j == 1) && (i < lastIndex)) + { + endOfLine(); + this.printer.startOfLine(Printer.UNKNOWN_LINE_NUMBER); + j = caseByLine; + } + else + { + j--; + } + } + } + } + + private void writeCaseEnum(CaseEnumLayoutBlock celb) + { + if (this.addSpace) + { + this.printer.print(" "); + this.addSpace = false; + } + + ClassFile classFile = celb.classFile; + ConstantPool constants = classFile.getConstantPool(); + List switchMap = + classFile.getSwitchMaps().get(celb.switchMapKeyIndex); + + ArrayLoadInstruction ali = (ArrayLoadInstruction)celb.fs.test; + Invokevirtual iv = (Invokevirtual)ali.indexref; + ConstantMethodref cmr = constants.getConstantMethodref(iv.index); + String internalEnumName = + constants.getConstantClassName(cmr.class_index); + + String enumDescriptor = SignatureUtil.CreateTypeName(internalEnumName); + + FastSwitch.Pair[] pairs = celb.fs.pairs; + int lineCount = celb.lineCount + 1; + int lastIndex = celb.lastIndex; + int caseCount = lastIndex - celb.firstIndex + 1; + + int caseByLine = caseCount / lineCount; + int middleLineCount = caseCount - caseByLine*lineCount; + int middleIndex = celb.firstIndex + middleLineCount*(caseByLine + 1); + int j = caseByLine + 1; + + for (int i=celb.firstIndex; i 0) + { + if ((j == 1) && (i < lastIndex)) + { + endOfLine(); + this.printer.startOfLine(Printer.UNKNOWN_LINE_NUMBER); + j = caseByLine + 1; + } + else + { + j--; + } + } + } + + j = caseByLine; + + for (int i=middleIndex; i<=lastIndex; i++) + { + FastSwitch.Pair pair = pairs[i]; + + if (pair.isDefault()) + { + this.printer.printKeyword("default"); + this.printer.print(": "); + } + else + { + this.printer.printKeyword("case"); + this.printer.print(' '); + + this.printer.debugStartOfInstructionBlockLayoutBlock(); + int key = pair.getKey(); + + if ((0 < key) && (key <= switchMap.size())) + { + String value = constants.getConstantUtf8(switchMap.get(key-1)); + this.printer.printStaticField( + internalEnumName, value, + enumDescriptor, classFile.getThisClassName()); + } + else + { + this.printer.startOfError(); + this.printer.print("???"); + this.printer.endOfError(); + } + this.printer.debugEndOfInstructionBlockLayoutBlock(); + + this.printer.print(": "); + } + + if (lineCount > 0) + { + if ((j == 1) && (i < lastIndex)) + { + endOfLine(); + this.printer.startOfLine(Printer.UNKNOWN_LINE_NUMBER); + j = caseByLine; + } + else + { + j--; + } + } + } + } + + private void writeCaseString(CaseLayoutBlock clb) + { + if (this.addSpace) + { + this.printer.print(" "); + this.addSpace = false; + } + + ClassFile classFile = clb.classFile; + ConstantPool constants = classFile.getConstantPool(); + + FastSwitch.Pair[] pairs = clb.fs.pairs; + int lineCount = clb.lineCount + 1; + int lastIndex = clb.lastIndex; + int caseCount = lastIndex - clb.firstIndex + 1; + + int caseByLine = caseCount / lineCount; + int middleLineCount = caseCount - caseByLine*lineCount; + int middleIndex = clb.firstIndex + middleLineCount*(caseByLine + 1); + int j = caseByLine + 1; + + for (int i=clb.firstIndex; i 0) + { + if ((j == 1) && (i < lastIndex)) + { + endOfLine(); + this.printer.startOfLine(Printer.UNKNOWN_LINE_NUMBER); + j = caseByLine + 1; + } + else + { + j--; + } + } + } + + j = caseByLine; + + for (int i=middleIndex; i<=lastIndex; i++) + { + FastSwitch.Pair pair = pairs[i]; + + if (pair.isDefault()) + { + this.printer.printKeyword("default"); + this.printer.print(": "); + } + else + { + this.printer.printKeyword("case"); + this.printer.print(' '); + + this.printer.debugStartOfInstructionBlockLayoutBlock(); + + ConstantValue cv = constants.getConstantValue(pair.getKey()); + ConstantValueWriter.Write( + this.loader, this.printer, this.referenceMap, + classFile, cv); + + this.printer.debugEndOfInstructionBlockLayoutBlock(); + + this.printer.print(": "); + } + + if (lineCount > 0) + { + if ((j == 1) && (i < lastIndex)) + { + endOfLine(); + this.printer.startOfLine(Printer.UNKNOWN_LINE_NUMBER); + j = caseByLine; + } + else + { + j--; + } + } + } + } + + private void writeCatch(FastCatchLayoutBlock fslb) + { + if (this.addSpace) + { + this.printer.print(" "); + this.addSpace = false; + } + + this.printer.printKeyword("catch"); + this.printer.print(" ("); + + ClassFile classFile = fslb.classFile; + ConstantPool constants = classFile.getConstantPool(); + Method method = fslb.method; + FastCatch fc = fslb.fc; + + writeCatchType(classFile, constants, fc.exceptionTypeIndex); + + if (fc.otherExceptionTypeIndexes != null) + { + int otherExceptionTypeIndexes[] = fc.otherExceptionTypeIndexes; + int otherExceptionTypeIndexesLength = + otherExceptionTypeIndexes.length; + + for (int i=0; i(); + + keywords.add("@interface"); + keywords.add("abstract"); + keywords.add("assert"); + keywords.add("boolean"); + keywords.add("break"); + keywords.add("byte"); + keywords.add("case"); + keywords.add("catch"); + keywords.add("char"); + keywords.add("class"); + keywords.add("const"); + keywords.add("continue"); + keywords.add("default"); + keywords.add("do"); + keywords.add("double"); + keywords.add("else"); + keywords.add("enum"); + keywords.add("extends"); + keywords.add("false"); + keywords.add("final"); + keywords.add("finally"); + keywords.add("float"); + keywords.add("for"); + keywords.add("goto"); + keywords.add("if"); + keywords.add("implements"); + keywords.add("import"); + keywords.add("instanceof"); + keywords.add("int"); + keywords.add("interface"); + keywords.add("long"); + keywords.add("native"); + keywords.add("new"); + keywords.add("null"); + keywords.add("package"); + keywords.add("private"); + keywords.add("protected"); + keywords.add("public"); + keywords.add("return"); + keywords.add("short"); + keywords.add("static"); + keywords.add("strictfp"); + keywords.add("super"); + keywords.add("switch"); + keywords.add("synchronized"); + keywords.add("this"); + keywords.add("throw"); + keywords.add("throws"); + keywords.add("transient"); + keywords.add("true"); + keywords.add("try"); + keywords.add("void"); + keywords.add("volatile"); + keywords.add("while"); + } +} diff --git a/src/jd/core/process/writer/ConstantValueWriter.java b/src/jd/core/process/writer/ConstantValueWriter.java new file mode 100644 index 00000000..7f35feb7 --- /dev/null +++ b/src/jd/core/process/writer/ConstantValueWriter.java @@ -0,0 +1,240 @@ +package jd.core.process.writer; + +import jd.core.loader.Loader; +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.constant.ConstantConstant; +import jd.core.model.classfile.constant.ConstantDouble; +import jd.core.model.classfile.constant.ConstantFloat; +import jd.core.model.classfile.constant.ConstantInteger; +import jd.core.model.classfile.constant.ConstantLong; +import jd.core.model.classfile.constant.ConstantString; +import jd.core.model.classfile.constant.ConstantValue; +import jd.core.model.reference.ReferenceMap; +import jd.core.printer.Printer; +import jd.core.util.StringUtil; + +public class ConstantValueWriter +{ + public static void Write( + Loader loader, Printer printer, ReferenceMap referenceMap, + ClassFile classFile, ConstantValue cv) + { + Write(loader, printer, referenceMap, classFile, cv, (byte)0); + } + + public static void Write( + Loader loader, Printer printer, ReferenceMap referenceMap, + ClassFile classFile, ConstantValue cv, byte constantIntegerType) + { + ConstantPool constants = classFile.getConstantPool(); + + switch (cv.tag) + { + case ConstantConstant.CONSTANT_Double: + { + double d = ((ConstantDouble)cv).bytes; + + if (d == Double.POSITIVE_INFINITY) + { + Write( + loader, printer, referenceMap, classFile, + "java/lang/Double", "POSITIVE_INFINITY", "D"); + } + else if (d == Double.NEGATIVE_INFINITY) + { + Write( + loader, printer, referenceMap, classFile, + "java/lang/Double", "NEGATIVE_INFINITY", "D"); + } + else if (d == Double.NaN) + { + Write( + loader, printer, referenceMap, classFile, + "java/lang/Double", "NaN", "D"); + } + else if (d == Double.MAX_VALUE) + { + Write( + loader, printer, referenceMap, classFile, + "java/lang/Double", "MAX_VALUE", "D"); + } + /* else if (d == Double.MIN_NORMAL) + { + Write( + loader, printer, referenceMap, classFile, + "java/lang/Double", "MIN_NORMAL", "D"); + } */ + else if (d == Double.MIN_VALUE) + { + Write( + loader, printer, referenceMap, classFile, + "java/lang/Double", "MIN_VALUE", "D"); + } + else + { + // TODO Conversion de la valeur en constante ? + String value = String.valueOf(d); + if (value.indexOf('.') == -1) + value += ".0"; + printer.printNumeric(value + 'D'); + } + } + break; + case ConstantConstant.CONSTANT_Float: + { + float value = ((ConstantFloat)cv).bytes; + + if (value == Float.POSITIVE_INFINITY) + { + Write( + loader, printer, referenceMap, classFile, + "java/lang/Float", "POSITIVE_INFINITY", "F"); + } + else if (value == Float.NEGATIVE_INFINITY) + { + Write( + loader, printer, referenceMap, classFile, + "java/lang/Float", "NEGATIVE_INFINITY", "F"); + } + else if (value == Float.NaN) + { + Write( + loader, printer, referenceMap, classFile, + "java/lang/Float", "NaN", "F"); + } + else if (value == Float.MAX_VALUE) + { + Write( + loader, printer, referenceMap, classFile, + "java/lang/Float", "MAX_VALUE", "F"); + } + /* else if (value == Float.MIN_NORMAL) + { + Write( + loader, printer, referenceMap, classFile, + "java/lang/Float", "MIN_NORMAL", "F"); + } */ + else if (value == Float.MIN_VALUE) + { + Write( + loader, printer, referenceMap, classFile, + "java/lang/Float", "MIN_VALUE", "F"); + } + else + { + // TODO Conversion de la valeur en constante ? + String s = String.valueOf(value); + if (s.indexOf('.') == -1) + s += ".0"; + printer.printNumeric(s + 'F'); + } + } + break; + case ConstantConstant.CONSTANT_Integer: + { + int value = ((ConstantInteger)cv).bytes; + + switch (constantIntegerType) + { + case 'Z': + { + printer.printKeyword((value == 0) ? "false" : "true"); + } + break; + case 'C': + { + String escapedString = StringUtil.EscapeCharAndAppendApostrophe((char)value); + String scopeInternalName = classFile.getThisClassName(); + printer.printString(escapedString, scopeInternalName); + } + break; + default: + { + if (value == Integer.MIN_VALUE) + { + Write( + loader, printer, referenceMap, classFile, + "java/lang/Integer", "MIN_VALUE", "I"); + } + else if (value == Integer.MAX_VALUE) + { + Write( + loader, printer, referenceMap, classFile, + "java/lang/Integer", "MAX_VALUE", "I"); + } + else + { + printer.printNumeric(String.valueOf(value)); + } + } + } + } + break; + case ConstantConstant.CONSTANT_Long: + { + long value = ((ConstantLong)cv).bytes; + + if (value == Long.MIN_VALUE) + { + Write( + loader, printer, referenceMap, classFile, + "java/lang/Long", "MIN_VALUE", "J"); + } + else if (value == Long.MAX_VALUE) + { + Write( + loader, printer, referenceMap, classFile, + "java/lang/Long", "MAX_VALUE", "J"); + } + else + { + printer.printNumeric(String.valueOf(value) + 'L'); + } + } + break; + case ConstantConstant.CONSTANT_String: + { + String s = constants.getConstantUtf8( + ((ConstantString)cv).string_index); + String escapedString = + StringUtil.EscapeStringAndAppendQuotationMark(s); + String scopeInternalName = classFile.getThisClassName(); + printer.printString(escapedString, scopeInternalName); + } + break; + } + } + + private static void Write( + Loader loader, Printer printer, ReferenceMap referenceMap, + ClassFile classFile, String internalTypeName, + String name, String descriptor) + { + String className = SignatureWriter.InternalClassNameToClassName( + loader, referenceMap, classFile, internalTypeName); + String scopeInternalName = classFile.getThisClassName(); + printer.printType(internalTypeName, className, scopeInternalName); + printer.print('.'); + printer.printStaticField(internalTypeName, name, descriptor, scopeInternalName); + } + + public static void WriteHexa( + Loader loader, Printer printer, ReferenceMap referenceMap, + ClassFile classFile, ConstantValue cv) + { + switch (cv.tag) + { + case ConstantConstant.CONSTANT_Integer: + printer.printNumeric( + "0x" + Integer.toHexString( ((ConstantInteger)cv).bytes ).toUpperCase()); + break; + case ConstantConstant.CONSTANT_Long: + printer.printNumeric( + "0x" + Long.toHexString( ((ConstantLong)cv).bytes ).toUpperCase()); + break; + default: + Write(loader, printer, referenceMap, classFile, cv, (byte)0); + } + } +} \ No newline at end of file diff --git a/src/jd/core/process/writer/ElementValuePrimitiveTypeWriter.java b/src/jd/core/process/writer/ElementValuePrimitiveTypeWriter.java new file mode 100644 index 00000000..b6a75d97 --- /dev/null +++ b/src/jd/core/process/writer/ElementValuePrimitiveTypeWriter.java @@ -0,0 +1,36 @@ +package jd.core.process.writer; + +import jd.core.loader.Loader; +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.attribute.ElementValuePrimitiveType; +import jd.core.model.classfile.constant.ConstantValue; +import jd.core.model.reference.ReferenceMap; +import jd.core.printer.Printer; +import jd.core.util.StringUtil; + +public class ElementValuePrimitiveTypeWriter +{ + public static void Write( + Loader loader, Printer printer, ReferenceMap referenceMap, + ClassFile classFile, ElementValuePrimitiveType evpt) + { + ConstantPool constants = classFile.getConstantPool(); + + if (evpt.type == 's') + { + String constValue = + constants.getConstantUtf8(evpt.const_value_index); + String escapedString = + StringUtil.EscapeStringAndAppendQuotationMark(constValue); + printer.printString(escapedString, classFile.getThisClassName()); + } + else + { + ConstantValue cv = constants.getConstantValue( + evpt.const_value_index); + ConstantValueWriter.Write( + loader, printer, referenceMap, classFile, cv, evpt.type); + } + } +} diff --git a/src/jd/core/process/writer/ElementValueWriter.java b/src/jd/core/process/writer/ElementValueWriter.java new file mode 100644 index 00000000..d8877d11 --- /dev/null +++ b/src/jd/core/process/writer/ElementValueWriter.java @@ -0,0 +1,84 @@ +package jd.core.process.writer; + +import jd.core.loader.Loader; +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.attribute.ElementValue; +import jd.core.model.classfile.attribute.ElementValueAnnotationValue; +import jd.core.model.classfile.attribute.ElementValueArrayValue; +import jd.core.model.classfile.attribute.ElementValueClassInfo; +import jd.core.model.classfile.attribute.ElementValueContants; +import jd.core.model.classfile.attribute.ElementValueEnumConstValue; +import jd.core.model.classfile.attribute.ElementValuePrimitiveType; +import jd.core.model.reference.ReferenceMap; +import jd.core.printer.Printer; +import jd.core.util.SignatureUtil; + +public class ElementValueWriter +{ + public static void WriteElementValue( + Loader loader, Printer printer, ReferenceMap referenceMap, + ClassFile classFile, ElementValue ev) + { + ConstantPool constants = classFile.getConstantPool(); + + switch (ev.tag) + { + case ElementValueContants.EV_PRIMITIVE_TYPE: + ElementValuePrimitiveType evpt = (ElementValuePrimitiveType)ev; + ElementValuePrimitiveTypeWriter.Write( + loader, printer, referenceMap, classFile, evpt); + break; + + case ElementValueContants.EV_CLASS_INFO: + ElementValueClassInfo evci = (ElementValueClassInfo)ev; + String signature = + constants.getConstantUtf8(evci.class_info_index); + SignatureWriter.WriteSignature( + loader, printer, referenceMap, classFile, signature); + printer.print('.'); + printer.printKeyword("class"); + break; + + case ElementValueContants.EV_ANNOTATION_VALUE: + ElementValueAnnotationValue evav = (ElementValueAnnotationValue)ev; + AnnotationWriter.WriteAnnotation( + loader, printer, referenceMap, + classFile, evav.annotation_value); + break; + + case ElementValueContants.EV_ARRAY_VALUE: + ElementValueArrayValue evarv = (ElementValueArrayValue)ev; + ElementValue[] values = evarv.values; + printer.print('{'); + + if ((values != null) && (values.length > 0)) + { + WriteElementValue( + loader, printer, referenceMap, classFile, values[0]); + for (int i=1; i +{ + public int compare(Reference o1, Reference o2) { + return o2.getCounter() - o1.getCounter(); + } +} diff --git a/src/jd/core/process/writer/ReferenceByInternalNameComparator.java b/src/jd/core/process/writer/ReferenceByInternalNameComparator.java new file mode 100644 index 00000000..8f54051c --- /dev/null +++ b/src/jd/core/process/writer/ReferenceByInternalNameComparator.java @@ -0,0 +1,12 @@ +package jd.core.process.writer; + +import java.util.Comparator; + +import jd.core.model.reference.Reference; + +public class ReferenceByInternalNameComparator implements Comparator +{ + public int compare(Reference o1, Reference o2) { + return o1.getInternalName().compareTo(o2.getInternalName()); + } +} diff --git a/src/jd/core/process/writer/SignatureWriter.java b/src/jd/core/process/writer/SignatureWriter.java new file mode 100644 index 00000000..0bbf8e2f --- /dev/null +++ b/src/jd/core/process/writer/SignatureWriter.java @@ -0,0 +1,603 @@ +package jd.core.process.writer; + +import java.util.HashSet; + +import jd.core.loader.Loader; +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.ClassFileConstants; +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.LocalVariable; +import jd.core.model.classfile.Method; +import jd.core.model.classfile.attribute.ParameterAnnotations; +import jd.core.model.reference.ReferenceMap; +import jd.core.printer.Printer; +import jd.core.util.CharArrayUtil; +import jd.core.util.SignatureFormatException; +import jd.core.util.SignatureUtil; +import jd.core.util.StringConstants; + +public class SignatureWriter +{ + public static void WriteTypeDeclaration( + Loader loader, Printer printer, ReferenceMap referenceMap, + ClassFile classFile, String signature) + { + char[] caSignature = signature.toCharArray(); + int length = caSignature.length; + + // Affichage du nom de type + printer.printTypeDeclaration( + classFile.getThisClassName(), classFile.getClassName()); + + // Affichage des generics + WriteGenerics( + loader, printer, referenceMap, classFile, caSignature, length, 0); + } + + public static int WriteConstructor( + Loader loader, Printer printer, ReferenceMap referenceMap, + ClassFile classFile, String signature, String descriptor) + { + char[] caSignature = signature.toCharArray(); + return WriteSignature( + loader, printer, referenceMap, classFile, + caSignature, caSignature.length, 0, true, descriptor, false); + } + + public static void WriteMethodDeclaration( + HashSet keywordSet, Loader loader, Printer printer, + ReferenceMap referenceMap, ClassFile classFile, Method method, + String signature, boolean descriptorFlag) + { + char[] caSignature = signature.toCharArray(); + int length = caSignature.length; + int index = 0; + + // Affichage des generics + int newIndex = WriteGenerics( + loader, printer, referenceMap, classFile, + caSignature, length, index); + + if (newIndex != index) { + printer.print(' '); + index = newIndex; + } + + if (caSignature[index] != '(') + throw new SignatureFormatException(signature); + + // pass '(' + index++; + + ConstantPool constants = classFile.getConstantPool(); + String internalClassName = classFile.getThisClassName(); + String descriptor = constants.getConstantUtf8(method.descriptor_index); + boolean staticMethodFlag = ((method.access_flags & ClassFileConstants.ACC_STATIC) != 0); + + if (method.name_index == constants.instanceConstructorIndex) + { + printer.printConstructorDeclaration(internalClassName, classFile.getClassName(), descriptor); + } + else + { + // search ')' + newIndex = index; + + while (newIndex < length) { + if (caSignature[newIndex++] == ')') + break; + } + + WriteSignature( + loader, printer, referenceMap, classFile, + caSignature, length, newIndex, false, null, false); + + printer.print(' '); + + String methodName = constants.getConstantUtf8(method.name_index); + if (keywordSet.contains(methodName)) + methodName = StringConstants.JD_METHOD_PREFIX + methodName; + + if (staticMethodFlag) + printer.printStaticMethodDeclaration(internalClassName, methodName, descriptor); + else + printer.printMethodDeclaration(internalClassName, methodName, descriptor); + } + + // Arguments + // Constructeur des classes interne non static : + // - var 1: outer this => ne pas generer de nom + // Constructeur des Enum : + // Descripteur: + // - var 1: nom de la valeur => ne pas afficher + // - var 2: index de la valeur => ne pas afficher + // Signature: + // - variableIndex = 1 + 1 + 1 + // Le premier parametre des m�thodes non statiques est 'this' + printer.print('('); + + int variableIndex = staticMethodFlag ? 0 : 1; + int firstVisibleParameterIndex = 0; + + if (method.name_index == constants.instanceConstructorIndex) { + if ((classFile.access_flags & ClassFileConstants.ACC_ENUM) != 0) { + if (descriptorFlag) + firstVisibleParameterIndex = 2; + else + variableIndex = 3; + } else if (classFile.isAInnerClass()) { + if ((classFile.access_flags & ClassFileConstants.ACC_STATIC) == 0) + firstVisibleParameterIndex = 1; + } + } + + // Parameter annotations + ParameterAnnotations[] invisibleParameterAnnotations = method.getInvisibleParameterAnnotations(); + ParameterAnnotations[] visibleParameterAnnotations = method.getVisibleParameterAnnotations(); + int parameterIndex = 0; + int varargsParameterIndex; + + if ((method.access_flags & ClassFileConstants.ACC_VARARGS) == 0) + { + varargsParameterIndex = Integer.MAX_VALUE; + } + else + { + varargsParameterIndex = SignatureUtil.GetParameterSignatureCount(signature) - 1; + } + + while (caSignature[index] != ')') { + char firstChar = caSignature[index]; + + if (parameterIndex >= firstVisibleParameterIndex) { + if (parameterIndex > firstVisibleParameterIndex) + printer.print(", "); + + // Affichage des annotations invisibles + if (invisibleParameterAnnotations != null) + AnnotationWriter.WriteParameterAnnotation( + loader, printer, referenceMap, classFile, + invisibleParameterAnnotations[parameterIndex]); + + // Affichage des annotations visibles + if (visibleParameterAnnotations != null) + AnnotationWriter.WriteParameterAnnotation( + loader, printer, referenceMap, classFile, + visibleParameterAnnotations[parameterIndex]); + + LocalVariable lv = null; + + // TODO Test � retirer. Ce test a ete ajouter lors du codage + // de la gestion des enum pour eviter un NullPointerException + if (method.getLocalVariables() != null) { + lv = method.getLocalVariables().searchLocalVariableWithIndexAndOffset(variableIndex, 0); + + if ((lv != null) && lv.finalFlag) { + printer.printKeyword("final"); + printer.print(' '); + } + } + + index = WriteSignature( + loader, printer, referenceMap, classFile, caSignature, + length, index, false, null, + (parameterIndex==varargsParameterIndex)); + + if (lv != null) { + printer.print(' '); + if (lv.name_index == -1) { + printer.startOfError(); + printer.print("???"); + printer.endOfError(); + } else { + printer.print(constants.getConstantUtf8(lv.name_index)); + } + } else { + printer.print(" arg"); + printer.print(variableIndex); + } + } else { + index = SignatureUtil.SkipSignature(caSignature, length, index); + } + + variableIndex += ((firstChar == 'D') || (firstChar == 'J')) ? 2 : 1; + parameterIndex++; + } + + printer.print(')'); + } + + private static int WriteGenerics( + Loader loader, Printer printer, ReferenceMap referenceMap, + ClassFile classFile, char[] caSignature, int length, int index) + { + if (caSignature[index] == '<') + { + printer.print('<'); + index++; + + while (index < length) + { + int endIndex = CharArrayUtil.IndexOf(caSignature, ':', index); + String templateName = CharArrayUtil.Substring(caSignature, index, endIndex); + printer.print(templateName); + index = endIndex + 1; + + // Mystere ... + if (caSignature[index] == ':') + index++; + + int newIndex = SignatureUtil.SkipSignature(caSignature, length, index); + + if (!IsObjectClass(caSignature, index, newIndex)) + { + printer.print(' '); + printer.printKeyword("extends"); + printer.print(' '); + WriteSignature( + loader, printer, referenceMap, classFile, + caSignature, length, index, false, null, false); + } + + index = newIndex; + + if (caSignature[index] == '>') + break; + + printer.print(", "); + } + printer.print('>'); + index++; + } + + return index; + } + + public static int WriteSignature( + Loader loader, Printer printer, ReferenceMap referenceMap, + ClassFile classFile, char[] caSignature, int length, int index) + { + return WriteSignature( + loader, printer, referenceMap, classFile, + caSignature, length, index, false, null, false); + } + + public static int WriteSignature( + Loader loader, Printer printer, ReferenceMap referenceMap, + ClassFile classFile, String signature) + { + char[] caSignature = signature.toCharArray(); + return WriteSignature( + loader, printer, referenceMap, classFile, + caSignature, caSignature.length, 0, false, null, false); + } + + private static int WriteSignature( + Loader loader, Printer printer, ReferenceMap referenceMap, + ClassFile classFile, char[] caSignature, int length, int index, + boolean constructorFlag, String constructorDescriptor, + boolean varargsFlag) + { + char c; + int beginIndex; + + while (true) { + // Preparation de l'affichage des dimensions du tableau : '[[?' ou + // '[L[?;' + int dimensionLength = 0; + + if (caSignature[index] == '[') { + dimensionLength++; + + while (++index < length) { + if ((caSignature[index] == 'L') && (index + 1 < length) && (caSignature[index + 1] == '[')) { + index++; + length--; + dimensionLength++; + } else if (caSignature[index] == '[') { + dimensionLength++; + } else { + break; + } + } + } + + switch (caSignature[index]) { + case 'B': + printer.printKeyword("byte"); + index++; + break; + case 'C': + printer.printKeyword("char"); + index++; + break; + case 'D': + printer.printKeyword("double"); + index++; + break; + case 'F': + printer.printKeyword("float"); + index++; + break; + case 'I': + printer.printKeyword("int"); + index++; + break; + case 'J': + printer.printKeyword("long"); + index++; + break; + case 'L': + case '.': + boolean typeFlag = (caSignature[index] == 'L'); + beginIndex = ++index; + c = '.'; + + // Recherche de ; ou de < + while (index < length) + { + c = caSignature[index]; + if ((c == ';') || (c == '<')) + break; + index++; + } + + String internalClassName = + CharArrayUtil.Substring(caSignature, beginIndex, index); + + if (typeFlag) + { + String thisClassName = classFile.getThisClassName(); + + if (constructorFlag) + { + printer.printConstructor( + internalClassName, + InternalClassNameToClassName( + loader, referenceMap, classFile, internalClassName), + constructorDescriptor, + thisClassName); + } + else + { + printer.printType( + internalClassName, + InternalClassNameToClassName( + loader, referenceMap, classFile, internalClassName), + thisClassName); + } + } + else + { + printer.print(InternalClassNameToClassName( + loader, referenceMap, classFile, internalClassName)); + } + + if (c == '<') { + printer.print('<'); + index = WriteSignature( + loader, printer, referenceMap, classFile, + caSignature, length, index + 1, false, null, false); + + while (caSignature[index] != '>') { + printer.print(", "); + index = WriteSignature( + loader, printer, referenceMap, classFile, + caSignature, length, index, false, null, false); + } + printer.print('>'); + + // pass '>' + index++; + } + + // pass ';' + if (caSignature[index] == ';') + index++; + break; + case 'S': + printer.printKeyword("short"); + index++; + break; + case 'T': + beginIndex = ++index; + index = CharArrayUtil.IndexOf(caSignature, ';', beginIndex); + printer.print(new String(caSignature, beginIndex, index - beginIndex)); + index++; + break; + case 'V': + printer.printKeyword("void"); + index++; + break; + case 'Z': + printer.printKeyword("boolean"); + index++; + break; + case '-': + printer.print("? "); + printer.printKeyword("super"); + printer.print(' '); + index = WriteSignature( + loader, printer, referenceMap, classFile, + caSignature, length, index + 1, false, null, false); + break; + case '+': + printer.print("? "); + printer.printKeyword("extends"); + printer.print(' '); + index = WriteSignature( + loader, printer, referenceMap, classFile, + caSignature, length, index + 1, false, null, false); + break; + case '*': + printer.print('?'); + index++; + break; + case 'X': + case 'Y': + printer.printKeyword("int"); + System.err.println(""); + index++; + break; + default: + // DEBUG + new Throwable("SignatureWriter.WriteSignature: invalid signature '" + String.valueOf(caSignature) + "'") + .printStackTrace(); + // DEBUG + } + + if (varargsFlag) + { + if (dimensionLength > 0) + { + while (--dimensionLength > 0) + printer.print("[]"); + printer.print("..."); + } + } + else + { + while (dimensionLength-- > 0) + printer.print("[]"); + } + + if ((index >= length) || (caSignature[index] != '.')) + break; + + printer.print('.'); + } + + return index; + } + + public static String InternalClassNameToClassName( + Loader loader, ReferenceMap referenceMap, + ClassFile classFile, String internalName) + { + if (classFile.getThisClassName().equals(internalName)) + { + // La classe est la classe courante ou l'une de ses classes + // internes + + // Reduction du nom de classe courante + int index = internalName.lastIndexOf(StringConstants.INTERNAL_INNER_SEPARATOR); + if (index >= 0) { + // Reduction des noms de classe interne + internalName = internalName.substring(index + 1); + } else { + index = internalName.lastIndexOf(StringConstants.INTERNAL_PACKAGE_SEPARATOR); + if (index >= 0) + // Retrait du nom du package + internalName = internalName.substring(index + 1); + } + } + else + { + // La classe n'est pas la classe courante ou l'une de ses classes + // internes + int index = internalName.lastIndexOf(StringConstants.INTERNAL_PACKAGE_SEPARATOR); + + if (index != -1) + { + String internalPackageName = internalName.substring(0, index); + + if (classFile.getInternalPackageName().equals(internalPackageName)) + { + // Classe appartenant au m�me package que la classe courante + if (classFile.getInnerClassFile(internalName) != null) + { + // Dans le cas d'une classe interne, on retire le nom + // de la classe externe + internalName = internalName.substring(classFile.getThisClassName().length() + 1); + } + else + { + // Le nom est celui d'une classe appartenant au package + // de la classe courante + internalName = internalName.substring(index + 1); + } + } + else + { + if (referenceMap.contains(internalName)) + { + // Si le nom interne fait parti de la liste des "import" + internalName = internalName.substring(index + 1); + } + else if ("java/lang".equals(internalPackageName)) + { + // Si c'est une classe du package "java.lang" + String internalClassName = + internalName.substring(index + 1); + + String currentPackageNamePlusInternalClassName = + classFile.getInternalPackageName() + + StringConstants.INTERNAL_PACKAGE_SEPARATOR + + internalClassName + + StringConstants.CLASS_FILE_SUFFIX; + + if (loader.canLoad(currentPackageNamePlusInternalClassName)) { + // Une class du package local contient une classe qui + // porte le meme nom que la classe du package "java.lang". + // On conserve le nom du package. + internalName = internalName.replace(StringConstants.INTERNAL_PACKAGE_SEPARATOR, + StringConstants.PACKAGE_SEPARATOR); + } else { + internalName = internalClassName; + } + } else { + // Sinon, on conserve le nom du package + internalName = internalName.replace(StringConstants.INTERNAL_PACKAGE_SEPARATOR, + StringConstants.PACKAGE_SEPARATOR); + } + } + } + } + + return internalName.replace(StringConstants.INTERNAL_INNER_SEPARATOR, StringConstants.INNER_SEPARATOR); + } + + public static String InternalClassNameToShortClassName( + ReferenceMap referenceMap, ClassFile classFile, String internalClassName) + { + int index = internalClassName.lastIndexOf(StringConstants.INTERNAL_PACKAGE_SEPARATOR); + + if (index != -1) + { + String aPackageName = internalClassName.substring(0, index); + + if (classFile.getInternalPackageName().equals(aPackageName)) + { + internalClassName = internalClassName.substring(index + 1); + } + else + { + if (referenceMap.contains(internalClassName)) + internalClassName = internalClassName.substring(index + 1); + else + internalClassName = internalClassName.replace( + StringConstants.INTERNAL_PACKAGE_SEPARATOR, + StringConstants.PACKAGE_SEPARATOR); + } + } + + return internalClassName.replace( + StringConstants.INTERNAL_INNER_SEPARATOR, + StringConstants.INNER_SEPARATOR); + } + + private static boolean IsObjectClass(char[] caSignature, int beginIndex, int endIndex) + { + int length = StringConstants.INTERNAL_OBJECT_SIGNATURE.length(); + + if (endIndex-beginIndex == length) + { + return CharArrayUtil.Substring(caSignature, beginIndex, endIndex).equals( + StringConstants.INTERNAL_OBJECT_SIGNATURE); + } + else + { + return false; + } + } +} diff --git a/src/jd/core/process/writer/visitor/SourceWriterVisitor.java b/src/jd/core/process/writer/visitor/SourceWriterVisitor.java new file mode 100644 index 00000000..f732663f --- /dev/null +++ b/src/jd/core/process/writer/visitor/SourceWriterVisitor.java @@ -0,0 +1,2599 @@ +package jd.core.process.writer.visitor; + +import java.util.HashSet; +import java.util.List; + +import jd.core.loader.Loader; +import jd.core.model.classfile.ClassFile; +import jd.core.model.classfile.ClassFileConstants; +import jd.core.model.classfile.ConstantPool; +import jd.core.model.classfile.Field; +import jd.core.model.classfile.LocalVariable; +import jd.core.model.classfile.LocalVariables; +import jd.core.model.classfile.Method; +import jd.core.model.classfile.constant.Constant; +import jd.core.model.classfile.constant.ConstantClass; +import jd.core.model.classfile.constant.ConstantConstant; +import jd.core.model.classfile.constant.ConstantFieldref; +import jd.core.model.classfile.constant.ConstantMethodref; +import jd.core.model.classfile.constant.ConstantNameAndType; +import jd.core.model.classfile.constant.ConstantUtf8; +import jd.core.model.classfile.constant.ConstantValue; +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.ALoad; +import jd.core.model.instruction.bytecode.instruction.ANewArray; +import jd.core.model.instruction.bytecode.instruction.AThrow; +import jd.core.model.instruction.bytecode.instruction.ArrayLength; +import jd.core.model.instruction.bytecode.instruction.ArrayLoadInstruction; +import jd.core.model.instruction.bytecode.instruction.ArrayStoreInstruction; +import jd.core.model.instruction.bytecode.instruction.AssertInstruction; +import jd.core.model.instruction.bytecode.instruction.AssignmentInstruction; +import jd.core.model.instruction.bytecode.instruction.BinaryOperatorInstruction; +import jd.core.model.instruction.bytecode.instruction.CheckCast; +import jd.core.model.instruction.bytecode.instruction.ComplexConditionalBranchInstruction; +import jd.core.model.instruction.bytecode.instruction.ConstInstruction; +import jd.core.model.instruction.bytecode.instruction.ConvertInstruction; +import jd.core.model.instruction.bytecode.instruction.DupLoad; +import jd.core.model.instruction.bytecode.instruction.DupStore; +import jd.core.model.instruction.bytecode.instruction.ExceptionLoad; +import jd.core.model.instruction.bytecode.instruction.GetField; +import jd.core.model.instruction.bytecode.instruction.GetStatic; +import jd.core.model.instruction.bytecode.instruction.Goto; +import jd.core.model.instruction.bytecode.instruction.IConst; +import jd.core.model.instruction.bytecode.instruction.IInc; +import jd.core.model.instruction.bytecode.instruction.IfCmp; +import jd.core.model.instruction.bytecode.instruction.IfInstruction; +import jd.core.model.instruction.bytecode.instruction.IncInstruction; +import jd.core.model.instruction.bytecode.instruction.IndexInstruction; +import jd.core.model.instruction.bytecode.instruction.InitArrayInstruction; +import jd.core.model.instruction.bytecode.instruction.InstanceOf; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.InvokeNew; +import jd.core.model.instruction.bytecode.instruction.InvokeNoStaticInstruction; +import jd.core.model.instruction.bytecode.instruction.Invokestatic; +import jd.core.model.instruction.bytecode.instruction.Jsr; +import jd.core.model.instruction.bytecode.instruction.LoadInstruction; +import jd.core.model.instruction.bytecode.instruction.LookupSwitch; +import jd.core.model.instruction.bytecode.instruction.MultiANewArray; +import jd.core.model.instruction.bytecode.instruction.NewArray; +import jd.core.model.instruction.bytecode.instruction.Pop; +import jd.core.model.instruction.bytecode.instruction.PutField; +import jd.core.model.instruction.bytecode.instruction.PutStatic; +import jd.core.model.instruction.bytecode.instruction.ReturnInstruction; +import jd.core.model.instruction.bytecode.instruction.StoreInstruction; +import jd.core.model.instruction.bytecode.instruction.TableSwitch; +import jd.core.model.instruction.bytecode.instruction.TernaryOpStore; +import jd.core.model.instruction.bytecode.instruction.TernaryOperator; +import jd.core.model.instruction.bytecode.instruction.UnaryOperatorInstruction; +import jd.core.model.instruction.fast.FastConstants; +import jd.core.model.instruction.fast.instruction.FastDeclaration; +import jd.core.model.reference.ReferenceMap; +import jd.core.printer.InstructionPrinter; +import jd.core.process.writer.ConstantValueWriter; +import jd.core.process.writer.SignatureWriter; +import jd.core.util.SignatureUtil; +import jd.core.util.StringConstants; +import jd.core.util.StringUtil; +import jd.core.util.UtilConstants; + + +public class SourceWriterVisitor +{ + protected Loader loader; + protected InstructionPrinter printer; + protected ReferenceMap referenceMap; + protected HashSet keywordSet; + protected ConstantPool constants; + protected LocalVariables localVariables; + + protected ClassFile classFile; + protected int methodAccessFlags; + protected int firstOffset; + protected int lastOffset; + protected int previousOffset; + + public SourceWriterVisitor( + Loader loader, + InstructionPrinter printer, + ReferenceMap referenceMap, + HashSet keywordSet) + { + this.loader = loader; + this.printer = printer; + this.referenceMap = referenceMap; + this.keywordSet = keywordSet; + } + + /* + * Affichage de toutes les instructions avec + * - firstOffset <= offset + * - offset <= lastOffset + */ + public void init( + ClassFile classFile, Method method, int firstOffset, int lastOffset) + { + this.classFile = classFile; + this.firstOffset = firstOffset; + this.lastOffset = lastOffset; + this.previousOffset = 0; + + if ((classFile == null) || (method == null)) + { + this.constants = null; + this.methodAccessFlags = 0; + this.localVariables = null; + } + else + { + this.constants = classFile.getConstantPool(); + this.methodAccessFlags = method.access_flags; + this.localVariables = method.getLocalVariables(); + } + } + + public int visit(Instruction instruction) + { + int lineNumber = instruction.lineNumber; + + if ((instruction.offset < this.firstOffset) || + (this.previousOffset > this.lastOffset)) + return lineNumber; + + switch (instruction.opcode) + { + case ByteCodeConstants.ARRAYLENGTH: + { + lineNumber = visit(instruction, ((ArrayLength)instruction).arrayref); + + if ((this.firstOffset <= this.previousOffset) && + (instruction.offset <= this.lastOffset)) + { + this.printer.print(lineNumber, '.'); + this.printer.printJavaWord("length"); + } + } + break; + case ByteCodeConstants.ARRAYLOAD: + { + ArrayLoadInstruction ali = (ArrayLoadInstruction)instruction; + lineNumber = writeArray(ali, ali.arrayref, ali.indexref); + } + break; + case ByteCodeConstants.AASTORE: + case ByteCodeConstants.ARRAYSTORE: + { + ArrayStoreInstruction asi = (ArrayStoreInstruction)instruction; + lineNumber = writeArray(asi, asi.arrayref, asi.indexref); + + int nextOffset = this.previousOffset + 1; + if ((this.firstOffset <= nextOffset) && + (nextOffset <= this.lastOffset)) + this.printer.print(lineNumber, " = "); + + lineNumber = visit(asi, asi.valueref); + } + break; + case ByteCodeConstants.ANEWARRAY: + { + ANewArray newArray = (ANewArray)instruction; + Instruction dimension = newArray.dimension; + + String signature = constants.getConstantClassName(newArray.index); + + if (signature.charAt(0) != '[') + signature = SignatureUtil.CreateTypeName(signature); + + String signatureWithoutArray = + SignatureUtil.CutArrayDimensionPrefix(signature); + + int nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + { + this.printer.printKeyword(lineNumber, "new"); + this.printer.print(' '); + + SignatureWriter.WriteSignature( + this.loader, this.printer, this.referenceMap, + this.classFile, signatureWithoutArray); + + this.printer.print(lineNumber, '['); + } + + lineNumber = visit(dimension); + + if ((this.firstOffset <= this.previousOffset) && + (instruction.offset <= this.lastOffset)) + { + this.printer.print(lineNumber, ']'); + + int dimensionCount = + signature.length() - signatureWithoutArray.length(); + + for (int i=dimensionCount; i>0; --i) + this.printer.print(lineNumber, "[]"); + } + } + break; + case ByteCodeConstants.ACONST_NULL: + { + if ((this.firstOffset <= this.previousOffset) && + (instruction.offset <= this.lastOffset)) + this.printer.printKeyword(lineNumber, "null"); + } + break; + case ByteCodeConstants.ASSERT: + { + AssertInstruction ai = (AssertInstruction)instruction; + + int nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + { + this.printer.printKeyword(lineNumber, "assert"); + this.printer.print(' '); + } + + lineNumber = visit(ai, ai.test); + + if (ai.msg != null) + { + nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (ai.msg.offset <= this.lastOffset)) + this.printer.print(lineNumber, " : "); + + lineNumber = visit(ai, ai.msg); + } + } + break; + case ByteCodeConstants.ASSIGNMENT: + lineNumber = writeAssignmentInstruction( + (AssignmentInstruction)instruction); + break; + case ByteCodeConstants.ATHROW: + { + AThrow athrow = (AThrow)instruction; + int nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + { + this.printer.printKeyword(lineNumber, "throw"); + this.printer.print(' '); + } + + lineNumber = visit(athrow, athrow.value); + } + break; + case ByteCodeConstants.UNARYOP: + { + UnaryOperatorInstruction ioi = + (UnaryOperatorInstruction)instruction; + + int nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + this.printer.print(lineNumber, ioi.operator); + + lineNumber = visit(ioi, ioi.value); + } + break; + case ByteCodeConstants.BINARYOP: + lineNumber = writeBinaryOperatorInstruction( + (BinaryOperatorInstruction)instruction); + break; + case ByteCodeConstants.BIPUSH: + case ByteCodeConstants.SIPUSH: + case ByteCodeConstants.ICONST: + lineNumber = writeBIPush_SIPush_IConst((IConst)instruction); + break; + case ByteCodeConstants.LCONST: + if ((this.firstOffset <= this.previousOffset) && + (instruction.offset <= this.lastOffset)) + { + this.printer.printNumeric(lineNumber, + String.valueOf(((ConstInstruction)instruction).value) + 'L'); + } + break; + case ByteCodeConstants.FCONST: + if ((this.firstOffset <= this.previousOffset) && + (instruction.offset <= this.lastOffset)) + { + String value = + String.valueOf(((ConstInstruction)instruction).value); + if (value.indexOf('.') == -1) + value += ".0"; + this.printer.printNumeric(lineNumber, value + 'F'); + } + break; + case ByteCodeConstants.DCONST: + if ((this.firstOffset <= this.previousOffset) && + (instruction.offset <= this.lastOffset)) + { + String value = + String.valueOf(((ConstInstruction)instruction).value); + if (value.indexOf('.') == -1) + value += ".0"; + this.printer.printNumeric(lineNumber, value + 'D'); + } + break; + case ByteCodeConstants.CONVERT: + lineNumber = writeConvertInstruction( + (ConvertInstruction)instruction); + break; + case ByteCodeConstants.IMPLICITCONVERT: + lineNumber = visit(((ConvertInstruction)instruction).value); + break; + case ByteCodeConstants.CHECKCAST: + { + CheckCast checkCast = (CheckCast)instruction; + + int nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + { + this.printer.print(lineNumber, '('); + + String signature; + Constant c = constants.get(checkCast.index); + + if (c.tag == ConstantConstant.CONSTANT_Utf8) + { + ConstantUtf8 cutf8 = (ConstantUtf8)c; + signature = cutf8.bytes; + } + else + { + ConstantClass cc = (ConstantClass)c; + signature = constants.getConstantUtf8(cc.name_index); + if (signature.charAt(0) != '[') + signature = SignatureUtil.CreateTypeName(signature); + } + + SignatureWriter.WriteSignature( + this.loader, this.printer, this.referenceMap, + this.classFile, signature); + + this.printer.print(')'); + } + + lineNumber = visit(checkCast, checkCast.objectref); + } + break; + case FastConstants.DECLARE: + lineNumber = writeDeclaration((FastDeclaration)instruction); + break; + case ByteCodeConstants.DUPSTORE: + { + DupStore dupStore = (DupStore)instruction; + + int nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + { + this.printer.print( + lineNumber, StringConstants.TMP_LOCAL_VARIABLE_NAME); + this.printer.print(instruction.offset); + this.printer.print('_'); + this.printer.print( + ((DupStore)instruction).objectref.offset); + this.printer.print(" = "); + } + + lineNumber = visit(instruction, dupStore.objectref); + } + break; + case ByteCodeConstants.DUPLOAD: + { + int nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + { + this.printer.print( + lineNumber, StringConstants.TMP_LOCAL_VARIABLE_NAME); + this.printer.print(instruction.offset); + this.printer.print('_'); + this.printer.print( + ((DupLoad)instruction).dupStore.objectref.offset); + } + } + break; + case FastConstants.ENUMVALUE: + lineNumber = writeEnumValueInstruction((InvokeNew)instruction); + break; + case ByteCodeConstants.GETFIELD: + writeGetField((GetField)instruction); + break; + case ByteCodeConstants.GETSTATIC: + lineNumber = writeGetStatic((GetStatic)instruction); + break; + case ByteCodeConstants.OUTERTHIS: + lineNumber = writeOuterThis((GetStatic)instruction); + break; + case ByteCodeConstants.GOTO: + { + if ((this.firstOffset <= this.previousOffset) && + (instruction.offset <= this.lastOffset)) + { + Goto gotoInstruction = (Goto)instruction; + this.printer.printKeyword(lineNumber, "goto"); + this.printer.print(' '); + this.printer.print( + lineNumber, gotoInstruction.GetJumpOffset()); + } + } + break; + case FastConstants.GOTO_CONTINUE: + if ((this.firstOffset <= this.previousOffset) && + (instruction.offset <= this.lastOffset)) + { + this.printer.printKeyword(lineNumber, "continue"); + } + break; + case FastConstants.GOTO_BREAK: + if ((this.firstOffset <= this.previousOffset) && + (instruction.offset <= this.lastOffset)) + { + this.printer.printKeyword(lineNumber, "break"); + } + break; + case ByteCodeConstants.IF: + lineNumber = writeIfTest((IfInstruction)instruction); + break; + case ByteCodeConstants.IFCMP: + lineNumber = writeIfCmpTest((IfCmp)instruction); + break; + case ByteCodeConstants.IFXNULL: + lineNumber = writeIfXNullTest((IfInstruction)instruction); + break; + case FastConstants.COMPLEXIF: + lineNumber = writeComplexConditionalBranchInstructionTest( + (ComplexConditionalBranchInstruction)instruction); + break; + case ByteCodeConstants.IINC: + lineNumber = writeIInc((IInc)instruction); + break; + case ByteCodeConstants.PREINC: + lineNumber = writePreInc((IncInstruction)instruction); + break; + case ByteCodeConstants.POSTINC: + lineNumber = writePostInc((IncInstruction)instruction); + break; + case ByteCodeConstants.INVOKENEW: + lineNumber = writeInvokeNewInstruction((InvokeNew)instruction); + break; + case ByteCodeConstants.INSTANCEOF: + { + InstanceOf instanceOf = (InstanceOf)instruction; + + lineNumber = visit(instanceOf, instanceOf.objectref); + + if ((this.firstOffset <= this.previousOffset) && + (instruction.offset <= this.lastOffset)) + { + this.printer.print(lineNumber, ' '); + this.printer.printKeyword("instanceof"); + this.printer.print(' '); + + // reference to a class, array, or interface + String signature = + constants.getConstantClassName(instanceOf.index); + + if (signature.charAt(0) != '[') + signature = SignatureUtil.CreateTypeName(signature); + + SignatureWriter.WriteSignature( + this.loader, this.printer, this.referenceMap, + this.classFile, signature); + } + } + break; + case ByteCodeConstants.INVOKEINTERFACE: + case ByteCodeConstants.INVOKEVIRTUAL: + lineNumber = writeInvokeNoStaticInstruction( + (InvokeNoStaticInstruction)instruction); + break; + case ByteCodeConstants.INVOKESPECIAL: + lineNumber = writeInvokespecial( + (InvokeNoStaticInstruction)instruction); + break; + case ByteCodeConstants.INVOKESTATIC: + lineNumber = writeInvokestatic((Invokestatic)instruction); + break; + case ByteCodeConstants.JSR: + { + if ((this.firstOffset <= this.previousOffset) && + (instruction.offset <= this.lastOffset)) + { + this.printer.printKeyword(lineNumber, "jsr"); + this.printer.print(' '); + this.printer.print((short)((Jsr)instruction).branch); + } + } + break; + case ByteCodeConstants.LDC: + case ByteCodeConstants.LDC2_W: + lineNumber = writeLcdInstruction((IndexInstruction)instruction); + break; + case ByteCodeConstants.LOAD: + case ByteCodeConstants.ALOAD: + case ByteCodeConstants.ILOAD: + lineNumber = writeLoadInstruction((LoadInstruction)instruction); + break; + case ByteCodeConstants.LOOKUPSWITCH: + { + LookupSwitch lookupSwitch = (LookupSwitch)instruction; + + int nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + { + this.printer.printKeyword(lineNumber, "switch"); + this.printer.print(" ("); + } + + lineNumber = visit(lookupSwitch.key); + + if ((this.firstOffset <= this.previousOffset) && + (instruction.offset <= this.lastOffset)) + { + this.printer.print(lineNumber, ')'); + } + } + break; + case ByteCodeConstants.TABLESWITCH: + { + TableSwitch tableSwitch = (TableSwitch)instruction; + + int nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + { + this.printer.printKeyword(lineNumber, "switch"); + this.printer.print(" ("); + } + + lineNumber = visit(tableSwitch.key); + + if ((this.firstOffset <= this.previousOffset) && + (instruction.offset <= this.lastOffset)) + { + this.printer.print(lineNumber, ')'); + } + } + break; + case ByteCodeConstants.MONITORENTER: + { + if ((this.firstOffset <= this.previousOffset) && + (instruction.offset <= this.lastOffset)) + { + this.printer.startOfError(); + this.printer.printKeyword(lineNumber, "monitorenter"); + this.printer.endOfError(); + } + } + break; + case ByteCodeConstants.MONITOREXIT: + { + if ((this.firstOffset <= this.previousOffset) && + (instruction.offset <= this.lastOffset)) + { + this.printer.startOfError(); + this.printer.printKeyword(lineNumber, "monitorexit"); + this.printer.endOfError(); + } + } + break; + case ByteCodeConstants.MULTIANEWARRAY: + lineNumber = writeMultiANewArray((MultiANewArray)instruction); + break; + case ByteCodeConstants.NEW: + { + if ((this.firstOffset <= this.previousOffset) && + (instruction.offset <= this.lastOffset)) + { + this.printer.printKeyword(lineNumber, "new"); + this.printer.print(' '); + this.printer.print( + lineNumber, constants.getConstantClassName( + ((IndexInstruction)instruction).index)); + } + } + break; + case ByteCodeConstants.NEWARRAY: + { + NewArray newArray = (NewArray)instruction; + int nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + { + this.printer.printKeyword(lineNumber, "new"); + this.printer.print(' '); + SignatureWriter.WriteSignature( + this.loader, this.printer, + this.referenceMap, this.classFile, + SignatureUtil.GetSignatureFromType(newArray.type)); + this.printer.print(lineNumber, '['); + } + + lineNumber = visit(newArray.dimension); + + if ((this.firstOffset <= this.previousOffset) && + (instruction.offset <= this.lastOffset)) + this.printer.print(lineNumber, ']'); + } + break; + case ByteCodeConstants.POP: + lineNumber = visit(instruction, ((Pop)instruction).objectref); + break; + case ByteCodeConstants.PUTFIELD: + { + PutField putField = (PutField)instruction; + + ConstantFieldref cfr = constants.getConstantFieldref(putField.index); + ConstantNameAndType cnat = + constants.getConstantNameAndType(cfr.name_and_type_index); + + boolean displayPrefix = false; + + if (this.localVariables.containsLocalVariableWithNameIndex(cnat.name_index)) + { + switch (putField.objectref.opcode) + { + case ByteCodeConstants.ALOAD: + if (((ALoad)putField.objectref).index == 0) + displayPrefix = true; + break; + case ByteCodeConstants.OUTERTHIS: + if (!needAPrefixForThisField( + cnat.name_index, cnat.descriptor_index, + (GetStatic)putField.objectref)) + displayPrefix = true; + break; + } + } + + if ((this.firstOffset <= this.previousOffset) && + (putField.objectref.offset <= this.lastOffset)) + { + if (displayPrefix == false) + { + this.printer.addNewLinesAndPrefix(lineNumber); + this.printer.startOfOptionalPrefix(); + } + + lineNumber = visit(putField, putField.objectref); + this.printer.print(lineNumber, '.'); + + if (displayPrefix == false) + { + this.printer.endOfOptionalPrefix(); + } + } + + String fieldName = + constants.getConstantUtf8(cnat.name_index); + if (this.keywordSet.contains(fieldName)) + fieldName = StringConstants.JD_FIELD_PREFIX + fieldName; + + int nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + { + String internalClassName = + this.constants.getConstantClassName(cfr.class_index); + String descriptor = + this.constants.getConstantUtf8(cnat.descriptor_index); + this.printer.printField( + lineNumber, internalClassName, fieldName, + descriptor, this.classFile.getThisClassName()); + this.printer.print(" = "); + } + + lineNumber = visit(putField, putField.valueref); + } + break; + case ByteCodeConstants.PUTSTATIC: + lineNumber = writePutStatic((PutStatic)instruction); + break; + case ByteCodeConstants.RET: + { + if ((this.firstOffset <= this.previousOffset) && + (instruction.offset <= this.lastOffset)) + { + this.printer.startOfError(); + this.printer.printKeyword(lineNumber, "ret"); + this.printer.endOfError(); + } + } + break; + case ByteCodeConstants.RETURN: + { + if ((this.firstOffset <= this.previousOffset) && + (instruction.offset <= this.lastOffset)) + this.printer.printKeyword(lineNumber, "return"); + } + break; + case ByteCodeConstants.XRETURN: + { + ReturnInstruction ri = (ReturnInstruction)instruction; + + if ((this.firstOffset <= this.previousOffset) && + (instruction.offset <= this.lastOffset)) + { + this.printer.printKeyword(ri.lineNumber, "return"); + this.printer.print(' '); + } + + lineNumber = visit(ri.valueref); + } + break; + case ByteCodeConstants.STORE: + case ByteCodeConstants.ASTORE: + case ByteCodeConstants.ISTORE: + lineNumber = writeStoreInstruction((StoreInstruction)instruction); + break; + case ByteCodeConstants.EXCEPTIONLOAD: + lineNumber = writeExceptionLoad((ExceptionLoad)instruction); + break; + case ByteCodeConstants.RETURNADDRESSLOAD: + { + if ((this.firstOffset <= this.previousOffset) && + (instruction.offset <= this.lastOffset)) + { + this.printer.startOfError(); + this.printer.printKeyword(lineNumber, "returnAddress"); + this.printer.endOfError(); + } + } + break; + case ByteCodeConstants.TERNARYOPSTORE: + { + int nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + { + this.printer.startOfError(); + this.printer.print(lineNumber, "tmpTernaryOp"); + this.printer.print(lineNumber, " = "); + this.printer.endOfError(); + } + + lineNumber = visit( + instruction, ((TernaryOpStore)instruction).objectref); + } + break; + case FastConstants.TERNARYOP: + { + TernaryOperator tp = (TernaryOperator)instruction; + + lineNumber = visit(tp.test); + + int nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + this.printer.print(lineNumber, " ? "); + + lineNumber = visit(tp, tp.value1); + + nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + this.printer.print(lineNumber, " : "); + + lineNumber = visit(tp, tp.value2); + } + break; + case FastConstants.INITARRAY: + lineNumber = WriteInitArrayInstruction( + (InitArrayInstruction)instruction); + break; + case FastConstants.NEWANDINITARRAY: + lineNumber = WriteNewAndInitArrayInstruction( + (InitArrayInstruction)instruction); + break; + case ByteCodeConstants.NOP: + break; + default: + System.err.println( + "Can not write code for " + + instruction.getClass().getName() + + ", opcode=" + instruction.opcode); + } + + this.previousOffset = instruction.offset; + + return lineNumber; + } + + protected int visit(Instruction parent, Instruction child) + { + return visit(parent.getPriority(), child); + } + + protected int visit(int parentPriority, Instruction child) + { + if (parentPriority < child.getPriority()) + { + int nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + this.printer.print(child.lineNumber, '('); + + int lineNumber = visit(child); + + nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + this.printer.print(lineNumber, ')'); + + return lineNumber; + } + else + { + return visit(child); + } + } + + private boolean needAPrefixForThisField( + int fieldNameIndex, int fieldDescriptorIndex, GetStatic getStatic) + { + if (this.classFile.getField(fieldNameIndex, fieldDescriptorIndex) != null) + { + // La classe courante contient un champ ayant le meme nom et la + // meme signature + return true; + } + + ConstantFieldref cfr = + this.constants.getConstantFieldref(getStatic.index); + String getStaticOuterClassName = + this.constants.getConstantClassName(cfr.class_index); + String fieldName = this.constants.getConstantUtf8(fieldNameIndex); + String fieldDescriptor = + this.constants.getConstantUtf8(fieldDescriptorIndex); + + ClassFile outerClassFile = this.classFile.getOuterClass(); + + while (outerClassFile != null) + { + String outerClassName = outerClassFile.getThisClassName(); + if (outerClassName.equals(getStaticOuterClassName)) + break; + + if (outerClassFile.getField(fieldName, fieldDescriptor) != null) + { + // La classe englobante courante contient un champ ayant le + // meme nom et la meme signature + return true; + } + + outerClassFile = outerClassFile.getOuterClass(); + } + + return false; + } + + private int writeBIPush_SIPush_IConst(IConst iconst) + { + int lineNumber = iconst.lineNumber; + + if ((this.firstOffset <= this.previousOffset) && + (iconst.offset <= this.lastOffset)) + { + int value = iconst.value; + String signature = iconst.getSignature(); + + if ("S".equals(signature)) + { + if (((short)value) == Short.MIN_VALUE) + { + writeBIPush_SIPush_IConst( + lineNumber, "java/lang/Short", "MIN_VALUE", "S"); + } + else if (((short)value) == Short.MAX_VALUE) + { + writeBIPush_SIPush_IConst( + lineNumber, "java/lang/Short", "MAX_VALUE", "S"); + } + else + { + this.printer.printNumeric(lineNumber, String.valueOf(value)); + } + } + else if ("B".equals(signature)) + { + if (value == Byte.MIN_VALUE) + { + writeBIPush_SIPush_IConst( + lineNumber, "java/lang/Byte", "MIN_VALUE", "B"); + } + else if (value == Byte.MAX_VALUE) + { + writeBIPush_SIPush_IConst( + lineNumber, "java/lang/Byte", "MAX_VALUE", "B"); + } + else + { + this.printer.printNumeric(lineNumber, String.valueOf(value)); + } + } + else if ("C".equals(signature)) + { + String escapedString = + StringUtil.EscapeCharAndAppendApostrophe((char)value); + String scopeInternalName = this.classFile.getThisClassName(); + this.printer.printString( + lineNumber, escapedString, scopeInternalName); + } + else if ("Z".equals(signature)) + { + this.printer.printKeyword( + lineNumber, (value == 0) ? "false" : "true"); + } + else + { + this.printer.printNumeric(lineNumber, String.valueOf(value)); + } + } + + return lineNumber; + } + + private void writeBIPush_SIPush_IConst( + int lineNumber, String internalTypeName, String name, String descriptor) + { + String className = SignatureWriter.InternalClassNameToClassName( + this.loader, this.referenceMap, this.classFile, internalTypeName); + String scopeInternalName = this.classFile.getThisClassName(); + this.printer.printType( + lineNumber, internalTypeName, className, scopeInternalName); + this.printer.print(lineNumber, '.'); + this.printer.printStaticField( + lineNumber, internalTypeName, name, descriptor, scopeInternalName); + } + + private int writeArray( + Instruction parent, Instruction arrayref, Instruction indexref) + { + int lineNumber = visit(parent, arrayref); + + int nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + this.printer.print(lineNumber, '['); + + lineNumber = visit(parent, indexref); + + if ((this.firstOffset <= this.previousOffset) && + (parent.offset <= this.lastOffset)) + this.printer.print(lineNumber, ']'); + + return lineNumber; + } + + /* +, -, *, /, %, <<, >>, >>>, &, |, ^ */ + private int writeBinaryOperatorInstruction(BinaryOperatorInstruction boi) + { + int lineNumber = boi.value1.lineNumber; + + if (boi.operator.length() == 1) + { + switch (boi.operator.charAt(0)) + { + case '&': case '|': case '^': + { + // Binary operators + lineNumber = + writeBinaryOperatorParameterInHexaOrBoolean(boi, boi.value1); + + int nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + { + this.printer.print(lineNumber, ' '); + this.printer.print(lineNumber, boi.operator); + this.printer.print(lineNumber, ' '); + } + + return + writeBinaryOperatorParameterInHexaOrBoolean(boi, boi.value2); + } + } + } + + // Other operators + lineNumber = visit(boi, boi.value1); + + int nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + { + this.printer.print(lineNumber, ' '); + this.printer.print(lineNumber, boi.operator); + this.printer.print(lineNumber, ' '); + } + + if (boi.getPriority() <= boi.value2.getPriority()) + { + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + this.printer.print(lineNumber, '('); + + lineNumber = visit(boi.value2); + + if ((this.firstOffset <= this.previousOffset) && + (boi.offset <= this.lastOffset)) + this.printer.print(lineNumber, ')'); + + return lineNumber; + } + else + { + return visit(boi.value2); + } + } + + protected int writeBinaryOperatorParameterInHexaOrBoolean( + Instruction parent, Instruction child) + { + if (parent.getPriority() < child.getPriority()) + { + int nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + this.printer.print(child.lineNumber, '('); + + int lineNumber = writeBinaryOperatorParameterInHexaOrBoolean(child); + + nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + this.printer.print(lineNumber, ')'); + + return lineNumber; + } + else + { + return writeBinaryOperatorParameterInHexaOrBoolean(child); + } + } + + private int writeBinaryOperatorParameterInHexaOrBoolean(Instruction value) + { + int lineNumber = value.lineNumber; + + if ((this.firstOffset <= this.previousOffset) && + (value.offset <= this.lastOffset)) + { + switch (value.opcode) + { + case ByteCodeConstants.BIPUSH: + case ByteCodeConstants.ICONST: + case ByteCodeConstants.SIPUSH: + { + IConst iconst = (IConst)value; + if (iconst.signature.equals("Z")) + { + if (iconst.value == 0) + this.printer.printKeyword(lineNumber, "false"); + else + this.printer.printKeyword(lineNumber, "true"); + } + else + { + this.printer.printNumeric( + lineNumber, + "0x" + Integer.toHexString(iconst.value).toUpperCase()); + } + } + break; + case ByteCodeConstants.LDC: + case ByteCodeConstants.LDC2_W: + this.printer.addNewLinesAndPrefix(lineNumber); + Constant cst = constants.get( ((IndexInstruction)value).index ); + ConstantValueWriter.WriteHexa( + this.loader, this.printer, this.referenceMap, + this.classFile, (ConstantValue)cst); + break; + default: + lineNumber = visit(value); + break; + } + } + + return lineNumber; + } + + protected int writeIfTest(IfInstruction ifInstruction) + { + String signature = + ifInstruction.value.getReturnedSignature(constants, localVariables); + + if ((signature != null) && (signature.charAt(0) == 'Z')) + { + switch (ifInstruction.cmp) + { + case ByteCodeConstants.CMP_EQ: + case ByteCodeConstants.CMP_LE: + case ByteCodeConstants.CMP_GE: + int nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + this.printer.print(ifInstruction.lineNumber, "!"); + } + + return visit(2, ifInstruction.value); + +// visit(ifInstruction, ifInstruction.value); +// switch (ifInstruction.cmp) +// { +// case ByteCodeConstants.CMP_EQ: +// case ByteCodeConstants.CMP_LE: +// case ByteCodeConstants.CMP_GE: +// spw.print(" == false"); +// break; +// default: +// spw.print(" == true"); +// } + } + else + { + int lineNumber = visit(6, ifInstruction.value); + + if ((this.firstOffset <= this.previousOffset) && + (ifInstruction.offset <= this.lastOffset)) + { + this.printer.print(' '); + this.printer.print(ByteCodeConstants.CMP_NAMES[ifInstruction.cmp]); + this.printer.print(' '); + this.printer.printNumeric("0"); + } + + return lineNumber; + } + } + + protected int writeIfCmpTest(IfCmp ifCmpInstruction) + { + int lineNumber = visit(6, ifCmpInstruction.value1); + + int nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + { + this.printer.print(lineNumber, ' '); + this.printer.print(ByteCodeConstants.CMP_NAMES[ifCmpInstruction.cmp]); + this.printer.print(' '); + } + + return visit(6, ifCmpInstruction.value2); + } + + protected int writeIfXNullTest(IfInstruction ifXNull) + { + int lineNumber = visit(6, ifXNull.value); + + if ((this.firstOffset <= this.previousOffset) && + (ifXNull.offset <= this.lastOffset)) + { + this.printer.print(lineNumber, ' '); + this.printer.print(ByteCodeConstants.CMP_NAMES[ifXNull.cmp]); + this.printer.print(' '); + this.printer.printKeyword("null"); + } + + return lineNumber; + } + + protected int writeComplexConditionalBranchInstructionTest( + ComplexConditionalBranchInstruction ccbi) + { + List branchList = ccbi.instructions; + int lenght = branchList.size(); + + if (lenght > 1) + { + String operator = + (ccbi.cmp==FastConstants.CMP_AND) ? " && " : " || "; + Instruction instruction = branchList.get(0); + int lineNumber = instruction.lineNumber; + + int nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + this.printer.print(lineNumber, '('); + + lineNumber = visit(instruction); + + nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + this.printer.print(lineNumber, ')'); + + for (int i=1; i 0) + { + return visit(branchList.get(0)); + } + else + { + return Instruction.UNKNOWN_LINE_NUMBER; + } + } + + private int writeIInc(IInc iinc) + { + int lineNumber = iinc.lineNumber; + + if ((this.firstOffset <= this.previousOffset) && + (iinc.offset <= this.lastOffset)) + { + String lvName = null; + + LocalVariable lv = + this.localVariables.getLocalVariableWithIndexAndOffset( + iinc.index, iinc.offset); + + if (lv != null) + { + int lvNameIndex = lv.name_index; + if (lvNameIndex > 0) + lvName = constants.getConstantUtf8(lvNameIndex); + } + + if (lvName == null) + { + //new RuntimeException("local variable not found") + // .printStackTrace(); + this.printer.startOfError(); + this.printer.print(lineNumber, "???"); + this.printer.endOfError(); + } + else + { + this.printer.print(lineNumber, lvName); + } + + switch (iinc.count) + { + case -1: + this.printer.print(lineNumber, "--"); + break; + case 1: + this.printer.print(lineNumber, "++"); + break; + default: + if (iinc.count >= 0) + { + this.printer.print(lineNumber, " += "); + this.printer.printNumeric(lineNumber, String.valueOf(iinc.count)); + } + else + { + this.printer.print(lineNumber, " -= "); + this.printer.printNumeric(lineNumber, String.valueOf(-iinc.count)); + } + } + } + + return lineNumber; + } + + private int writePreInc(IncInstruction ii) + { + int lineNumber = ii.lineNumber; + + if ((this.firstOffset <= this.previousOffset) && + (ii.offset <= this.lastOffset)) + { + switch (ii.count) + { + case -1: + this.printer.print(lineNumber, "--"); + lineNumber = visit(ii.value); + break; + case 1: + this.printer.print(lineNumber, "++"); + lineNumber = visit(ii.value); + break; + default: + lineNumber = visit(ii.value); + + if (ii.count >= 0) + { + this.printer.print(lineNumber, " += "); + this.printer.printNumeric(lineNumber, String.valueOf(ii.count)); + } + else + { + this.printer.print(lineNumber, " -= "); + this.printer.printNumeric(lineNumber, String.valueOf(-ii.count)); + } + break; + } + } + + return lineNumber; + } + + private int writePostInc(IncInstruction ii) + { + int lineNumber = ii.lineNumber; + + if ((this.firstOffset <= this.previousOffset) && + (ii.offset <= this.lastOffset)) + { + switch (ii.count) + { + case -1: + lineNumber = visit(ii.value); + this.printer.print(lineNumber, "--"); + break; + case 1: + lineNumber = visit(ii.value); + this.printer.print(lineNumber, "++"); + break; + default: + new RuntimeException("PostInc with value=" + ii.count) + .printStackTrace(); + } + } + + return lineNumber; + } + + private int writeInvokeNewInstruction(InvokeNew in) + { + ConstantMethodref cmr = this.constants.getConstantMethodref(in.index); + String internalClassName = + this.constants.getConstantClassName(cmr.class_index); + String prefix = + this.classFile.getThisClassName() + + StringConstants.INTERNAL_INNER_SEPARATOR; + ClassFile innerClassFile; + + if (internalClassName.startsWith(prefix)) + innerClassFile = this.classFile.getInnerClassFile(internalClassName); + else + innerClassFile = null; + + int lineNumber = in.lineNumber; + int firstIndex; + int length = in.args.size(); + + ConstantNameAndType cnat = + this.constants.getConstantNameAndType(cmr.name_and_type_index); + String constructorDescriptor = + this.constants.getConstantUtf8(cnat.descriptor_index); + + if (innerClassFile == null) + { + // Normal new invoke + firstIndex = 0; + } + else if (innerClassFile.getInternalAnonymousClassName() == null) + { + // Inner class new invoke + firstIndex = computeFirstIndex(innerClassFile.access_flags, in); + } + else + { + // Anonymous new invoke + firstIndex = computeFirstIndex(this.methodAccessFlags, in); + // Search parameter count of super constructor + String constructorName = + this.constants.getConstantUtf8(cnat.name_index); + Method constructor = + innerClassFile.getMethod(constructorName, constructorDescriptor); + if (constructor != null) + { + length = + firstIndex + constructor.getSuperConstructorParameterCount(); + assert length <= in.args.size(); + } + } + + if (this.firstOffset <= this.previousOffset) + { + this.printer.printKeyword(lineNumber, "new"); + this.printer.print(' '); + + if (innerClassFile == null) + { + // Normal new invoke + SignatureWriter.WriteConstructor( + this.loader, this.printer, this.referenceMap, + this.classFile, + SignatureUtil.CreateTypeName(internalClassName), + constructorDescriptor); + //writeArgs(in.lineNumber, 0, in.args); + } + else if (innerClassFile.getInternalAnonymousClassName() == null) + { + // Inner class new invoke + SignatureWriter.WriteConstructor( + this.loader, this.printer, this.referenceMap, + this.classFile, + SignatureUtil.CreateTypeName(internalClassName), + constructorDescriptor); + } + else + { + // Anonymous new invoke + SignatureWriter.WriteConstructor( + this.loader, this.printer, this.referenceMap, this.classFile, + SignatureUtil.CreateTypeName(innerClassFile.getInternalAnonymousClassName()), + constructorDescriptor); + } + } + + return writeArgs(in.lineNumber, firstIndex, length, in.args); + } + + private int computeFirstIndex(int accessFlags, InvokeNew in) + { + if (((accessFlags & ClassFileConstants.ACC_STATIC) == 0) && + (in.args.size() > 0)) + { + Instruction arg0 = in.args.get(0); + if ((arg0.opcode == ByteCodeConstants.ALOAD) && + (((ALoad)arg0).index == 0)) + { + return 1; + } + else + { + return 0; + } + } + else + { + return 0; + } + } + + private int writeEnumValueInstruction(InvokeNew in) + { + int lineNumber = in.lineNumber; + + ConstantFieldref cfr = + constants.getConstantFieldref(in.enumValueFieldRefIndex); + ConstantNameAndType cnat = constants.getConstantNameAndType( + cfr.name_and_type_index); + + String internalClassName = classFile.getThisClassName(); + String name = constants.getConstantUtf8(cnat.name_index); + String descriptor = constants.getConstantUtf8(cnat.descriptor_index); + + this.printer.addNewLinesAndPrefix(lineNumber); + this.printer.printStaticFieldDeclaration( + internalClassName, name, descriptor); + + if (in.args.size() > 2) + lineNumber = writeArgs(lineNumber, 2, in.args.size(), in.args); + + return lineNumber; + } + + private int writeGetField(GetField getField) + { + int lineNumber = getField.lineNumber; + ConstantFieldref cfr = + constants.getConstantFieldref(getField.index); + ConstantNameAndType cnat = + constants.getConstantNameAndType(cfr.name_and_type_index); + Field field = + this.classFile.getField(cnat.name_index, cnat.descriptor_index); + + if ((field != null) && + (field.outerMethodLocalVariableNameIndex != UtilConstants.INVALID_INDEX)) + { + // Specificite des classes anonymes : affichage du nom du champs de + // la methode englobante plutot que le nom du champs + if ((this.firstOffset <= this.previousOffset) && + (getField.offset <= this.lastOffset)) + { + String internalClassName = + this.constants.getConstantClassName(cfr.class_index); + String fieldName = this.constants.getConstantUtf8( + field.outerMethodLocalVariableNameIndex); + if (this.keywordSet.contains(fieldName)) + fieldName = StringConstants.JD_FIELD_PREFIX + fieldName; + String descriptor = + this.constants.getConstantUtf8(cnat.descriptor_index); + this.printer.printField( + lineNumber, internalClassName, fieldName, + descriptor, this.classFile.getThisClassName()); + } + } + else + { + // Cas normal + boolean displayPrefix = false; + + if (this.localVariables.containsLocalVariableWithNameIndex(cnat.name_index)) + { + switch (getField.objectref.opcode) + { + case ByteCodeConstants.ALOAD: + if (((ALoad)getField.objectref).index == 0) + displayPrefix = true; + break; + case ByteCodeConstants.OUTERTHIS: + if (!needAPrefixForThisField( + cnat.name_index, cnat.descriptor_index, + (GetStatic)getField.objectref)) + displayPrefix = true; + break; + } + } + + if ((this.firstOffset <= this.previousOffset) && + (getField.objectref.offset <= this.lastOffset)) + { + if (displayPrefix == false) + { + this.printer.addNewLinesAndPrefix(lineNumber); + this.printer.startOfOptionalPrefix(); + } + + lineNumber = visit(getField, getField.objectref); + this.printer.print(lineNumber, '.'); + + if (displayPrefix == false) + { + this.printer.endOfOptionalPrefix(); + } + } + + if ((this.firstOffset <= this.previousOffset) && + (getField.offset <= this.lastOffset)) + { + String internalClassName = + this.constants.getConstantClassName(cfr.class_index); + String fieldName = + this.constants.getConstantUtf8(cnat.name_index); + if (this.keywordSet.contains(fieldName)) + fieldName = StringConstants.JD_FIELD_PREFIX + fieldName; + String descriptor = + this.constants.getConstantUtf8(cnat.descriptor_index); + this.printer.printField( + lineNumber, internalClassName, fieldName, + descriptor, this.classFile.getThisClassName()); + } + } + + return lineNumber; + } + + private int writeInvokeNoStaticInstruction(InvokeNoStaticInstruction insi) + { + ConstantMethodref cmr = constants.getConstantMethodref(insi.index); + ConstantNameAndType cnat = + constants.getConstantNameAndType(cmr.name_and_type_index); + boolean thisInvoke = false; + + if ((insi.objectref.opcode == ByteCodeConstants.ALOAD) && + (((ALoad)insi.objectref).index == 0)) + { + ALoad aload = (ALoad)insi.objectref; + LocalVariable lv = + this.localVariables.getLocalVariableWithIndexAndOffset( + aload.index, aload.offset); + + if (lv != null) + { + String name = this.constants.getConstantUtf8(lv.name_index); + if (StringConstants.THIS_LOCAL_VARIABLE_NAME.equals(name)) + thisInvoke = true; + } + } + + if (thisInvoke) + { + int nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + { + String internalClassName = + this.constants.getConstantClassName(cmr.class_index); + String methodName = constants.getConstantUtf8(cnat.name_index); + if (this.keywordSet.contains(methodName)) + methodName = StringConstants.JD_METHOD_PREFIX + methodName; + String descriptor = + this.constants.getConstantUtf8(cnat.descriptor_index); + // Methode de la classe courante : elimination du prefix 'this.' + this.printer.printMethod( + insi.lineNumber, internalClassName, methodName, + descriptor, this.classFile.getThisClassName()); + } + } + else + { + boolean displayPrefix = + ((insi.objectref.opcode != ByteCodeConstants.OUTERTHIS) || + needAPrefixForThisMethod( + cnat.name_index, cnat.descriptor_index, + (GetStatic)insi.objectref)); + + int lineNumber = insi.objectref.lineNumber; + + if (displayPrefix == false) + { + this.printer.addNewLinesAndPrefix(lineNumber); + this.printer.startOfOptionalPrefix(); + } + + visit(insi, insi.objectref); + + int nextOffset = this.previousOffset + 1; + lineNumber = insi.lineNumber; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + { + this.printer.print(lineNumber, '.'); + } + + if (displayPrefix == false) + { + this.printer.endOfOptionalPrefix(); + } + + nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + { + String internalClassName = + this.constants.getConstantClassName(cmr.class_index); + String methodName = constants.getConstantUtf8(cnat.name_index); + if (this.keywordSet.contains(methodName)) + methodName = StringConstants.JD_METHOD_PREFIX + methodName; + String descriptor = + this.constants.getConstantUtf8(cnat.descriptor_index); + this.printer.printMethod( + lineNumber, internalClassName, methodName, + descriptor, this.classFile.getThisClassName()); + } + } + + return writeArgs(insi.lineNumber, 0, insi.args.size(), insi.args); + } + + private boolean needAPrefixForThisMethod( + int methodNameIndex, int methodDescriptorIndex, GetStatic getStatic) + { + if (this.classFile.getMethod(methodNameIndex, methodDescriptorIndex) != null) + { + // La classe courante contient une method ayant le meme nom et la + // meme signature + return true; + } + + ConstantFieldref cfr = + this.constants.getConstantFieldref(getStatic.index); + String getStaticOuterClassName = + this.constants.getConstantClassName(cfr.class_index); + String methodName = this.constants.getConstantUtf8(methodNameIndex); + String methodDescriptor = + this.constants.getConstantUtf8(methodDescriptorIndex); + + ClassFile outerClassFile = this.classFile.getOuterClass(); + + while (outerClassFile != null) + { + String outerClassName = outerClassFile.getThisClassName(); + if (outerClassName.equals(getStaticOuterClassName)) + break; + + if (outerClassFile.getMethod(methodName, methodDescriptor) != null) + { + // La classe englobante courante contient une method ayant le + // meme nom et la meme signature + return true; + } + + outerClassFile = outerClassFile.getOuterClass(); + } + + return false; + } + + private int writeInvokespecial(InvokeNoStaticInstruction insi) + { + ConstantMethodref cmr = constants.getConstantMethodref(insi.index); + ConstantNameAndType cnat = + constants.getConstantNameAndType(cmr.name_and_type_index); + boolean thisInvoke = false; + int firstIndex; + + if ((insi.objectref.opcode == ByteCodeConstants.ALOAD) && + (((ALoad)insi.objectref).index == 0)) + { + ALoad aload = (ALoad)insi.objectref; + LocalVariable lv = + this.localVariables.getLocalVariableWithIndexAndOffset( + aload.index, aload.offset); + + if ((lv != null) && + (lv.name_index == this.constants.thisLocalVariableNameIndex)) + { + thisInvoke = true; + } + } + + if (thisInvoke) + { + // Appel d'un constructeur? + if (cnat.name_index == constants.instanceConstructorIndex) + { + if (cmr.class_index == classFile.getThisClassIndex()) + { + // Appel d'un constructeur de la classe courante + if ((this.classFile.access_flags & ClassFileConstants.ACC_ENUM) == 0) + { + if (this.classFile.isAInnerClass() && + ((this.classFile.access_flags & ClassFileConstants.ACC_STATIC) == 0)) + { + // inner class: firstIndex=1 + firstIndex = 1; + } + else + { + // class: firstIndex=0 + // static inner class: firstIndex=0 + firstIndex = 0; + } + } + else + { + // enum: firstIndex=2 + // static inner enum: firstIndex=2 + firstIndex = 2; + } + } + else + { + // Appel d'un constructeur de la classe mere + if (this.classFile.isAInnerClass()) + { + // inner class: firstIndex=1 + firstIndex = 1; + } + else + { + // class: firstIndex=0 + firstIndex = 0; + } + } + } + else + { + // Appel a une methode privee? + firstIndex = 0; + } + } + else + { + firstIndex = 0; + } + + if (thisInvoke) + { + int nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + { + int lineNumber = insi.lineNumber; + + // Appel d'un constructeur? + if (cnat.name_index == constants.instanceConstructorIndex) + { + if (cmr.class_index == classFile.getThisClassIndex()) + { + // Appel d'un constructeur de la classe courante + this.printer.printKeyword(lineNumber, "this"); + } + else + { + // Appel d'un constructeur de la classe mere + this.printer.printKeyword(lineNumber, "super"); + } + } + else + { + // Appel a une methode privee? + Method method = this.classFile.getMethod( + cnat.name_index, cnat.descriptor_index); + + if ((method == null) || + ((method.access_flags & ClassFileConstants.ACC_PRIVATE) == 0)) + { + // Methode de la classe mere + this.printer.printKeyword(lineNumber, "super"); + this.printer.print(lineNumber, '.'); + } + //else + //{ + // // Methode de la classe courante : elimination du prefix 'this.' + //} + + String internalClassName = + this.constants.getConstantClassName(cmr.class_index); + String methodName = constants.getConstantUtf8(cnat.name_index); + if (this.keywordSet.contains(methodName)) + methodName = StringConstants.JD_METHOD_PREFIX + methodName; + String descriptor = + this.constants.getConstantUtf8(cnat.descriptor_index); + this.printer.printMethod( + lineNumber, internalClassName, methodName, + descriptor, this.classFile.getThisClassName()); + } + } + } + else + { + int lineNumber = insi.lineNumber; + + visit(insi, insi.objectref); + + int nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + { + this.printer.print(lineNumber, '.'); + + String internalClassName = + this.constants.getConstantClassName(cmr.class_index); + String methodName = constants.getConstantUtf8(cnat.name_index); + if (this.keywordSet.contains(methodName)) + methodName = StringConstants.JD_METHOD_PREFIX + methodName; + String descriptor = + this.constants.getConstantUtf8(cnat.descriptor_index); + + this.printer.printMethod( + internalClassName, methodName, + descriptor, this.classFile.getThisClassName()); + } + } + + return writeArgs( + insi.lineNumber, firstIndex, insi.args.size(), insi.args); + } + + private int writeInvokestatic(Invokestatic invokestatic) + { + int nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + { + int lineNumber = invokestatic.lineNumber; + + ConstantMethodref cmr = + constants.getConstantMethodref(invokestatic.index); + + String internalClassName = + this.constants.getConstantClassName(cmr.class_index); + + if (classFile.getThisClassIndex() != cmr.class_index) + { + this.printer.addNewLinesAndPrefix(lineNumber); + int length = SignatureWriter.WriteSignature( + this.loader, this.printer, + this.referenceMap, this.classFile, + SignatureUtil.CreateTypeName(constants.getConstantClassName(cmr.class_index))); + + if (length > 0) + { + this.printer.print('.'); + } + } + + ConstantNameAndType cnat = + constants.getConstantNameAndType(cmr.name_and_type_index); + + String methodName = constants.getConstantUtf8(cnat.name_index); + if (this.keywordSet.contains(methodName)) + methodName = StringConstants.JD_METHOD_PREFIX + methodName; + String descriptor = + this.constants.getConstantUtf8(cnat.descriptor_index); + + this.printer.printStaticMethod( + lineNumber, internalClassName, methodName, descriptor, + this.classFile.getThisClassName()); + } + + return writeArgs( + invokestatic.lineNumber, 0, + invokestatic.args.size(), invokestatic.args); + } + + private int writeArgs( + int lineNumber, int firstIndex, int length, List args) + { + if (length > firstIndex) + { + int nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + this.printer.print(lineNumber, '('); + + lineNumber = visit(args.get(firstIndex)); + + for (int i=firstIndex+1; i 0) + { + this.printer.print(lineNumber, '.'); + } + } + + ConstantNameAndType cnat = constants.getConstantNameAndType( + cfr.name_and_type_index); + String descriptor = constants.getConstantUtf8(cnat.descriptor_index); + String constName = constants.getConstantUtf8(cnat.name_index); + + this.printer.printStaticField( + lineNumber, internalClassName, constName, + descriptor, this.classFile.getThisClassName()); + } + + return lineNumber; + } + + private int writeOuterThis(GetStatic getStatic) + { + int lineNumber = getStatic.lineNumber; + + if ((this.firstOffset <= this.previousOffset) && + (getStatic.offset <= this.lastOffset)) + { + ConstantFieldref cfr = + constants.getConstantFieldref(getStatic.index); + + if (cfr.class_index != classFile.getThisClassIndex()) + { + this.printer.addNewLinesAndPrefix(lineNumber); + int length = SignatureWriter.WriteSignature( + this.loader, this.printer, + this.referenceMap, this.classFile, + SignatureUtil.CreateTypeName(constants.getConstantClassName(cfr.class_index))); + + if (length > 0) + { + this.printer.print(lineNumber, '.'); + } + } + + ConstantNameAndType cnat = constants.getConstantNameAndType( + cfr.name_and_type_index); + this.printer.printKeyword( + lineNumber, constants.getConstantUtf8(cnat.name_index)); + } + + return lineNumber; + } + + private int writeLcdInstruction(IndexInstruction ii) + { + int lineNumber = ii.lineNumber; + + if ((this.firstOffset <= this.previousOffset) && + (ii.offset <= this.lastOffset)) + { + // Dans les specs, LDC pointe vers une constante du pool. Lors de la + // declaration d'enumeration, le byte code de la methode + // 'Enum.valueOf(Class enumType, String name)' contient une + // instruction LDC pointant un objet de type 'ConstantClass'. + Constant cst = constants.get(ii.index); + + if (cst.tag == ConstantConstant.CONSTANT_Class) + { + // Exception a la regle + ConstantClass cc = (ConstantClass)cst; + String signature = SignatureUtil.CreateTypeName( + constants.getConstantUtf8(cc.name_index)); + + this.printer.addNewLinesAndPrefix(lineNumber); + SignatureWriter.WriteSignature( + this.loader, this.printer, this.referenceMap, + this.classFile, signature); + this.printer.print('.'); + this.printer.printKeyword("class"); + } + else + { + // Cas g�n�ral + this.printer.addNewLinesAndPrefix(lineNumber); + ConstantValueWriter.Write( + this.loader, this.printer, this.referenceMap, + this.classFile, (ConstantValue)cst); + } + } + + return lineNumber; + } + + private int writeLoadInstruction(LoadInstruction loadInstruction) + { + int lineNumber = loadInstruction.lineNumber; + + if ((this.firstOffset <= this.previousOffset) && + (loadInstruction.offset <= this.lastOffset)) + { + LocalVariable lv = + this.localVariables.getLocalVariableWithIndexAndOffset( + loadInstruction.index, loadInstruction.offset); + + if ((lv == null) || (lv.name_index <= 0)) + { + // Error + this.printer.startOfError(); + this.printer.print(lineNumber, "???"); + this.printer.endOfError(); + } + else + { + int nameIndex = lv.name_index; + + if (nameIndex == -1) + { + // Error + this.printer.startOfError(); + this.printer.print(lineNumber, "???"); + this.printer.endOfError(); + } + else if (nameIndex == this.constants.thisLocalVariableNameIndex) + { + this.printer.printKeyword( + lineNumber, constants.getConstantUtf8(lv.name_index)); + } + else + { + this.printer.print( + lineNumber, constants.getConstantUtf8(lv.name_index)); + } + } + } + + return lineNumber; + } + + private int writeMultiANewArray(MultiANewArray multiANewArray) + { + int lineNumber = multiANewArray.lineNumber; + + String signature = constants.getConstantClassName(multiANewArray.index); + + int nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + { + this.printer.printKeyword(lineNumber, "new"); + this.printer.print(' '); + + SignatureWriter.WriteSignature( + this.loader, this.printer, this.referenceMap, this.classFile, + SignatureUtil.CutArrayDimensionPrefix(signature)); + } + + Instruction[] dimensions = multiANewArray.dimensions; + + for (int i=dimensions.length-1; i>=0; i--) + { + nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + this.printer.print(lineNumber, '['); + + lineNumber = visit(dimensions[i]); + + nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + this.printer.print(lineNumber, ']'); + } + + // Affichage des dimensions sans taille + nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + { + int dimensionCount = SignatureUtil.GetArrayDimensionCount(signature); + for (int i=dimensions.length; i 0) + { + this.printer.print(lineNumber, '.'); + } + } + + ConstantNameAndType cnat = + constants.getConstantNameAndType(cfr.name_and_type_index); + String descriptor = constants.getConstantUtf8(cnat.descriptor_index); + String internalClassName = SignatureUtil.GetInternalName(descriptor); + String constName = constants.getConstantUtf8(cnat.name_index); + + this.printer.printStaticField( + lineNumber, internalClassName, constName, + descriptor, this.classFile.getThisClassName()); + + this.printer.print(lineNumber, " = "); + } + + // Est-il necessaire de parenth�ser l'expression ? + // visit(putStatic, putStatic.valueref); + return visit(putStatic.valueref); + } + + private int writeStoreInstruction(StoreInstruction storeInstruction) + { + int nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + { + int lineNumber = storeInstruction.lineNumber; + + LocalVariable lv = + this.localVariables.getLocalVariableWithIndexAndOffset( + storeInstruction.index, storeInstruction.offset); + + if ((lv == null) || (lv.name_index <= 0)) + { + this.printer.startOfError(); + this.printer.print(lineNumber, "???"); + this.printer.endOfError(); + } + else + { + this.printer.print( + lineNumber, constants.getConstantUtf8(lv.name_index)); + } + + this.printer.print(lineNumber, " = "); + } + + // Est-il necessaire de parenth�ser l'expression ? + // visit(storeInstruction, storeInstruction.valueref); + return visit(storeInstruction.valueref); + } + + private int writeExceptionLoad(ExceptionLoad exceptionLoad) + { + int lineNumber = exceptionLoad.lineNumber; + int nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + { + if (exceptionLoad.exceptionNameIndex == 0) + { + this.printer.printKeyword(lineNumber, "finally"); + } + else + { + LocalVariable lv = + this.localVariables.getLocalVariableWithIndexAndOffset( + exceptionLoad.index, exceptionLoad.offset); + + if ((lv == null) || (lv.name_index == 0)) + { + this.printer.startOfError(); + this.printer.print(lineNumber, "???"); + this.printer.endOfError(); + } + else + { + this.printer.print( + lineNumber, constants.getConstantUtf8(lv.name_index)); + } + } + } + + return lineNumber; + } + + private int writeAssignmentInstruction(AssignmentInstruction ai) + { + int lineNumber = ai.lineNumber; + int previousOffsetBackup = this.previousOffset; + + visit(ai.value1); + + this.previousOffset = previousOffsetBackup; + int nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + { + this.printer.print(lineNumber, ' '); + this.printer.print(lineNumber, ai.operator); + this.printer.print(lineNumber, ' '); + } + + /* +=, -=, *=, /=, %=, <<=, >>=, >>>=, &=, |=, ^= */ + if (ai.operator.length() > 0) + { + switch (ai.operator.charAt(0)) + { + case '&': case '|': case '^': + // Binary operators + return writeBinaryOperatorParameterInHexaOrBoolean(ai, ai.value2); + } + } + + return visit(ai, ai.value2); + } + + private int writeConvertInstruction(ConvertInstruction instruction) + { + int nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + { + int lineNumber = instruction.lineNumber; + + switch (instruction.signature.charAt(0)) + { + case 'C': + this.printer.print(lineNumber, '('); + this.printer.printKeyword("char"); + this.printer.print(')'); + break; + case 'B': + this.printer.print(lineNumber, '('); + this.printer.printKeyword("byte"); + this.printer.print(')'); + break; + case 'S': + this.printer.print(lineNumber, '('); + this.printer.printKeyword("short"); + this.printer.print(')'); + break; + case 'I': + this.printer.print(lineNumber, '('); + this.printer.printKeyword("int"); + this.printer.print(')'); + break; + case 'L': + this.printer.print(lineNumber, '('); + this.printer.printKeyword("long"); + this.printer.print(')'); + break; + case 'F': + this.printer.print(lineNumber, '('); + this.printer.printKeyword("float"); + this.printer.print(')'); + break; + case 'D': + this.printer.print(lineNumber, '('); + this.printer.printKeyword("double"); + this.printer.print(')'); + break; + } + } + + return visit(instruction, instruction.value); + } + + private int writeDeclaration(FastDeclaration fd) + { + int lineNumber = fd.lineNumber; + + LocalVariable lv = + localVariables.getLocalVariableWithIndexAndOffset( + fd.index, fd.offset); + + if (lv == null) + { + if (fd.instruction == null) + { + int nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + { + this.printer.startOfError(); + this.printer.print(lineNumber, "???"); + this.printer.endOfError(); + } + } + else + { + lineNumber = visit(fd.instruction); + } + } + else + { + int nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + { + this.printer.addNewLinesAndPrefix(lineNumber); + String signature = + this.constants.getConstantUtf8(lv.signature_index); + String internalName = + SignatureUtil.GetInternalName(signature); + ClassFile innerClassFile = + this.classFile.getInnerClassFile(internalName); + + if (lv.finalFlag) + { + this.printer.printKeyword("final"); + this.printer.print(' '); + } + + if ((innerClassFile != null) && + (innerClassFile.getInternalAnonymousClassName() != null)) + { + String internalAnonymousClassSignature = + SignatureUtil.CreateTypeName(innerClassFile.getInternalAnonymousClassName()); + SignatureWriter.WriteSignature( + this.loader, this.printer, this.referenceMap, + this.classFile, internalAnonymousClassSignature); + } + else + { + SignatureWriter.WriteSignature( + this.loader, this.printer, this.referenceMap, + this.classFile, signature); + } + + this.printer.print(' '); + } + + if (fd.instruction == null) + { + nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + this.printer.print( + lineNumber, constants.getConstantUtf8(lv.name_index)); + } + else + { + lineNumber = visit(fd.instruction); + } + } + + return lineNumber; + } + + /* + * Affichage des initialisations de tableaux associees aux instructions + * 'NEWARRAY' et 'ANEWARRAY' dans les affectations '?Store' et passees + * en parametres. + */ + private int WriteInitArrayInstruction(InitArrayInstruction iai) + { + int lineNumber = iai.lineNumber; + + // Affichage des valeurs + int nextOffset = this.previousOffset + 1; + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + this.printer.print(lineNumber, "{"); + + List values = iai.values; + final int length = values.size(); + + if (length > 0) + { + Instruction instruction = values.get(0); + + if ((this.firstOffset <= this.previousOffset) && + (nextOffset <= this.lastOffset)) + { + if (lineNumber == instruction.lineNumber) + this.printer.print(" "); + } + + lineNumber = visit(instruction); + + for (int i=1; i newValue) + lastIndex = medIndex-1; + else + break; + } + + medIndex = (lastIndex + firstIndex) / 2; + value = this.values[medIndex]; + + if (value < newValue) + { + medIndex++; + System.arraycopy(this.values, medIndex, + this.values, medIndex+1, this.size-medIndex); + this.values[medIndex] = newValue; + this.size++; + } + else if (value > newValue) + { + System.arraycopy(this.values, medIndex, + this.values, medIndex+1, this.size-medIndex); + this.values[medIndex] = newValue; + this.size++; + } + } + } + } + + public int[] toArray() + { + if (this.values == null) + return null; + + int[] tmp = new int[this.size]; + System.arraycopy(this.values, 0, tmp, 0, this.size); + return tmp; + } + + public int get(int index) + { + if ((this.values == null) || (index >= this.size)) + throw new IndexOutOfBoundsException( + "Index: "+index+", Size: "+size); + + return this.values[index]; + } +} diff --git a/src/jd/core/util/InvalidParameterException.java b/src/jd/core/util/InvalidParameterException.java new file mode 100644 index 00000000..84749f7b --- /dev/null +++ b/src/jd/core/util/InvalidParameterException.java @@ -0,0 +1,17 @@ +package jd.core.util; + + +public class InvalidParameterException extends RuntimeException +{ + private static final long serialVersionUID = -3407799517256621265L; + + public InvalidParameterException() + { + super(); + } + + public InvalidParameterException(String s) + { + super(s); + } +} diff --git a/src/jd/core/util/SignatureFormatException.java b/src/jd/core/util/SignatureFormatException.java new file mode 100644 index 00000000..b47bad12 --- /dev/null +++ b/src/jd/core/util/SignatureFormatException.java @@ -0,0 +1,17 @@ +package jd.core.util; + + +public class SignatureFormatException extends RuntimeException +{ + private static final long serialVersionUID = -3407799517256621265L; + + public SignatureFormatException() + { + super(); + } + + public SignatureFormatException(String s) + { + super(s); + } +} diff --git a/src/jd/core/util/SignatureUtil.java b/src/jd/core/util/SignatureUtil.java new file mode 100644 index 00000000..569c0eec --- /dev/null +++ b/src/jd/core/util/SignatureUtil.java @@ -0,0 +1,355 @@ +package jd.core.util; + +import java.util.ArrayList; + +import jd.core.model.instruction.bytecode.ByteCodeConstants; + + +public class SignatureUtil +{ + /** + * @see SignatureAnalyzer.SignatureAnalyzer(...) + */ + public static int SkipSignature(char[] caSignature, int length, int index) + { + char c; + + while (true) + { + // Affichage des dimensions du tableau : '[[?' ou '[L[?;' + if (caSignature[index] == '[') + { + while (++index < length) + { + if ((caSignature[index] == 'L') && + (index+1 < length) && + (caSignature[index+1] == '[')) + { + index++; + length--; + } + else if (caSignature[index] != '[') + { + break; + } + } + } + + switch(caSignature[index]) + { + case 'B' : case 'C' : case 'D' : case 'F' : + case 'I' : case 'J' : case 'S' : case 'V' : + case 'Z' : case '*' : case 'X' : case 'Y' : + index++; + break; + case 'L' : case '.' : + index++; + c = '.'; + + // Recherche de ; ou de < + while (index < length) + { + c = caSignature[index]; + if ((c == ';') || (c == '<')) + break; + index++; + } + + if (c == '<') + { + index = SkipSignature(caSignature, length, index+1); + + while (caSignature[index] != '>') + { + index = SkipSignature(caSignature, length, index); + } + + // pass '>' + index++; + } + + // pass ';' + if (caSignature[index] == ';') + index++; + break; + case 'T' : + index = CharArrayUtil.IndexOf(caSignature, ';', index+1) + 1; + break; + case '-' : case '+' : + index = SkipSignature(caSignature, length, index+1); + break; + //default: + // DEBUG + //new Throwable( + // "SignatureWriter.WriteSignature: invalid signature '" + + // String.valueOf(caSignature) + "'").printStackTrace(); + // DEBUG + } + + if ((index >= length) || (caSignature[index] != '.')) + break; + } + + return index; + } + + public static String GetSignatureFromType(int type) + { + switch (type) + { + case ByteCodeConstants.T_BOOLEAN: return "Z"; + case ByteCodeConstants.T_CHAR: return "C"; + case ByteCodeConstants.T_FLOAT: return "F"; + case ByteCodeConstants.T_DOUBLE: return "D"; + case ByteCodeConstants.T_BYTE: return "B"; + case ByteCodeConstants.T_SHORT: return "S"; + case ByteCodeConstants.T_INT: return "I"; + case ByteCodeConstants.T_LONG: return "J"; + default: return null; + } + } + + public static int GetTypeFromSignature(String signature) + { + if (signature.length() != 1) + return 0; + + switch (signature.charAt(0)) + { + case 'Z': return ByteCodeConstants.T_BOOLEAN; + case 'C': return ByteCodeConstants.T_CHAR; + case 'F': return ByteCodeConstants.T_FLOAT; + case 'D': return ByteCodeConstants.T_DOUBLE; + case 'B': return ByteCodeConstants.T_BYTE; + case 'S': return ByteCodeConstants.T_SHORT; + case 'I': return ByteCodeConstants.T_INT; + case 'J': return ByteCodeConstants.T_LONG; + default: return 0; + } + } + + public static boolean IsPrimitiveSignature(String signature) + { + if ((signature == null) || (signature.length() != 1)) + return false; + + switch (signature.charAt(0)) + { + case 'Z': case 'C': case 'F': case 'D': + case 'B': case 'S': case 'I': case 'J': + return true; + default: + return false; + } + } + + public static boolean IsIntegerSignature(String signature) + { + if ((signature == null) || (signature.length() != 1)) + return false; + + switch (signature.charAt(0)) + { + case 'C': case 'B': case 'S': case 'I': + return true; + default: + return false; + } + } + + public static boolean IsObjectSignature(String signature) + { + if ((signature == null) || (signature.length() <= 2)) + return false; + + return signature.charAt(0) == 'L'; + } + + public static String GetInternalName(String signature) + { + char[] caSignature = signature.toCharArray(); + int length = signature.length(); + int beginIndex = 0; + + while ((beginIndex < length) && (caSignature[beginIndex] == '[')) + beginIndex++; + + if ((beginIndex < length) && (caSignature[beginIndex] == 'L')) + { + beginIndex++; + length--; + return CharArrayUtil.Substring(caSignature, beginIndex, length); + } + else + { + return (beginIndex == 0) ? signature : + CharArrayUtil.Substring(caSignature, beginIndex, length); + } + } + + public static String CutArrayDimensionPrefix(String signature) + { + int beginIndex = 0; + + while (signature.charAt(beginIndex) == '[') + beginIndex++; + + return signature.substring(beginIndex); + } + + public static int GetArrayDimensionCount(String signature) + { + int beginIndex = 0; + + while (signature.charAt(beginIndex) == '[') + beginIndex++; + + return beginIndex; + } + + public static String GetInnerName(String signature) + { + signature = CutArrayDimensionPrefix(signature); + + switch (signature.charAt(0)) + { + case 'L': + case 'T': + return signature.substring(1, signature.length()-1); + default: + return signature; + } + } + + public static ArrayList GetParameterSignatures( + String methodSignature) + { + char[] caSignature = methodSignature.toCharArray(); + int length = caSignature.length; + ArrayList parameterTypes = new ArrayList(1); + int index = CharArrayUtil.IndexOf(caSignature, '(', 0); + + if (index != -1) + { + // pass '(' + index++; + + // Arguments + while (caSignature[index] != ')') + { + int newIndex = SkipSignature(caSignature, length, index); + parameterTypes.add(methodSignature.substring(index, newIndex)); + index = newIndex; + } + } + + return parameterTypes; + } + + public static String GetMethodReturnedSignature(String signature) + { + int index = signature.indexOf(')'); + if (index == -1) + return null; + + return signature.substring(index + 1); + } + + public static int GetParameterSignatureCount(String methodSignature) + { + char[] caSignature = methodSignature.toCharArray(); + int length = caSignature.length; + int index = CharArrayUtil.IndexOf(caSignature, '(', 0); + int count = 0; + + if (index != -1) + { + // pass '(' + index++; + + // Arguments + while (caSignature[index] != ')') + { + int newIndex = SkipSignature(caSignature, length, index); + index = newIndex; + count++; + } + } + + return count; + } + + public static int CreateTypesBitField(String signature) + { + /* + * Pour une constante de type 'signature', les types de variable + * possible est retourn�e. + */ + switch (signature.charAt(0)) + { + case 'I': return ByteCodeConstants.TBF_INT_INT; + case 'S': return ByteCodeConstants.TBF_INT_INT | ByteCodeConstants.TBF_INT_SHORT; + case 'B': return ByteCodeConstants.TBF_INT_INT | ByteCodeConstants.TBF_INT_SHORT | ByteCodeConstants.TBF_INT_BYTE; + case 'C': return ByteCodeConstants.TBF_INT_INT | ByteCodeConstants.TBF_INT_SHORT | ByteCodeConstants.TBF_INT_CHAR; + case 'X': return ByteCodeConstants.TBF_INT_INT | ByteCodeConstants.TBF_INT_SHORT | ByteCodeConstants.TBF_INT_BYTE | ByteCodeConstants.TBF_INT_CHAR | ByteCodeConstants.TBF_INT_BOOLEAN; + case 'Y': return ByteCodeConstants.TBF_INT_INT | ByteCodeConstants.TBF_INT_SHORT | ByteCodeConstants.TBF_INT_BYTE | ByteCodeConstants.TBF_INT_CHAR; + case 'Z': return ByteCodeConstants.TBF_INT_BOOLEAN; + default: return 0; + } + } + + public static int CreateArgOrReturnBitFields(String signature) + { + /* + * Pour un argument de type 'signature', les types de variable possible + * est retourn�e. + */ + switch (signature.charAt(0)) + { + case 'I': return ByteCodeConstants.TBF_INT_INT | ByteCodeConstants.TBF_INT_SHORT | ByteCodeConstants.TBF_INT_BYTE | ByteCodeConstants.TBF_INT_CHAR; + case 'S': return ByteCodeConstants.TBF_INT_SHORT | ByteCodeConstants.TBF_INT_BYTE; + case 'B': return ByteCodeConstants.TBF_INT_BYTE; + case 'C': return ByteCodeConstants.TBF_INT_CHAR; + case 'X': return ByteCodeConstants.TBF_INT_INT | ByteCodeConstants.TBF_INT_SHORT | ByteCodeConstants.TBF_INT_BYTE | ByteCodeConstants.TBF_INT_CHAR | ByteCodeConstants.TBF_INT_BOOLEAN; + case 'Y': return ByteCodeConstants.TBF_INT_INT | ByteCodeConstants.TBF_INT_SHORT | ByteCodeConstants.TBF_INT_BYTE | ByteCodeConstants.TBF_INT_CHAR; + case 'Z': return ByteCodeConstants.TBF_INT_BOOLEAN; + default: return 0; + } + } + + public static String GetSignatureFromTypesBitField(int typesBitField) + { + /* + * Lorsqu'un choix est possible, le plus 'gros' type est retourn�. + */ + if ((typesBitField & ByteCodeConstants.TBF_INT_INT) != 0) + return "I"; + if ((typesBitField & ByteCodeConstants.TBF_INT_SHORT) != 0) + return "S"; + if ((typesBitField & ByteCodeConstants.TBF_INT_CHAR) != 0) + return "C"; + if ((typesBitField & ByteCodeConstants.TBF_INT_BYTE) != 0) + return "B"; + if ((typesBitField & ByteCodeConstants.TBF_INT_BOOLEAN) != 0) + return "Z"; + return "I"; + } + + public static String CreateTypeName(String signature) + { + if (signature.length() == 0) + return signature; + + switch(signature.charAt(0)) + { + case '[': + return signature; + case 'L': + case 'T': + if (signature.charAt(signature.length()-1) == ';') + return signature; + default: + return "L" + signature + ';'; + } + } +} diff --git a/src/jd/core/util/StringConstants.java b/src/jd/core/util/StringConstants.java new file mode 100644 index 00000000..9caa7d22 --- /dev/null +++ b/src/jd/core/util/StringConstants.java @@ -0,0 +1,70 @@ +package jd.core.util; + + +public class StringConstants +{ + public static final String CLASS_CONSTRUCTOR = ""; + public static final String INSTANCE_CONSTRUCTOR = ""; + + public static final String INTERNAL_CLASS_CLASS_NAME = "java/lang/Class"; + public static final String INTERNAL_OBJECT_CLASS_NAME = "java/lang/Object"; + public static final String INTERNAL_STRING_CLASS_NAME = "java/lang/String"; + public static final String INTERNAL_STRINGBUFFER_CLASS_NAME = "java/lang/StringBuffer"; + public static final String INTERNAL_STRINGBUILDER_CLASS_NAME = "java/lang/StringBuilder"; + public static final String INTERNAL_THROWABLE_CLASS_NAME = "java/lang/Throwable"; + public static final String INTERNAL_JAVA_LANG_PACKAGE_NAME = "java/lang"; + public static final char INTERNAL_PACKAGE_SEPARATOR = '/'; + public static final char INTERNAL_INNER_SEPARATOR = '$'; + public static final char INTERNAL_BEGIN_TEMPLATE = '<'; + public static final char INTERNAL_END_TEMPLATE = '>'; + + public static final char PACKAGE_SEPARATOR = '.'; + public static final char INNER_SEPARATOR = '.'; + public static final String CLASS_FILE_SUFFIX = ".class"; + + public static final String INTERNAL_CLASS_SIGNATURE = "Ljava/lang/Class;"; + public static final String INTERNAL_OBJECT_SIGNATURE = "Ljava/lang/Object;"; + public static final String INTERNAL_STRING_SIGNATURE = "Ljava/lang/String;"; + public static final String INTERNAL_DEPRECATED_SIGNATURE = "Ljava/lang/Deprecated;"; + public static final String INTERNAL_CLASSNOTFOUNDEXCEPTION_SIGNATURE = + "Ljava/lang/ClassNotFoundException;"; + + public static final String THIS_LOCAL_VARIABLE_NAME = "this"; + public static final String OUTER_THIS_LOCAL_VARIABLE_NAME = "this$1"; + public static final String TMP_LOCAL_VARIABLE_NAME = "tmp"; + + public static final String INDENT = " "; + + public static final String ENUM_VALUES_ARRAY_NAME = "$VALUES"; + public static final String ENUM_VALUES_ARRAY_NAME_ECLIPSE = "ENUM$VALUES"; + public static final String ENUM_VALUES_METHOD_NAME = "values"; + public static final String ENUM_VALUEOF_METHOD_NAME = "valueOf"; + public static final String TOSTRING_METHOD_NAME = "toString"; + public static final String VALUEOF_METHOD_NAME = "valueOf"; + public static final String APPEND_METHOD_NAME = "append"; + public static final String FORNAME_METHOD_NAME = "forName"; + public static final String ORDINAL_METHOD_NAME = "ordinal"; + + public static final String ANNOTATIONDEFAULT_ATTRIBUTE_NAME = "AnnotationDefault"; + public static final String CODE_ATTRIBUTE_NAME = "Code"; + public static final String CONSTANTVALUE_ATTRIBUTE_NAME = "ConstantValue"; + public static final String DEPRECATED_ATTRIBUTE_NAME = "Deprecated"; + public static final String ENCLOSINGMETHOD_ATTRIBUTE_NAME = "EnclosingMethod"; + public static final String EXCEPTIONS_ATTRIBUTE_NAME = "Exceptions"; + public static final String INNERCLASSES_ATTRIBUTE_NAME = "InnerClasses"; + public static final String LINENUMBERTABLE_ATTRIBUTE_NAME = "LineNumberTable"; + public static final String LOCALVARIABLETABLE_ATTRIBUTE_NAME = "LocalVariableTable"; + public static final String LOCALVARIABLETYPETABLE_ATTRIBUTE_NAME = "LocalVariableTypeTable"; + public static final String RUNTIMEINVISIBLEANNOTATIONS_ATTRIBUTE_NAME = "RuntimeInvisibleAnnotations"; + public static final String RUNTIMEVISIBLEANNOTATIONS_ATTRIBUTE_NAME = "RuntimeVisibleAnnotations"; + public static final String RUNTIMEINVISIBLEPARAMETERANNOTATIONS_ATTRIBUTE_NAME = "RuntimeInvisibleParameterAnnotations"; + public static final String RUNTIMEVISIBLEPARAMETERANNOTATIONS_ATTRIBUTE_NAME = "RuntimeVisibleParameterAnnotations"; + public static final String SIGNATURE_ATTRIBUTE_NAME = "Signature"; + public static final String SOURCEFILE_ATTRIBUTE_NAME = "SourceFile"; + public static final String SYNTHETIC_ATTRIBUTE_NAME = "Synthetic"; + + public static final String CLASS_DOLLAR = "class$"; + public static final String ARRAY_DOLLAR = "array$"; + public static final String JD_METHOD_PREFIX = "jdMethod_"; + public static final String JD_FIELD_PREFIX = "jdField_"; +} diff --git a/src/jd/core/util/StringToIndexMap.java b/src/jd/core/util/StringToIndexMap.java new file mode 100644 index 00000000..a4bab317 --- /dev/null +++ b/src/jd/core/util/StringToIndexMap.java @@ -0,0 +1,70 @@ +package jd.core.util; + +public class StringToIndexMap +{ + private static final int INITIAL_CAPACITY = 128*2; + + private HashEntry[] entries; + + public StringToIndexMap() + { + this.entries = new HashEntry[INITIAL_CAPACITY]; + } + + public void put(String key, int value) + { + int hashCode = key.hashCode(); + int index = hashCodeToIndex(hashCode, this.entries.length); + HashEntry entry = this.entries[index]; + + while (entry != null) + { + if ((entry.hashCode == hashCode) && key.equals(entry.key)) + { + entry.value = value; + return; + } + entry = entry.next; + } + + this.entries[index] = + new HashEntry(key, hashCode, value, this.entries[index]); + } + + public int get(String key) + { + int hashCode = key.hashCode(); + int index = hashCodeToIndex(hashCode, this.entries.length); + HashEntry entry = this.entries[index]; + + while (entry != null) + { + if ((entry.hashCode == hashCode) && key.equals(entry.key)) + return entry.value; + entry = entry.next; + } + + return -1; + } + + private int hashCodeToIndex(int hashCode, int size) + { + return hashCode & (size - 1); + } + + private static class HashEntry + { + public String key; + public int hashCode; + public int value; + public HashEntry next; + + public HashEntry(String key, int hashCode, int value, HashEntry next) + { + this.key = key; + this.hashCode = hashCode; + this.value = value; + this.next = next; + } + } +} diff --git a/src/jd/core/util/StringUtil.java b/src/jd/core/util/StringUtil.java new file mode 100644 index 00000000..4cd208eb --- /dev/null +++ b/src/jd/core/util/StringUtil.java @@ -0,0 +1,79 @@ +package jd.core.util; + +public class StringUtil +{ + private static void EscapeChar(StringBuffer sb, char c) + { + switch (c) + { + case '\\': + sb.append("\\\\"); + break; + case '\b': + sb.append("\\b"); + break; + case '\f': + sb.append("\\f"); + break; + case '\n': + sb.append("\\n"); + break; + case '\r': + sb.append("\\r"); + break; + case '\t': + sb.append("\\t"); + break; + default: + if (c < ' ') + { + sb.append("\\0"); + sb.append((char)('0' + ((int)c >> 3))); + sb.append((char)('0' + ((int)c & 7))); + } + else + { + sb.append(c); + } + } + } + + public static String EscapeStringAndAppendQuotationMark(String s) + { + int length = s.length(); + StringBuffer sb = new StringBuffer(length * 2 + 2); + + sb.append('"'); + + if (length > 0) + { + for (int i=0; i