📄 methodinliner.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.optimize.peephole;import proguard.classfile.util.*;import proguard.classfile.attribute.visitor.*;import proguard.classfile.attribute.*;import proguard.classfile.instruction.visitor.InstructionVisitor;import proguard.classfile.instruction.*;import proguard.classfile.editor.*;import proguard.classfile.*;import proguard.classfile.visitor.*;import proguard.classfile.constant.visitor.ConstantVisitor;import proguard.classfile.constant.*;import proguard.optimize.info.*;/** * This AttributeVisitor inlines short methods in the code attributes that it * visits. * * @author Eric Lafortune */public class MethodInlinerextends SimplifiedVisitorimplements AttributeVisitor, InstructionVisitor, ExceptionInfoVisitor, ConstantVisitor, MemberVisitor{ private static final int MAXIMUM_INLINING_CODE_LENGTH = 8; private static final int MAXIMUM_CODE_EXPANSION = 2; private static final int MAXIMUM_EXTRA_CODE_LENGTH = 128; //* private static final boolean DEBUG = false; /*/ private static boolean DEBUG = true; //*/ private boolean allowAccessModification; private InstructionVisitor extraInlinedInvocationVisitor; private CodeAttributeComposer codeAttributeComposer = new CodeAttributeComposer(); private AccessMethodMarker accessMethodMarker = new AccessMethodMarker(); private CatchExceptionMarker catchExceptionMarker = new CatchExceptionMarker(); private ConstantAdder constantAdder = new ConstantAdder(); private StackSizeComputer stackSizeComputer = new StackSizeComputer(); private Clazz targetClass; private Method targetMethod; private boolean inlining; private boolean emptyInvokingStack; private int uninitializedObjectCount; private int variableOffset; private boolean inlined; private boolean inlinedAny; /** * Creates a new MethodInliner. * @param allowAccessModification indicates whether the access modifiers of * classes and class members can be changed * in order to inline methods. */ public MethodInliner(boolean allowAccessModification) { this(allowAccessModification, null); } /** * Creates a new MethodInliner. * @param allowAccessModification indicates whether the access modifiers of * classes and class members can be changed * in order to inline methods. * @param extraInlinedInvocationVisitor an optional extra visitor for all * inlined invocation instructions. */ public MethodInliner(boolean allowAccessModification, InstructionVisitor extraInlinedInvocationVisitor) { this.allowAccessModification = allowAccessModification; this.extraInlinedInvocationVisitor = extraInlinedInvocationVisitor; } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { if (!inlining) {// codeAttributeComposer.DEBUG = DEBUG =// clazz.getName().equals("abc/Def") &&// method.getName(clazz).equals("abc"); targetClass = clazz; targetMethod = method; uninitializedObjectCount = method.getName(clazz).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT) ? 1 : 0; inlinedAny = false; codeAttributeComposer.reset(); constantAdder.setTargetClass((ProgramClass)clazz); stackSizeComputer.visitCodeAttribute(clazz, method, codeAttribute); // Append the body of the code. copyCode(clazz, method, codeAttribute); targetClass = null; targetMethod = null; constantAdder.setTargetClass(null); // Update the code attribute if any code has been inlined. if (inlinedAny) { codeAttributeComposer.visitCodeAttribute(clazz, method, codeAttribute); // Update the accessing flags. codeAttribute.instructionsAccept(clazz, method, accessMethodMarker); // Update the exception catching flags. catchExceptionMarker.visitCodeAttribute(clazz, method, codeAttribute); } } // Only inline the method if it is invoked once or if it is short. // TODO: Check total code length after inlining. else if (MethodInvocationMarker.getInvocationCount(method) == 1 || codeAttribute.u4codeLength <= MAXIMUM_INLINING_CODE_LENGTH) { if (DEBUG) { System.out.println("MethodInliner: inlining ["+ clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"] in ["+ targetClass.getName()+"."+targetMethod.getName(targetClass)+targetMethod.getDescriptor(targetClass)+"]"); } // Append instructions to store the parameters. storeParameters(clazz, method); // Inline the body of the code. copyCode(clazz, method, codeAttribute); inlined = true; inlinedAny = true; } } /** * Appends instructions to pop the parameters for the given method, storing * them in new local variables. */ private void storeParameters(Clazz clazz, Method method) { String descriptor = method.getDescriptor(clazz); boolean isStatic = (method.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) != 0; // Count the number of parameters, taking into account their categories. int parameterCount = ClassUtil.internalMethodParameterCount(descriptor); int parameterSize = ClassUtil.internalMethodParameterSize(descriptor); int parameterOffset = isStatic ? 0 : 1; // Store the parameter types. String[] parameterTypes = new String[parameterSize]; InternalTypeEnumeration internalTypeEnumeration = new InternalTypeEnumeration(descriptor); for (int parameterIndex = 0; parameterIndex < parameterSize; parameterIndex++) { String parameterType = internalTypeEnumeration.nextType(); parameterTypes[parameterIndex] = parameterType; if (ClassUtil.internalTypeSize(parameterType) == 2) { parameterIndex++; } } codeAttributeComposer.beginCodeFragment((parameterOffset + parameterCount) * 4); // Go over the parameter types backward, storing the stack entries // in their corresponding variables. for (int parameterIndex = parameterSize-1; parameterIndex >= 0; parameterIndex--) { String parameterType = parameterTypes[parameterIndex]; if (parameterType != null) { byte opcode; switch (parameterType.charAt(0)) { case ClassConstants.INTERNAL_TYPE_BOOLEAN: case ClassConstants.INTERNAL_TYPE_BYTE: case ClassConstants.INTERNAL_TYPE_CHAR: case ClassConstants.INTERNAL_TYPE_SHORT: case ClassConstants.INTERNAL_TYPE_INT: opcode = InstructionConstants.OP_ISTORE; break; case ClassConstants.INTERNAL_TYPE_LONG: opcode = InstructionConstants.OP_LSTORE; break; case ClassConstants.INTERNAL_TYPE_FLOAT: opcode = InstructionConstants.OP_FSTORE; break; case ClassConstants.INTERNAL_TYPE_DOUBLE: opcode = InstructionConstants.OP_DSTORE; break; default: opcode = InstructionConstants.OP_ASTORE; break; } codeAttributeComposer.appendInstruction(parameterSize-parameterIndex-1, new VariableInstruction(opcode, variableOffset + parameterOffset + parameterIndex).shrink()); } } // Put the 'this' reference in variable 0 (plus offset). if (!isStatic) { codeAttributeComposer.appendInstruction(parameterSize, new VariableInstruction(InstructionConstants.OP_ASTORE, variableOffset).shrink()); } codeAttributeComposer.endCodeFragment(); } /** * Appends the code of the given code attribute. */ private void copyCode(Clazz clazz, Method method, CodeAttribute codeAttribute) { // The code may expand, due to expanding constant and variable // instructions. codeAttributeComposer.beginCodeFragment(codeAttribute.u4codeLength * MAXIMUM_CODE_EXPANSION + MAXIMUM_EXTRA_CODE_LENGTH);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -