public void visitLibraryClass(LibraryClass libraryClass) { if (shouldBeMarkedAsUsed(libraryClass)) { markAsUsed(libraryClass); // We're not going to analyze all library code. We're assuming that // if this class is being used, all of its methods will be used as // well. We'll mark them as such (here and in all subclasses). // Mark the superclass. Clazz superClass = libraryClass.superClass; if (superClass != null) { superClass.accept(this); } // Mark the interfaces. Clazz[] interfaceClasses = libraryClass.interfaceClasses; if (interfaceClasses != null) { for (int index = 0; index < interfaceClasses.length; index++) { if (interfaceClasses[index] != null) { interfaceClasses[index].accept(this); } } } // Mark all methods. libraryClass.methodsAccept(this); } }
/** * Lets the given class visitor visit all known direct interfaces. * * @param classVisitor the <code>ClassVisitor</code> that will visit the interfaces. */ public void interfacesAccept(ClassVisitor classVisitor) { if (interfaceClasses != null) { for (int index = 0; index < interfaceClasses.length; index++) { Clazz interfaceClass = interfaceClasses[index]; if (interfaceClass != null) { interfaceClass.accept(classVisitor); } } } }
public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo) { // At this point, we only mark outer classes of this class. // Inner class can be marked later, by InnerUsageMarker. if (innerClassesInfo.u2innerClassIndex != 0 && clazz.getName().equals(clazz.getClassName(innerClassesInfo.u2innerClassIndex))) { markAsUsed(innerClassesInfo); innerClassesInfo.innerClassConstantAccept(clazz, this); innerClassesInfo.outerClassConstantAccept(clazz, this); innerClassesInfo.innerNameConstantAccept(clazz, this); } }
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); } }
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 boolean extends_(Clazz clazz) { if (this.equals(clazz)) { return true; } return superClass != null && superClass.extends_(clazz); }
public boolean extends_(String className) { if (getName().equals(className)) { return true; } return superClass != null && superClass.extends_(className); }
/** * 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))))); } }
/** * 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 hierarchyAccept( boolean visitThisClass, boolean visitSuperClass, boolean visitInterfaces, boolean visitSubclasses, ClassVisitor classVisitor) { // First visit the current classfile. if (visitThisClass) { accept(classVisitor); } // Then visit its superclass, recursively. if (visitSuperClass) { if (superClass != null) { superClass.hierarchyAccept(true, true, visitInterfaces, false, classVisitor); } } // Then visit its interfaces, recursively. if (visitInterfaces) { // Visit the interfaces of the superclasses, if we haven't done so yet. if (!visitSuperClass) { if (superClass != null) { superClass.hierarchyAccept(false, false, true, false, classVisitor); } } // Visit the interfaces. if (interfaceClasses != null) { for (int index = 0; index < interfaceClasses.length; index++) { Clazz interfaceClass = interfaceClasses[index]; if (interfaceClass != null) { interfaceClass.hierarchyAccept(true, false, true, false, classVisitor); } } } } // Then visit its subclasses, recursively. if (visitSubclasses) { if (subClasses != null) { for (int index = 0; index < subClasses.length; index++) { subClasses[index].hierarchyAccept(true, false, false, true, classVisitor); } } } }
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; } }
public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant) { if (shouldBeMarkedAsUsed(invokeDynamicConstant)) { markAsUsed(invokeDynamicConstant); markConstant(clazz, invokeDynamicConstant.u2nameAndTypeIndex); // Mark the bootstrap methods attribute. clazz.attributesAccept( new MyBootStrapMethodUsageMarker(invokeDynamicConstant.u2bootstrapMethodAttributeIndex)); } }
public boolean extendsOrImplements(String className) { if (getName().equals(className)) { return true; } if (superClass != null && superClass.extendsOrImplements(className)) { return true; } if (interfaceClasses != null) { for (int index = 0; index < interfaceClasses.length; index++) { Clazz interfaceClass = interfaceClasses[index]; if (interfaceClass != null && interfaceClass.extendsOrImplements(className)) { return true; } } } return false; }
public void visitConstantInstruction( Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { markConstant(clazz, constantInstruction.constantIndex); // Also mark the parameterless constructor of the class, in case the // string constant or class constant is being used in a Class.forName // or a .class construct. clazz.constantPoolEntryAccept( constantInstruction.constantIndex, parameterlessConstructorMarker); }
public void visitSignatureAttribute( Clazz clazz, Method method, SignatureAttribute signatureAttribute) { // Compute the new signature. String signature = clazz.getString(signatureAttribute.u2signatureIndex); String newSignature = shrinkDescriptor(method, signature); // Update the signature. signatureAttribute.u2signatureIndex = new ConstantPoolEditor((ProgramClass) clazz).addUtf8Constant(newSignature); // Update the referenced classes. signatureAttribute.referencedClasses = shrinkReferencedClasses(method, signature, signatureAttribute.referencedClasses); }
/** * Lets the given class visitor visit the superclass, if it is known. * * @param classVisitor the <code>ClassVisitor</code> that will visit the superclass. */ public void superClassAccept(ClassVisitor classVisitor) { if (superClass != null) { superClass.accept(classVisitor); } }
/** * Marks the given constant pool entry of the given class. This includes visiting any referenced * objects. */ private void markConstant(Clazz clazz, int index) { clazz.constantPoolEntryAccept(index, this); }
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); } }