📄 codepreverifier.java
字号:
/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu) * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */package proguard.preverify;import proguard.classfile.*;import proguard.classfile.attribute.*;import proguard.classfile.attribute.preverification.*;import proguard.classfile.attribute.visitor.AttributeVisitor;import proguard.classfile.editor.*;import proguard.classfile.instruction.InstructionConstants;import proguard.classfile.util.SimplifiedVisitor;import proguard.classfile.visitor.*;import proguard.evaluation.*;import proguard.evaluation.value.*;import proguard.optimize.evaluation.*;import java.util.*;/** * This class can preverify methods in program class pools, according to a given * specification. * * @author Eric Lafortune */public class CodePreverifierextends SimplifiedVisitorimplements MemberVisitor, AttributeVisitor{ //* private static final boolean DEBUG = false; /*/ private static boolean DEBUG = true; //*/ private final boolean microEdition; private final PartialEvaluator partialEvaluator = new PartialEvaluator(); private final LivenessAnalyzer livenessAnalyzer = new LivenessAnalyzer(partialEvaluator); private final ConstantPoolEditor constantPoolEditor = new ConstantPoolEditor(); private final AttributesEditor attributesEditor = new AttributesEditor(); /** * Creates a new CodePreverifier. */ public CodePreverifier(boolean microEdition) { this.microEdition = microEdition; } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // TODO: Remove this when the preverifier has stabilized. // Catch any unexpected exceptions from the actual visiting method. try { // Process the code. visitCodeAttribute0(clazz, method, codeAttribute); } catch (RuntimeException ex) { System.err.println("Unexpected error while preverifying:"); System.err.println(" Class = ["+clazz.getName()+"]"); System.err.println(" Method = ["+method.getName(clazz)+method.getDescriptor(clazz)+"]"); System.err.println(" Exception = ["+ex.getClass().getName()+"] ("+ex.getMessage()+")"); throw ex; } } public void visitCodeAttribute0(Clazz clazz, Method method, CodeAttribute codeAttribute) {// DEBUG =// clazz.getName().equals("abc/Def") &&// method.getName(clazz).equals("abc"); ProgramClass programClass = (ProgramClass)clazz; ProgramMethod programMethod = (ProgramMethod)method; // Evaluate the method. //partialEvaluator.visitCodeAttribute(clazz, method, codeAttribute); livenessAnalyzer.visitCodeAttribute(clazz, method, codeAttribute); // Collect the stack map frames. List stackMapFrameList = new ArrayList(); for (int offset = 0; offset < codeAttribute.u4codeLength; offset++) { // Only store frames at the beginning of code blocks. if (partialEvaluator.isTraced(offset) && partialEvaluator.isBranchOrExceptionTarget(offset)) { // Convert the variable values to types. VerificationType[] variableTypes = correspondingVerificationTypes(programClass, programMethod, codeAttribute, offset, partialEvaluator.getVariablesBefore(offset)); // Convert the stack values to types. VerificationType[] stackTypes = correspondingVerificationTypes(programClass, programMethod, codeAttribute, offset, partialEvaluator.getStackBefore(offset)); // Create and store a new frame. stackMapFrameList.add(new FullFrame(offset, variableTypes, stackTypes)); } } // Compress the stack map frames if the target is not Java Micro Edition. if (!microEdition && !stackMapFrameList.isEmpty()) { // Convert the initial variable values to types. VerificationType[] initialVariables = correspondingVerificationTypes(programClass, programMethod, codeAttribute, PartialEvaluator.AT_METHOD_ENTRY, partialEvaluator.getVariablesBefore(0)); // Special case: the <init> method. if (method.getName(programClass).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT)) { initialVariables[0] = VerificationTypeFactory.createUninitializedThisType(); } compressStackMapFrames(initialVariables, stackMapFrameList); } // Get the proper name for the attribute to be added/replaced/deleted. String stackMapAttributeName = microEdition ? ClassConstants.ATTR_StackMap : ClassConstants.ATTR_StackMapTable; int frameCount = stackMapFrameList.size(); if (DEBUG) { Attribute originalStackMapAttribute = codeAttribute.getAttribute(clazz, stackMapAttributeName); if (originalStackMapAttribute != null) { int originalFrameCount = microEdition ? ((StackMapAttribute)originalStackMapAttribute).u2stackMapFramesCount : ((StackMapTableAttribute)originalStackMapAttribute).u2stackMapFramesCount; StackMapFrame[] originalFrames = microEdition ? ((StackMapAttribute)originalStackMapAttribute).stackMapFrames : ((StackMapTableAttribute)originalStackMapAttribute).stackMapFrames; if (frameCount != originalFrameCount || !Arrays.equals(stackMapFrameList.toArray(), originalFrames)) { System.out.println("Original preverification ["+clazz.getName()+"]:"); new ClassPrinter().visitProgramMethod(programClass, programMethod); } } else if (frameCount != 0) { System.out.println("Original preverification empty ["+clazz.getName()+"."+method.getName(clazz)+"]"); } } if (frameCount == 0) { // Remove any stack map (table) attribute from the code attribute. attributesEditor.deleteAttribute(programClass, programMethod, codeAttribute, stackMapAttributeName); } else { Attribute stackMapAttribute; // Create the appropriate attribute. if (microEdition) { // Copy the frames into an array. FullFrame[] stackMapFrames = new FullFrame[frameCount]; stackMapFrameList.toArray(stackMapFrames); // Put the frames into a stack map attribute. stackMapAttribute = new StackMapAttribute(stackMapFrames); } else { // Copy the frames into an array. StackMapFrame[] stackMapFrames = new StackMapFrame[frameCount]; stackMapFrameList.toArray(stackMapFrames); // Put the frames into a stack map table attribute. stackMapAttribute = new StackMapTableAttribute(stackMapFrames); } // Fill out the name of the stack map attribute. stackMapAttribute.u2attributeNameIndex = constantPoolEditor.addUtf8Constant(programClass, stackMapAttributeName); // Add the new stack map (table) attribute to the code attribute. attributesEditor.addAttribute(programClass, programMethod, codeAttribute, stackMapAttribute); if (DEBUG) { System.out.println("Preverifier ["+programClass.getName()+"."+programMethod.getName(programClass)+"]:"); stackMapAttribute.accept(programClass, programMethod, codeAttribute, new ClassPrinter()); } } } // Small utility methods. /** * Creates and returns the verification types corresponding to the given * variables. If necessary, class constants are added to the constant pool * of the given class. */ private VerificationType[] correspondingVerificationTypes(ProgramClass programClass, ProgramMethod programMethod, CodeAttribute codeAttribute, int offset, TracedVariables variables) { int maximumVariablesSize = variables.size(); int typeCount = 0; int typeIndex = 0; // Count the the number of verification types, ignoring any nulls at // the end. for (int index = 0; index < maximumVariablesSize; index++) { Value value = variables.getValue(index); typeIndex++; // Remember the maximum live type index. if (value != null && (offset == PartialEvaluator.AT_METHOD_ENTRY || livenessAnalyzer.isAliveBefore(offset, index))) { typeCount = typeIndex; // Category 2 types that are alive are stored as single entries. if (value.isCategory2()) { index++; } } } // Create and fill out the verification types. VerificationType[] types = new VerificationType[typeCount]; typeIndex = 0; // Note the slightly different terminating condition, because the // types may have been truncated. for (int index = 0; typeIndex < typeCount; index++) { Value value = variables.getValue(index); Value producerValue = variables.getProducerValue(index); // Fill out the type. VerificationType type;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -