/** Returns the ClassMemberSpecification currently represented in this dialog. */ public ClassMemberSpecification getClassMemberSpecification() { String name = nameTextField.getText(); String type = typeTextField.getText(); String arguments = argumentsTextField.getText(); if (name.equals("") || name.equals("*")) { name = null; } if (type.equals("") || type.equals("*")) { type = null; } if (name != null || type != null) { if (isField) { if (type == null) { type = ClassConstants.EXTERNAL_TYPE_INT; } type = ClassUtil.internalType(type); } else { if (type == null) { type = ClassConstants.EXTERNAL_TYPE_VOID; } type = ClassUtil.internalMethodDescriptor(type, ListUtil.commaSeparatedList(arguments)); } } ClassMemberSpecification classMemberSpecification = new ClassMemberSpecification(0, 0, name, type); // Also get the access radio button settings. getClassMemberSpecificationRadioButtons( classMemberSpecification, ClassConstants.INTERNAL_ACC_PUBLIC, publicRadioButtons); getClassMemberSpecificationRadioButtons( classMemberSpecification, ClassConstants.INTERNAL_ACC_PRIVATE, privateRadioButtons); getClassMemberSpecificationRadioButtons( classMemberSpecification, ClassConstants.INTERNAL_ACC_PROTECTED, protectedRadioButtons); getClassMemberSpecificationRadioButtons( classMemberSpecification, ClassConstants.INTERNAL_ACC_STATIC, staticRadioButtons); getClassMemberSpecificationRadioButtons( classMemberSpecification, ClassConstants.INTERNAL_ACC_FINAL, finalRadioButtons); getClassMemberSpecificationRadioButtons( classMemberSpecification, ClassConstants.INTERNAL_ACC_VOLATILE, volatileRadioButtons); getClassMemberSpecificationRadioButtons( classMemberSpecification, ClassConstants.INTERNAL_ACC_TRANSIENT, transientRadioButtons); getClassMemberSpecificationRadioButtons( classMemberSpecification, ClassConstants.INTERNAL_ACC_SYNCHRONIZED, synchronizedRadioButtons); getClassMemberSpecificationRadioButtons( classMemberSpecification, ClassConstants.INTERNAL_ACC_NATIVE, nativeRadioButtons); getClassMemberSpecificationRadioButtons( classMemberSpecification, ClassConstants.INTERNAL_ACC_ABSTRACT, abstractRadioButtons); getClassMemberSpecificationRadioButtons( classMemberSpecification, ClassConstants.INTERNAL_ACC_STRICT, strictRadioButtons); return classMemberSpecification; }
public void visitProgramClass(ProgramClass programClass) { String name = programClass.getName(); String newName = ClassObfuscator.newClassName(programClass); ps.println( ClassUtil.externalClassName(name) + " -> " + ClassUtil.externalClassName(newName) + ":"); // Print out the class members. programClass.fieldsAccept(this); programClass.methodsAccept(this); }
private void writeMethodSpecification(List memberSpecifications) { if (memberSpecifications != null) { for (int index = 0; index < memberSpecifications.size(); index++) { MemberSpecification memberSpecification = (MemberSpecification) memberSpecifications.get(index); writer.print(" "); // Write out the required annotation, if any. if (memberSpecification.annotationType != null) { writer.print(ConfigurationConstants.ANNOTATION_KEYWORD); writer.println(ClassUtil.externalType(memberSpecification.annotationType)); writer.print(" "); } // Write out the method access flags. writer.print( ClassUtil.externalMethodAccessFlags( memberSpecification.requiredUnsetAccessFlags, ConfigurationConstants.NEGATOR_KEYWORD)); writer.print( ClassUtil.externalMethodAccessFlags(memberSpecification.requiredSetAccessFlags)); // Write out the method name and descriptor. String name = memberSpecification.name; String descriptor = memberSpecification.descriptor; writer.print( descriptor == null ? name == null ? ConfigurationConstants.ANY_METHOD_KEYWORD : ConfigurationConstants.ANY_TYPE_KEYWORD + ' ' + name + ConfigurationConstants.OPEN_ARGUMENTS_KEYWORD + ConfigurationConstants.ANY_ARGUMENTS_KEYWORD + ConfigurationConstants.CLOSE_ARGUMENTS_KEYWORD : ClassUtil.externalFullMethodDescription( ClassConstants.METHOD_NAME_INIT, 0, name == null ? ConfigurationConstants.ANY_CLASS_MEMBER_KEYWORD : name, descriptor)); writer.println(ConfigurationConstants.SEPARATOR_KEYWORD); } } }
public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // DEBUG = // clazz.getName().equals("abc/Def") && // method.getName(clazz).equals("abc"); // The minimum variable size is determined by the arguments. codeAttribute.u2maxLocals = ClassUtil.internalMethodParameterSize(method.getDescriptor(clazz), method.getAccessFlags()); if (DEBUG) { System.out.println( "VariableSizeUpdater: " + clazz.getName() + "." + method.getName(clazz) + method.getDescriptor(clazz)); System.out.println(" Max locals: " + codeAttribute.u2maxLocals + " <- parameters"); } // Go over all instructions. codeAttribute.instructionsAccept(clazz, method, this); // Remove the unused variables of the attributes. codeAttribute.attributesAccept(clazz, method, variableCleaner); }
public void visitLibraryClass(LibraryClass libraryClass) { notePrinter.print( libraryClass.getName(), "Note: duplicate definition of library class [" + ClassUtil.externalClassName(libraryClass.getName()) + "]"); }
/** Returns a shrunk descriptor or signature of the given method. */ private String shrinkDescriptor(Method method, String descriptor) { // All parameters of non-static methods are shifted by one in the local // variable frame. int parameterIndex = (method.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) != 0 ? 0 : 1; // Go over the parameters. InternalTypeEnumeration internalTypeEnumeration = new InternalTypeEnumeration(descriptor); StringBuffer newDescriptorBuffer = new StringBuffer(); newDescriptorBuffer.append(internalTypeEnumeration.formalTypeParameters()); newDescriptorBuffer.append(ClassConstants.INTERNAL_METHOD_ARGUMENTS_OPEN); while (internalTypeEnumeration.hasMoreTypes()) { String type = internalTypeEnumeration.nextType(); if (ParameterUsageMarker.isParameterUsed(method, parameterIndex)) { newDescriptorBuffer.append(type); } else if (DEBUG) { System.out.println(" Deleting parameter #" + parameterIndex + " [" + type + "]"); } parameterIndex += ClassUtil.isInternalCategory2Type(type) ? 2 : 1; } newDescriptorBuffer.append(ClassConstants.INTERNAL_METHOD_ARGUMENTS_CLOSE); newDescriptorBuffer.append(internalTypeEnumeration.returnType()); return newDescriptorBuffer.toString(); }
public ReferenceValue referenceArrayLoad(IntegerValue indexValue, ValueFactory valueFactory) { return type == null ? ValueFactory.REFERENCE_VALUE_NULL : !ClassUtil.isInternalArrayType(type) ? ValueFactory.REFERENCE_VALUE_JAVA_LANG_OBJECT_MAYBE_NULL : valueFactory.createValue(type.substring(1), referencedClass, true).referenceValue(); }
public final String internalType() { return type == null ? ClassConstants.TYPE_JAVA_LANG_OBJECT : ClassUtil.isInternalArrayType(type) ? type : ClassConstants.TYPE_CLASS_START + type + ClassConstants.TYPE_CLASS_END; }
/** * Marks the hierarchy of implementing or overriding methods corresponding to the given method, if * any. */ protected void markMethodHierarchy(Clazz clazz, Method method) { int accessFlags = method.getAccessFlags(); if ((accessFlags & (ClassConstants.ACC_PRIVATE | ClassConstants.ACC_STATIC)) == 0 && !ClassUtil.isInitializer(method.getName(clazz))) { // We can skip private and static methods in the hierarchy, and // also abstract methods, unless they might widen a current // non-public access. int requiredUnsetAccessFlags = ClassConstants.ACC_PRIVATE | ClassConstants.ACC_STATIC | ((accessFlags & ClassConstants.ACC_PUBLIC) == 0 ? 0 : ClassConstants.ACC_ABSTRACT); clazz.accept( new ConcreteClassDownTraveler( new ClassHierarchyTraveler( true, true, false, true, new NamedMethodVisitor( method.getName(clazz), method.getDescriptor(clazz), new MemberAccessFilter(0, requiredUnsetAccessFlags, this))))); } }
public void visitProgramClass(ProgramClass programClass) { notePrinter.print( programClass.getName(), "Note: duplicate definition of program class [" + ClassUtil.externalClassName(programClass.getName()) + "]"); }
public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute) { // Process the generic definitions, superclass, and implemented // interfaces. String signature = clazz.getString(signatureAttribute.u2signatureIndex); // Count the signature types. InternalTypeEnumeration internalTypeEnumeration = new InternalTypeEnumeration(signature); int count = 0; int interfacesCount = -1; while (internalTypeEnumeration.hasMoreTypes()) { String internalType = internalTypeEnumeration.nextType(); count++; if (ClassUtil.isInternalClassType(internalType)) { interfacesCount++; } } // Put the signature types in an array. internalTypeEnumeration = new InternalTypeEnumeration(signature); String[] internalTypes = new String[count]; for (int index = 0; index < count; index++) { String internalType = internalTypeEnumeration.nextType(); internalTypes[index] = internalType; } // Sort the interface types in the array. Arrays.sort(internalTypes, count - interfacesCount, count); // Recompose the signature types in a string. StringBuffer newSignatureBuffer = new StringBuffer(); for (int index = 0; index < count; index++) { // Is this not an interface type, or an interface type that isn't // a duplicate of the previous interface type? if (index < count - interfacesCount || !internalTypes[index].equals(internalTypes[index - 1])) { newSignatureBuffer.append(internalTypes[index]); } } String newSignature = newSignatureBuffer.toString(); // Did the signature change? if (!newSignature.equals(signature)) { // Update the signature. ((Utf8Constant) ((ProgramClass) clazz).constantPool[signatureAttribute.u2signatureIndex]) .setString(newSignatureBuffer.toString()); // Clear the referenced classes. // TODO: Properly update the referenced classes. signatureAttribute.referencedClasses = null; } }
/** Returns a list with external versions of the given list of internal class names. */ private List externalClassNames(List internalClassNames) { List externalClassNames = new ArrayList(internalClassNames.size()); for (int index = 0; index < internalClassNames.size(); index++) { externalClassNames.add(ClassUtil.externalClassName((String) internalClassNames.get(index))); } return externalClassNames; }
/** Shrinks the array of referenced classes of the given method. */ private Clazz[] shrinkReferencedClasses( Method method, String descriptor, Clazz[] referencedClasses) { if (referencedClasses != null) { // All parameters of non-static methods are shifted by one in the local // variable frame. int parameterIndex = (method.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) != 0 ? 0 : 1; int referencedClassIndex = 0; int newReferencedClassIndex = 0; // Go over the parameters. InternalTypeEnumeration internalTypeEnumeration = new InternalTypeEnumeration(descriptor); // Also look at the formal type parameters. String type = internalTypeEnumeration.formalTypeParameters(); int count = new DescriptorClassEnumeration(type).classCount(); for (int counter = 0; counter < count; counter++) { referencedClasses[newReferencedClassIndex++] = referencedClasses[referencedClassIndex++]; } while (internalTypeEnumeration.hasMoreTypes()) { // Consider the classes referenced by this parameter type. type = internalTypeEnumeration.nextType(); count = new DescriptorClassEnumeration(type).classCount(); if (ParameterUsageMarker.isParameterUsed(method, parameterIndex)) { // Copy the referenced classes. for (int counter = 0; counter < count; counter++) { referencedClasses[newReferencedClassIndex++] = referencedClasses[referencedClassIndex++]; } } else { // Skip the referenced classes. referencedClassIndex += count; } parameterIndex += ClassUtil.isInternalCategory2Type(type) ? 2 : 1; } // Also look at the return value. type = internalTypeEnumeration.returnType(); count = new DescriptorClassEnumeration(type).classCount(); for (int counter = 0; counter < count; counter++) { referencedClasses[newReferencedClassIndex++] = referencedClasses[referencedClassIndex++]; } // Clear the unused entries. while (newReferencedClassIndex < referencedClassIndex) { referencedClasses[newReferencedClassIndex++] = null; } } return referencedClasses; }
/** Sets the ClassMemberSpecification to be represented in this dialog. */ public void setClassMemberSpecification(ClassMemberSpecification classMemberSpecification) { String name = classMemberSpecification.name; String descriptor = classMemberSpecification.descriptor; // Set the access radio buttons. setClassMemberSpecificationRadioButtons( classMemberSpecification, ClassConstants.INTERNAL_ACC_PUBLIC, publicRadioButtons); setClassMemberSpecificationRadioButtons( classMemberSpecification, ClassConstants.INTERNAL_ACC_PRIVATE, privateRadioButtons); setClassMemberSpecificationRadioButtons( classMemberSpecification, ClassConstants.INTERNAL_ACC_PROTECTED, protectedRadioButtons); setClassMemberSpecificationRadioButtons( classMemberSpecification, ClassConstants.INTERNAL_ACC_STATIC, staticRadioButtons); setClassMemberSpecificationRadioButtons( classMemberSpecification, ClassConstants.INTERNAL_ACC_FINAL, finalRadioButtons); setClassMemberSpecificationRadioButtons( classMemberSpecification, ClassConstants.INTERNAL_ACC_VOLATILE, volatileRadioButtons); setClassMemberSpecificationRadioButtons( classMemberSpecification, ClassConstants.INTERNAL_ACC_TRANSIENT, transientRadioButtons); setClassMemberSpecificationRadioButtons( classMemberSpecification, ClassConstants.INTERNAL_ACC_SYNCHRONIZED, synchronizedRadioButtons); setClassMemberSpecificationRadioButtons( classMemberSpecification, ClassConstants.INTERNAL_ACC_NATIVE, nativeRadioButtons); setClassMemberSpecificationRadioButtons( classMemberSpecification, ClassConstants.INTERNAL_ACC_ABSTRACT, abstractRadioButtons); setClassMemberSpecificationRadioButtons( classMemberSpecification, ClassConstants.INTERNAL_ACC_STRICT, strictRadioButtons); // Set the class name text fields. nameTextField.setText(name == null ? "" : name); if (isField) { typeTextField.setText(descriptor == null ? "" : ClassUtil.externalType(descriptor)); } else { typeTextField.setText( descriptor == null ? "" : ClassUtil.externalMethodReturnType(descriptor)); argumentsTextField.setText( descriptor == null ? "" : ClassUtil.externalMethodArguments(descriptor)); } }
private void writeOption(String optionName, String arguments, boolean replaceInternalClassNames) { if (arguments != null) { if (replaceInternalClassNames) { arguments = ClassUtil.externalClassName(arguments); } writer.print(optionName); writer.print(' '); writer.println(quotedString(arguments)); } }
public void visitProgramField(ProgramClass programClass, ProgramField programField) { String newName = MemberObfuscator.newMemberName(programField); if (newName != null) { ps.println( " " + // lineNumberRange(programClass, programField) + ClassUtil.externalFullFieldDescription( 0, programField.getName(programClass), programField.getDescriptor(programClass)) + " -> " + newName); } }
public void read(DataEntry dataEntry) throws IOException { try { // Get the input stream. InputStream inputStream = dataEntry.getInputStream(); // Wrap it into a data input stream. DataInputStream dataInputStream = new DataInputStream(inputStream); // Create a Clazz representation. Clazz clazz; if (isLibrary) { clazz = new LibraryClass(); clazz.accept( new LibraryClassReader( dataInputStream, skipNonPublicLibraryClasses, skipNonPublicLibraryClassMembers)); } else { clazz = new ProgramClass(); clazz.accept(new ProgramClassReader(dataInputStream)); } // Apply the visitor, if we have a real class. String className = clazz.getName(); if (className != null) { if (!dataEntry .getName() .replace(File.pathSeparatorChar, ClassConstants.PACKAGE_SEPARATOR) .equals(className + ClassConstants.CLASS_FILE_EXTENSION) && warningPrinter != null) { warningPrinter.print( className, "Warning: class [" + dataEntry.getName() + "] unexpectedly contains class [" + ClassUtil.externalClassName(className) + "]"); } clazz.accept(classVisitor); } dataEntry.closeInputStream(); } catch (Exception ex) { throw (IOException) new IOException( "Can't process class [" + dataEntry.getName() + "] (" + ex.getMessage() + ")") .initCause(ex); } }
/** * Marks the hierarchy of implementing or overriding methods corresponding to the given method, if * any. */ protected void markMethodHierarchy(Clazz clazz, Method method) { int accessFlags = method.getAccessFlags(); if ((accessFlags & (ClassConstants.ACC_PRIVATE | ClassConstants.ACC_STATIC)) == 0 && !ClassUtil.isInitializer(method.getName(clazz))) { // We can skip private and static methods in the hierarchy, and // also abstract methods, unless they might widen a current // non-public access. int requiredUnsetAccessFlags = ClassConstants.ACC_PRIVATE | ClassConstants.ACC_STATIC | ((accessFlags & ClassConstants.ACC_PUBLIC) == 0 ? 0 : ClassConstants.ACC_ABSTRACT); // Mark default implementations in interfaces down the hierarchy. // TODO: This may be premature if there aren't any concrete implementing classes. clazz.accept( new ClassAccessFilter( ClassConstants.ACC_ABSTRACT, 0, new ClassHierarchyTraveler( false, false, false, true, new ProgramClassFilter( new ClassAccessFilter( ClassConstants.ACC_ABSTRACT, 0, new NamedMethodVisitor( method.getName(clazz), method.getDescriptor(clazz), new MemberAccessFilter( 0, requiredUnsetAccessFlags, defaultMethodUsageMarker))))))); // Mark other implementations. clazz.accept( new ConcreteClassDownTraveler( new ClassHierarchyTraveler( true, true, false, true, new NamedMethodVisitor( method.getName(clazz), method.getDescriptor(clazz), new MemberAccessFilter(0, requiredUnsetAccessFlags, this))))); } }
public void visitAnyParameterAnnotationsAttribute( Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute) { int[] annotationsCounts = parameterAnnotationsAttribute.u2parameterAnnotationsCount; Annotation[][] annotations = parameterAnnotationsAttribute.parameterAnnotations; // All parameters of non-static methods are shifted by one in the local // variable frame. int parameterIndex = (method.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) != 0 ? 0 : 1; int annotationIndex = 0; int newAnnotationIndex = 0; // Go over the parameters. String descriptor = method.getDescriptor(clazz); InternalTypeEnumeration internalTypeEnumeration = new InternalTypeEnumeration(descriptor); while (internalTypeEnumeration.hasMoreTypes()) { String type = internalTypeEnumeration.nextType(); if (ParameterUsageMarker.isParameterUsed(method, parameterIndex)) { annotationsCounts[newAnnotationIndex] = annotationsCounts[annotationIndex]; annotations[newAnnotationIndex++] = annotations[annotationIndex]; } annotationIndex++; parameterIndex += ClassUtil.isInternalCategory2Type(type) ? 2 : 1; } // Update the number of parameters. parameterAnnotationsAttribute.u2parametersCount = newAnnotationIndex; // Clear the unused entries. while (newAnnotationIndex < annotationIndex) { annotationsCounts[newAnnotationIndex] = 0; annotations[newAnnotationIndex++] = null; } }
public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { // Special cases: <clinit> and <init> are always kept unchanged. // We can ignore them here. String name = programMethod.getName(programClass); if (name.equals(ClassConstants.INTERNAL_METHOD_NAME_CLINIT) || name.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT)) { return; } String newName = MemberObfuscator.newMemberName(programMethod); if (newName != null) { ps.println( " " + lineNumberRange(programClass, programMethod) + ClassUtil.externalFullMethodDescription( programClass.getName(), 0, programMethod.getName(programClass), programMethod.getDescriptor(programClass)) + " -> " + newName); } }
public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant) { String type = fieldrefConstant.getType(clazz); typeStackDelta = ClassUtil.internalTypeSize(ClassUtil.internalMethodReturnType(type)); }
public ReferenceValue generalize(TypedReferenceValue other) { // If both types are identical, the generalization is the same too. if (this.equals(other)) { return this; } String thisType = this.type; String otherType = other.type; // If both types are nul, the generalization is null too. if (thisType == null && otherType == null) { return ValueFactory.REFERENCE_VALUE_NULL; } // If this type is null, the generalization is the other type, maybe null. if (thisType == null) { return other.generalizeMayBeNull(true); } // If the other type is null, the generalization is this type, maybe null. if (otherType == null) { return this.generalizeMayBeNull(true); } boolean mayBeNull = this.mayBeNull || other.mayBeNull; // If the two types are equal, the generalization remains the same, maybe null. if (thisType.equals(otherType)) { return typedReferenceValue(this, mayBeNull); } // Start taking into account the type dimensions. int thisDimensionCount = ClassUtil.internalArrayTypeDimensionCount(thisType); int otherDimensionCount = ClassUtil.internalArrayTypeDimensionCount(otherType); int commonDimensionCount = Math.min(thisDimensionCount, otherDimensionCount); if (thisDimensionCount == otherDimensionCount) { // See if we can take into account the referenced classes. Clazz thisReferencedClass = this.referencedClass; Clazz otherReferencedClass = other.referencedClass; if (thisReferencedClass != null && otherReferencedClass != null) { // Is one class simply an extension of the other one? if (thisReferencedClass.extendsOrImplements(otherReferencedClass)) { return typedReferenceValue(other, mayBeNull); } if (otherReferencedClass.extendsOrImplements(thisReferencedClass)) { return typedReferenceValue(this, mayBeNull); } // Do the classes have a non-trivial common superclass? Clazz commonClass = findCommonClass(thisReferencedClass, otherReferencedClass, false); if (commonClass.getName().equals(ClassConstants.NAME_JAVA_LANG_OBJECT)) { // Otherwise, do the classes have a common interface? Clazz commonInterface = findCommonClass(thisReferencedClass, otherReferencedClass, true); if (commonInterface != null) { commonClass = commonInterface; } } return new TypedReferenceValue( commonDimensionCount == 0 ? commonClass.getName() : ClassUtil.internalArrayTypeFromClassName( commonClass.getName(), commonDimensionCount), commonClass, mayBeNull); } } else if (thisDimensionCount > otherDimensionCount) { // See if the other type is an interface type of arrays. if (ClassUtil.isInternalArrayInterfaceName( ClassUtil.internalClassNameFromClassType(otherType))) { return typedReferenceValue(other, mayBeNull); } } else if (thisDimensionCount < otherDimensionCount) { // See if this type is an interface type of arrays. if (ClassUtil.isInternalArrayInterfaceName( ClassUtil.internalClassNameFromClassType(thisType))) { return typedReferenceValue(this, mayBeNull); } } // Reduce the common dimension count if either type is an array of // primitives type of this dimension. if (commonDimensionCount > 0 && (ClassUtil.isInternalPrimitiveType(otherType.charAt(commonDimensionCount))) || ClassUtil.isInternalPrimitiveType(thisType.charAt(commonDimensionCount))) { commonDimensionCount--; } // Fall back on a basic Object or array of Objects type. return commonDimensionCount != 0 ? new TypedReferenceValue( ClassUtil.internalArrayTypeFromClassName( ClassConstants.NAME_JAVA_LANG_OBJECT, commonDimensionCount), null, mayBeNull) : mayBeNull ? ValueFactory.REFERENCE_VALUE_JAVA_LANG_OBJECT_MAYBE_NULL : ValueFactory.REFERENCE_VALUE_JAVA_LANG_OBJECT_NOT_NULL; }
private void visitRefConstant(Clazz clazz, RefConstant methodrefConstant) { String type = methodrefConstant.getType(clazz); parameterStackDelta = ClassUtil.internalMethodParameterSize(type); typeStackDelta = ClassUtil.internalTypeSize(ClassUtil.internalMethodReturnType(type)); }
private void writeOption(String optionName, ClassSpecification classSpecification) { writer.println(); // Write out the comments for this option. writeComments(classSpecification.comments); writer.print(optionName); writer.print(' '); // Write out the required annotation, if any. if (classSpecification.annotationType != null) { writer.print(ConfigurationConstants.ANNOTATION_KEYWORD); writer.print(ClassUtil.externalType(classSpecification.annotationType)); writer.print(' '); } // Write out the class access flags. writer.print( ClassUtil.externalClassAccessFlags( classSpecification.requiredUnsetAccessFlags, ConfigurationConstants.NEGATOR_KEYWORD)); writer.print(ClassUtil.externalClassAccessFlags(classSpecification.requiredSetAccessFlags)); // Write out the class keyword, if we didn't write the interface // keyword earlier. if (((classSpecification.requiredSetAccessFlags | classSpecification.requiredUnsetAccessFlags) & (ClassConstants.ACC_INTERFACE | ClassConstants.ACC_ENUM)) == 0) { writer.print(ConfigurationConstants.CLASS_KEYWORD); } writer.print(' '); // Write out the class name. writer.print( classSpecification.className != null ? ClassUtil.externalClassName(classSpecification.className) : ConfigurationConstants.ANY_CLASS_KEYWORD); // Write out the extends template, if any. if (classSpecification.extendsAnnotationType != null || classSpecification.extendsClassName != null) { writer.print(' '); writer.print(ConfigurationConstants.EXTENDS_KEYWORD); writer.print(' '); // Write out the required extends annotation, if any. if (classSpecification.extendsAnnotationType != null) { writer.print(ConfigurationConstants.ANNOTATION_KEYWORD); writer.print(ClassUtil.externalType(classSpecification.extendsAnnotationType)); writer.print(' '); } // Write out the extended class name. writer.print( classSpecification.extendsClassName != null ? ClassUtil.externalClassName(classSpecification.extendsClassName) : ConfigurationConstants.ANY_CLASS_KEYWORD); } // Write out the keep field and keep method options, if any. if (classSpecification.fieldSpecifications != null || classSpecification.methodSpecifications != null) { writer.print(' '); writer.println(ConfigurationConstants.OPEN_KEYWORD); writeFieldSpecification(classSpecification.fieldSpecifications); writeMethodSpecification(classSpecification.methodSpecifications); writer.println(ConfigurationConstants.CLOSE_KEYWORD); } else { writer.println(); } }
/** Performs the subsequent ReTrace operations. */ public void execute() throws IOException { // Read the mapping file. MappingReader mappingReader = new MappingReader(mappingFile); mappingReader.pump(this); StringBuffer expressionBuffer = new StringBuffer(regularExpression.length() + 32); char[] expressionTypes = new char[32]; int expressionTypeCount = 0; int index = 0; while (true) { int nextIndex = regularExpression.indexOf('%', index); if (nextIndex < 0 || nextIndex == regularExpression.length() - 1 || expressionTypeCount == expressionTypes.length) { break; } expressionBuffer.append(regularExpression.substring(index, nextIndex)); expressionBuffer.append('('); char expressionType = regularExpression.charAt(nextIndex + 1); switch (expressionType) { case 'c': expressionBuffer.append(REGEX_CLASS); break; case 'C': expressionBuffer.append(REGEX_CLASS_SLASH); break; case 'l': expressionBuffer.append(REGEX_LINE_NUMBER); break; case 't': expressionBuffer.append(REGEX_TYPE); break; case 'f': expressionBuffer.append(REGEX_MEMBER); break; case 'm': expressionBuffer.append(REGEX_MEMBER); break; case 'a': expressionBuffer.append(REGEX_ARGUMENTS); break; } expressionBuffer.append(')'); expressionTypes[expressionTypeCount++] = expressionType; index = nextIndex + 2; } expressionBuffer.append(regularExpression.substring(index)); Pattern pattern = Pattern.compile(expressionBuffer.toString()); // Read the stack trace file. LineNumberReader reader = new LineNumberReader( stackTraceFile == null ? (Reader) new InputStreamReader(System.in) : (Reader) new BufferedReader(new FileReader(stackTraceFile))); try { StringBuffer outLine = new StringBuffer(256); List extraOutLines = new ArrayList(); String className = null; // Read the line in the stack trace. while (true) { String line = reader.readLine(); if (line == null) { break; } Matcher matcher = pattern.matcher(line); if (matcher.matches()) { int lineNumber = 0; String type = null; String arguments = null; // Figure out a class name, line number, type, and // arguments beforehand. for (int expressionTypeIndex = 0; expressionTypeIndex < expressionTypeCount; expressionTypeIndex++) { int startIndex = matcher.start(expressionTypeIndex + 1); if (startIndex >= 0) { String match = matcher.group(expressionTypeIndex + 1); char expressionType = expressionTypes[expressionTypeIndex]; switch (expressionType) { case 'c': className = originalClassName(match); break; case 'C': className = originalClassName(ClassUtil.externalClassName(match)); break; case 'l': lineNumber = Integer.parseInt(match); break; case 't': type = originalType(match); break; case 'a': arguments = originalArguments(match); break; } } } // Actually construct the output line. int lineIndex = 0; outLine.setLength(0); extraOutLines.clear(); for (int expressionTypeIndex = 0; expressionTypeIndex < expressionTypeCount; expressionTypeIndex++) { int startIndex = matcher.start(expressionTypeIndex + 1); if (startIndex >= 0) { int endIndex = matcher.end(expressionTypeIndex + 1); String match = matcher.group(expressionTypeIndex + 1); // Copy a literal piece of input line. outLine.append(line.substring(lineIndex, startIndex)); char expressionType = expressionTypes[expressionTypeIndex]; switch (expressionType) { case 'c': className = originalClassName(match); outLine.append(className); break; case 'C': className = originalClassName(ClassUtil.externalClassName(match)); outLine.append(ClassUtil.internalClassName(className)); break; case 'l': lineNumber = Integer.parseInt(match); outLine.append(match); break; case 't': type = originalType(match); outLine.append(type); break; case 'f': originalFieldName(className, match, type, outLine, extraOutLines); break; case 'm': originalMethodName( className, match, lineNumber, type, arguments, outLine, extraOutLines); break; case 'a': arguments = originalArguments(match); outLine.append(arguments); break; } // Skip the original element whose processed version // has just been appended. lineIndex = endIndex; } } // Copy the last literal piece of input line. outLine.append(line.substring(lineIndex)); // Print out the main line. System.out.println(outLine); // Print out any additional lines. for (int extraLineIndex = 0; extraLineIndex < extraOutLines.size(); extraLineIndex++) { System.out.println(extraOutLines.get(extraLineIndex)); } } else { // Print out the original line. System.out.println(line); } } } catch (IOException ex) { throw new IOException("Can't read stack trace (" + ex.getMessage() + ")"); } finally { if (stackTraceFile != null) { try { reader.close(); } catch (IOException ex) { // This shouldn't happen. } } } }
public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // Get the original parameter size that was saved. int oldParameterSize = ParameterUsageMarker.getParameterSize(method); // Compute the new parameter size from the shrunk descriptor. int newParameterSize = ClassUtil.internalMethodParameterSize(method.getDescriptor(clazz), method.getAccessFlags()); if (oldParameterSize > newParameterSize) { // Get the total size of the local variable frame. int maxLocals = codeAttribute.u2maxLocals; if (DEBUG) { System.out.println( "ParameterShrinker: " + clazz.getName() + "." + method.getName(clazz) + method.getDescriptor(clazz)); System.out.println(" Old parameter size = " + oldParameterSize); System.out.println(" New parameter size = " + newParameterSize); System.out.println(" Max locals = " + maxLocals); } // Create a variable map. int[] variableMap = new int[maxLocals]; // Move unused parameters right after the parameter block. int usedParameterIndex = 0; int unusedParameterIndex = newParameterSize; for (int parameterIndex = 0; parameterIndex < oldParameterSize; parameterIndex++) { // Is the variable required as a parameter? if (ParameterUsageMarker.isParameterUsed(method, parameterIndex)) { // Keep the variable as a parameter. variableMap[parameterIndex] = usedParameterIndex++; } else { if (DEBUG) { System.out.println(" Deleting parameter #" + parameterIndex); } // Shift the variable to the unused parameter block, // in case it is still used as a variable. variableMap[parameterIndex] = unusedParameterIndex++; // Visit the method, if required. if (extraVariableMemberVisitor != null) { method.accept(clazz, extraVariableMemberVisitor); } } } // Fill out the remainder of the map. for (int variableIndex = oldParameterSize; variableIndex < maxLocals; variableIndex++) { variableMap[variableIndex] = variableIndex; } // Set the map. variableRemapper.setVariableMap(variableMap); // Remap the variables. variableRemapper.visitCodeAttribute(clazz, method, codeAttribute); } }
public int instanceOf(String otherType, Clazz otherReferencedClass) { String thisType = this.type; // If this type is null, it is never an instance of any class. if (thisType == null) { return NEVER; } // Start taking into account the type dimensions. int thisDimensionCount = ClassUtil.internalArrayTypeDimensionCount(thisType); int otherDimensionCount = ClassUtil.internalArrayTypeDimensionCount(otherType); int commonDimensionCount = Math.min(thisDimensionCount, otherDimensionCount); // Strip any common array prefixes. thisType = thisType.substring(commonDimensionCount); otherType = otherType.substring(commonDimensionCount); // If either stripped type is a primitive type, we can tell right away. if (commonDimensionCount > 0 && (ClassUtil.isInternalPrimitiveType(thisType.charAt(0)) || ClassUtil.isInternalPrimitiveType(otherType.charAt(0)))) { return !thisType.equals(otherType) ? NEVER : mayBeNull ? MAYBE : ALWAYS; } // Strip the class type prefix and suffix of this type, if any. if (thisDimensionCount == commonDimensionCount) { thisType = ClassUtil.internalClassNameFromClassType(thisType); } // Strip the class type prefix and suffix of the other type, if any. if (otherDimensionCount == commonDimensionCount) { otherType = ClassUtil.internalClassNameFromClassType(otherType); } // If this type is an array type, and the other type is not // java.lang.Object, java.lang.Cloneable, or java.io.Serializable, // this type can never be an instance. if (thisDimensionCount > otherDimensionCount && !ClassUtil.isInternalArrayInterfaceName(otherType)) { return NEVER; } // If the other type is an array type, and this type is not // java.lang.Object, java.lang.Cloneable, or java.io.Serializable, // this type can never be an instance. if (thisDimensionCount < otherDimensionCount && !ClassUtil.isInternalArrayInterfaceName(thisType)) { return NEVER; } // If this type may be null, it might not be an instance of any class. if (mayBeNull) { return MAYBE; } // If this type is equal to the other type, or if the other type is // java.lang.Object, this type is always an instance. if (thisType.equals(otherType) || ClassConstants.NAME_JAVA_LANG_OBJECT.equals(otherType)) { return ALWAYS; } // If this type is an array type, it's ok. if (thisDimensionCount > otherDimensionCount) { return ALWAYS; } // If the other type is an array type, it might be ok. if (thisDimensionCount < otherDimensionCount) { return MAYBE; } // If the value extends the type, we're sure. return referencedClass != null && otherReferencedClass != null && referencedClass.extendsOrImplements(otherReferencedClass) ? ALWAYS : MAYBE; }
/** * Writes the given configuration. * * @param configuration the configuration that is to be written out. * @throws IOException if an IO error occurs while writing the configuration. */ public void write(Configuration configuration) throws IOException { // Write the program class path (input and output entries). writeJarOptions( ConfigurationConstants.INJARS_OPTION, ConfigurationConstants.OUTJARS_OPTION, configuration.programJars); writer.println(); // Write the library class path (output entries only). writeJarOptions( ConfigurationConstants.LIBRARYJARS_OPTION, ConfigurationConstants.LIBRARYJARS_OPTION, configuration.libraryJars); writer.println(); // Write the other options. writeOption( ConfigurationConstants.SKIP_NON_PUBLIC_LIBRARY_CLASSES_OPTION, configuration.skipNonPublicLibraryClasses); writeOption( ConfigurationConstants.DONT_SKIP_NON_PUBLIC_LIBRARY_CLASS_MEMBERS_OPTION, !configuration.skipNonPublicLibraryClassMembers); writeOption(ConfigurationConstants.KEEP_DIRECTORIES_OPTION, configuration.keepDirectories); writeOption( ConfigurationConstants.TARGET_OPTION, ClassUtil.externalClassVersion(configuration.targetClassVersion)); writeOption( ConfigurationConstants.FORCE_PROCESSING_OPTION, configuration.lastModified == Long.MAX_VALUE); writeOption(ConfigurationConstants.DONT_SHRINK_OPTION, !configuration.shrink); writeOption(ConfigurationConstants.PRINT_USAGE_OPTION, configuration.printUsage); writeOption(ConfigurationConstants.DONT_OPTIMIZE_OPTION, !configuration.optimize); writeOption(ConfigurationConstants.OPTIMIZATIONS, configuration.optimizations); writeOption(ConfigurationConstants.OPTIMIZATION_PASSES, configuration.optimizationPasses); writeOption( ConfigurationConstants.ALLOW_ACCESS_MODIFICATION_OPTION, configuration.allowAccessModification); writeOption( ConfigurationConstants.MERGE_INTERFACES_AGGRESSIVELY_OPTION, configuration.mergeInterfacesAggressively); writeOption(ConfigurationConstants.DONT_OBFUSCATE_OPTION, !configuration.obfuscate); writeOption(ConfigurationConstants.PRINT_MAPPING_OPTION, configuration.printMapping); writeOption(ConfigurationConstants.APPLY_MAPPING_OPTION, configuration.applyMapping); writeOption( ConfigurationConstants.OBFUSCATION_DICTIONARY_OPTION, configuration.obfuscationDictionary); writeOption( ConfigurationConstants.CLASS_OBFUSCATION_DICTIONARY_OPTION, configuration.classObfuscationDictionary); writeOption( ConfigurationConstants.PACKAGE_OBFUSCATION_DICTIONARY_OPTION, configuration.packageObfuscationDictionary); writeOption( ConfigurationConstants.OVERLOAD_AGGRESSIVELY_OPTION, configuration.overloadAggressively); writeOption( ConfigurationConstants.USE_UNIQUE_CLASS_MEMBER_NAMES_OPTION, configuration.useUniqueClassMemberNames); writeOption( ConfigurationConstants.DONT_USE_MIXED_CASE_CLASS_NAMES_OPTION, !configuration.useMixedCaseClassNames); writeOption( ConfigurationConstants.KEEP_PACKAGE_NAMES_OPTION, configuration.keepPackageNames, true); writeOption( ConfigurationConstants.FLATTEN_PACKAGE_HIERARCHY_OPTION, configuration.flattenPackageHierarchy, true); writeOption( ConfigurationConstants.REPACKAGE_CLASSES_OPTION, configuration.repackageClasses, true); writeOption(ConfigurationConstants.KEEP_ATTRIBUTES_OPTION, configuration.keepAttributes); writeOption( ConfigurationConstants.KEEP_PARAMETER_NAMES_OPTION, configuration.keepParameterNames); writeOption( ConfigurationConstants.RENAME_SOURCE_FILE_ATTRIBUTE_OPTION, configuration.newSourceFileAttribute); writeOption( ConfigurationConstants.ADAPT_CLASS_STRINGS_OPTION, configuration.adaptClassStrings, true); writeOption( ConfigurationConstants.ADAPT_RESOURCE_FILE_NAMES_OPTION, configuration.adaptResourceFileNames); writeOption( ConfigurationConstants.ADAPT_RESOURCE_FILE_CONTENTS_OPTION, configuration.adaptResourceFileContents); writeOption(ConfigurationConstants.DONT_PREVERIFY_OPTION, !configuration.preverify); writeOption(ConfigurationConstants.MICRO_EDITION_OPTION, configuration.microEdition); writeOption(ConfigurationConstants.VERBOSE_OPTION, configuration.verbose); writeOption(ConfigurationConstants.DONT_NOTE_OPTION, configuration.note, true); writeOption(ConfigurationConstants.DONT_WARN_OPTION, configuration.warn, true); writeOption(ConfigurationConstants.IGNORE_WARNINGS_OPTION, configuration.ignoreWarnings); writeOption( ConfigurationConstants.PRINT_CONFIGURATION_OPTION, configuration.printConfiguration); writeOption(ConfigurationConstants.DUMP_OPTION, configuration.dump); writeOption(ConfigurationConstants.PRINT_SEEDS_OPTION, configuration.printSeeds); writer.println(); // Write the "why are you keeping" options. writeOptions(ConfigurationConstants.WHY_ARE_YOU_KEEPING_OPTION, configuration.whyAreYouKeeping); // Write the keep options. writeOptions(KEEP_OPTIONS, configuration.keep); // Write the "no side effect methods" options. writeOptions( ConfigurationConstants.ASSUME_NO_SIDE_EFFECTS_OPTION, configuration.assumeNoSideEffects); if (writer.checkError()) { throw new IOException("Can't write configuration"); } }
/** Returns the generalization of this ReferenceValue and the given other ReferenceValue. */ public ReferenceValue generalize(ReferenceValue other) { // If both types are identical, the generalization is the same too. if (this.equals(other)) { return this; } String thisType = this.type; String otherType = other.type; // If both types are nul, the generalization is null too. if (thisType == null && otherType == null) { return ValueFactory.REFERENCE_VALUE_NULL; } // If this type is null, the generalization is the other type, maybe null. if (thisType == null) { return other.generalizeMayBeNull(true); } // If the other type is null, the generalization is this type, maybe null. if (otherType == null) { return this.generalizeMayBeNull(true); } boolean mayBeNull = this.mayBeNull || other.mayBeNull; // If the two types are equal, the generalization remains the same, maybe null. if (thisType.equals(otherType)) { return this.generalizeMayBeNull(mayBeNull); } // Start taking into account the type dimensions. int thisDimensionCount = ClassUtil.internalArrayTypeDimensionCount(thisType); int otherDimensionCount = ClassUtil.internalArrayTypeDimensionCount(otherType); int commonDimensionCount = Math.min(thisDimensionCount, otherDimensionCount); if (thisDimensionCount == otherDimensionCount) { // See if we can take into account the referenced classes. Clazz thisReferencedClass = this.referencedClass; Clazz otherReferencedClass = other.referencedClass; if (thisReferencedClass != null && otherReferencedClass != null) { if (thisReferencedClass.extendsOrImplements(otherReferencedClass)) { return other.generalizeMayBeNull(mayBeNull); } if (otherReferencedClass.extendsOrImplements(thisReferencedClass)) { return this.generalizeMayBeNull(mayBeNull); } // Collect the superclasses and interfaces of this class. Set thisSuperClasses = new HashSet(); thisReferencedClass.hierarchyAccept( false, true, true, false, new ClassCollector(thisSuperClasses)); int thisSuperClassesCount = thisSuperClasses.size(); if (thisSuperClassesCount == 0 && thisReferencedClass.getSuperName() != null) { throw new IllegalArgumentException( "Can't find any super classes of [" + thisType + "] (not even immediate super class [" + thisReferencedClass.getSuperName() + "])"); } // Collect the superclasses and interfaces of the other class. Set otherSuperClasses = new HashSet(); otherReferencedClass.hierarchyAccept( false, true, true, false, new ClassCollector(otherSuperClasses)); int otherSuperClassesCount = otherSuperClasses.size(); if (otherSuperClassesCount == 0 && otherReferencedClass.getSuperName() != null) { throw new IllegalArgumentException( "Can't find any super classes of [" + otherType + "] (not even immediate super class [" + otherReferencedClass.getSuperName() + "])"); } if (DEBUG) { System.out.println( "ReferenceValue.generalize this [" + thisReferencedClass.getName() + "] with other [" + otherReferencedClass.getName() + "]"); System.out.println(" This super classes: " + thisSuperClasses); System.out.println(" Other super classes: " + otherSuperClasses); } // Find the common superclasses. thisSuperClasses.retainAll(otherSuperClasses); if (DEBUG) { System.out.println(" Common super classes: " + thisSuperClasses); } // Find a class that is a subclass of all common superclasses, // or that at least has the maximum number of common superclasses. Clazz commonClass = null; int maximumSuperClassCount = -1; // Go over all common superclasses to find it. In case of // multiple subclasses, keep the lowest one alphabetically, // in order to ensure that the choice is deterministic. Iterator commonSuperClasses = thisSuperClasses.iterator(); while (commonSuperClasses.hasNext()) { Clazz commonSuperClass = (Clazz) commonSuperClasses.next(); int superClassCount = superClassCount(commonSuperClass, thisSuperClasses); if (maximumSuperClassCount < superClassCount || (maximumSuperClassCount == superClassCount && commonClass != null && commonClass.getName().compareTo(commonSuperClass.getName()) > 0)) { commonClass = commonSuperClass; maximumSuperClassCount = superClassCount; } } if (commonClass == null) { throw new IllegalArgumentException( "Can't find common super class of [" + thisType + "] (with " + thisSuperClassesCount + " known super classes) and [" + otherType + "] (with " + otherSuperClassesCount + " known super classes)"); } if (DEBUG) { System.out.println(" Best common class: [" + commonClass.getName() + "]"); } // TODO: Handle more difficult cases, with multiple global subclasses. return new ReferenceValue( commonDimensionCount == 0 ? commonClass.getName() : ClassUtil.internalArrayTypeFromClassName( commonClass.getName(), commonDimensionCount), commonClass, mayBeNull); } } else if (thisDimensionCount > otherDimensionCount) { // See if the other type is an interface type of arrays. if (ClassUtil.isInternalArrayInterfaceName( ClassUtil.internalClassNameFromClassType(otherType))) { return other.generalizeMayBeNull(mayBeNull); } } else if (thisDimensionCount < otherDimensionCount) { // See if this type is an interface type of arrays. if (ClassUtil.isInternalArrayInterfaceName( ClassUtil.internalClassNameFromClassType(thisType))) { return this.generalizeMayBeNull(mayBeNull); } } // Reduce the common dimension count if either type is an array of // primitives type of this dimension. if (commonDimensionCount > 0 && (ClassUtil.isInternalPrimitiveType(otherType.charAt(commonDimensionCount))) || ClassUtil.isInternalPrimitiveType(thisType.charAt(commonDimensionCount))) { commonDimensionCount--; } // Fall back on a basic Object or array of Objects type. return commonDimensionCount == 0 ? mayBeNull ? ValueFactory.REFERENCE_VALUE_JAVA_LANG_OBJECT_MAYBE_NULL : ValueFactory.REFERENCE_VALUE_JAVA_LANG_OBJECT_NOT_NULL : new ReferenceValue( ClassUtil.internalArrayTypeFromClassName( ClassConstants.INTERNAL_NAME_JAVA_LANG_OBJECT, commonDimensionCount), null, mayBeNull); }