📄 valuenumberframemodelingvisitor.java
字号:
/* * Bytecode Analysis Framework * Copyright (C) 2003,2004 University of Maryland * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 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 edu.umd.cs.findbugs.ba;import java.util.*;import org.apache.bcel.Constants;import org.apache.bcel.generic.*;/** * Visitor which models the effects of bytecode instructions * on value numbers of values in the operand stack frames. * * @see ValueNumber * @see ValueNumberFrame * @see ValueNumberAnalysis * @author David Hovemeyer */public class ValueNumberFrameModelingVisitor extends AbstractFrameModelingVisitor<ValueNumber, ValueNumberFrame> implements Debug, ValueNumberAnalysisFeatures { /* ---------------------------------------------------------------------- * Fields * ---------------------------------------------------------------------- */ private MethodGen methodGen; private ValueNumberFactory factory; private ValueNumberCache cache; private LoadedFieldSet loadedFieldSet; private HashMap<String, ValueNumber> classObjectValueMap; private IdentityHashMap<InstructionHandle, ValueNumber> constantValueMap; private HashMap<ValueNumber, String> stringConstantMap; private RepositoryLookupFailureCallback lookupFailureCallback; private InstructionHandle handle; /* ---------------------------------------------------------------------- * Public interface * ---------------------------------------------------------------------- */ /** * Constructor. * * @param methodGen the method being analyzed * @param factory factory for ValueNumbers for the method * @param cache cache of input/output transformations for each instruction * @param loadedFieldSet fields loaded/stored by each instruction and entire method * @param lookupFailureCallback callback to use to report class lookup failures */ public ValueNumberFrameModelingVisitor(MethodGen methodGen, ValueNumberFactory factory, ValueNumberCache cache, LoadedFieldSet loadedFieldSet, RepositoryLookupFailureCallback lookupFailureCallback) { super(methodGen.getConstantPool()); this.methodGen = methodGen; this.factory = factory; this.cache = cache; this.loadedFieldSet = loadedFieldSet; this.classObjectValueMap = new HashMap<String, ValueNumber>(); this.constantValueMap = new IdentityHashMap<InstructionHandle, ValueNumber>(); this.stringConstantMap = new HashMap<ValueNumber, String>(); this.lookupFailureCallback = lookupFailureCallback; } public ValueNumber getDefaultValue() { return factory.createFreshValue(); } /** * Set the instruction handle of the instruction currently being visited. * This must be called before the instruction accepts this visitor! */ public void setHandle(InstructionHandle handle) { this.handle = handle; } /* ---------------------------------------------------------------------- * Instruction modeling * ---------------------------------------------------------------------- */ /** * Determine whether redundant load elimination * should be performed for the heap location referenced by * the current instruction. * * @return true if we should do redundant load elimination * for the current instruction, false if not */ private boolean doRedundantLoadElimination() { if (!REDUNDANT_LOAD_ELIMINATION) return false; XField xfield = loadedFieldSet.getField(handle); if (xfield == null) return false; if (!xfield.isReferenceType()) return false; // Don't do redundant load elimination for fields that // are loaded in only one place. if (loadedFieldSet.getLoadStoreCount(xfield).getLoadCount() <= 1) return false; return true; } /** * Determine whether forward substitution * should be performed for the heap location referenced by * the current instruction. * * @return true if we should do forward substitution * for the current instruction, false if not */ private boolean doForwardSubstitution() { if (!REDUNDANT_LOAD_ELIMINATION) return false; XField xfield = loadedFieldSet.getField(handle); if (xfield == null) return false; if (!xfield.isReferenceType()) return false; // Don't do forward substitution for fields that // are never read. if (!loadedFieldSet.isLoaded(xfield)) return false; return true; } private void checkConsumedAndProducedValues(Instruction ins, ValueNumber[] consumedValueList, ValueNumber[] producedValueList) { int numConsumed = ins.consumeStack(getCPG()); int numProduced = ins.produceStack(getCPG()); if (numConsumed == Constants.UNPREDICTABLE) throw new IllegalStateException("Unpredictable stack consumption for " + ins); if (numProduced == Constants.UNPREDICTABLE) throw new IllegalStateException("Unpredictable stack production for " + ins); if (consumedValueList.length != numConsumed) { throw new IllegalStateException("Wrong number of values consumed for " + ins + ": expected " + numConsumed + ", got " + consumedValueList.length); } if (producedValueList.length != numProduced) { throw new IllegalStateException("Wrong number of values produced for " + ins + ": expected " + numProduced + ", got " + producedValueList.length); } } /** * This is the default instruction modeling method. */ public void modelNormalInstruction(Instruction ins, int numWordsConsumed, int numWordsProduced) { int flags = (ins instanceof InvokeInstruction) ? ValueNumber.RETURN_VALUE : 0; // Get the input operands to this instruction. ValueNumber[] inputValueList = popInputValues(numWordsConsumed); // See if we have the output operands in the cache. // If not, push default (fresh) values for the output, // and add them to the cache. ValueNumber[] outputValueList = getOutputValues(inputValueList, numWordsProduced, flags); if (VERIFY_INTEGRITY) { checkConsumedAndProducedValues(ins, inputValueList, outputValueList); } // Push output operands on stack. pushOutputValues(outputValueList); } public void visitGETFIELD(GETFIELD obj) { if (doRedundantLoadElimination()) { try { XField xfield = Hierarchy.findXField(obj, getCPG()); if (xfield != null) { loadInstanceField((InstanceField) xfield, obj); return; } } catch (ClassNotFoundException e) { lookupFailureCallback.reportMissingClass(e); } } handleNormalInstruction(obj); } public void visitPUTFIELD(PUTFIELD obj) { if (doForwardSubstitution()) { try { XField xfield = Hierarchy.findXField(obj, getCPG()); if (xfield != null) { storeInstanceField((InstanceField) xfield, obj, false); return; } } catch (ClassNotFoundException e) { lookupFailureCallback.reportMissingClass(e); } } handleNormalInstruction(obj); } private static final ValueNumber[] EMPTY_INPUT_VALUE_LIST = new ValueNumber[0]; public void visitGETSTATIC(GETSTATIC obj) { if (doRedundantLoadElimination()) { ValueNumberFrame frame = getFrame(); ConstantPoolGen cpg = getCPG(); String fieldName = obj.getName(cpg); String fieldSig = obj.getSignature(cpg); // Is this an access of a Class object? if (fieldName.startsWith("class$") && fieldSig.equals("Ljava/lang/Class;")) { String className = fieldName.substring("class$".length()).replace('$', '.'); if (RLE_DEBUG) System.out.println("[found load of class object " + className + "]"); ValueNumber value = getClassObjectValue(className); frame.pushValue(value); return; } try { XField xfield = Hierarchy.findXField(obj, getCPG()); if (xfield != null) { loadStaticField((StaticField) xfield, obj); return; } } catch (ClassNotFoundException e) { lookupFailureCallback.reportMissingClass(e); } } handleNormalInstruction(obj); } public void visitPUTSTATIC(PUTSTATIC obj) { if (doForwardSubstitution()) { try { XField xfield = Hierarchy.findXField(obj, getCPG()); if (xfield != null) { storeStaticField((StaticField) xfield, obj, false); return; } } catch (ClassNotFoundException e) { lookupFailureCallback.reportMissingClass(e); } } handleNormalInstruction(obj); } public void visitINVOKESTATIC(INVOKESTATIC obj) { if (REDUNDANT_LOAD_ELIMINATION) { ConstantPoolGen cpg = getCPG(); String methodName = obj.getName(cpg); String methodSig = obj.getSignature(cpg); if (methodName.equals("class$") && methodSig.equals("(Ljava/lang/String;)Ljava/lang/Class;")) { // Access of a Class object ValueNumberFrame frame = getFrame(); try { ValueNumber arg = frame.getTopValue(); String className = stringConstantMap.get(arg); if (className != null) { frame.popValue(); if (RLE_DEBUG) System.out.println("[found access of class object " + className + "]"); frame.pushValue(getClassObjectValue(className)); return; } } catch (DataflowAnalysisException e) { throw new AnalysisException("stack underflow", methodGen, handle, e); } } else if (Hierarchy.isInnerClassAccess(obj, cpg)) { // Possible access of field via an inner-class access method XField xfield = loadedFieldSet.getField(handle); if (xfield != null) { if (loadedFieldSet.instructionIsLoad(handle)) { // Load via inner-class accessor if (doRedundantLoadElimination()) { if (xfield.isStatic()) loadStaticField((StaticField) xfield, obj); else loadInstanceField((InstanceField) xfield, obj); return; } } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -