001: /*
002: * Bytecode Analysis Framework
003: * Copyright (C) 2003,2004 University of Maryland
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation; either
008: * version 2.1 of the License, or (at your option) any later version.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public
016: * License along with this library; if not, write to the Free Software
017: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018: */
019:
020: package edu.umd.cs.findbugs.ba;
021:
022: import org.apache.bcel.Constants;
023: import org.apache.bcel.classfile.Method;
024: import org.apache.bcel.generic.ConstantPoolGen;
025: import org.apache.bcel.generic.Instruction;
026: import org.apache.bcel.generic.InstructionHandle;
027:
028: /**
029: * A really simple forward dataflow analysis to find the depth of
030: * the Java operand stack. This is more of a proof of concept for
031: * the dataflow analysis framework than anything useful.
032: *
033: * @see Dataflow
034: * @see DataflowAnalysis
035: */
036: public class StackDepthAnalysis extends
037: ForwardDataflowAnalysis<StackDepth> {
038: public static final int TOP = -1;
039: public static final int BOTTOM = -2;
040:
041: private ConstantPoolGen cpg;
042:
043: /**
044: * Constructor.
045: *
046: * @param cpg the ConstantPoolGen of the method whose CFG we're performing the analysis on
047: * @param dfs DepthFirstSearch of the method's CFG
048: */
049: public StackDepthAnalysis(ConstantPoolGen cpg, DepthFirstSearch dfs) {
050: super (dfs);
051: this .cpg = cpg;
052: }
053:
054: public StackDepth createFact() {
055: return new StackDepth(TOP);
056: }
057:
058: public void makeFactTop(StackDepth fact) {
059: fact.setDepth(TOP);
060: }
061:
062: public boolean isTop(StackDepth fact) {
063: return fact.getDepth() == TOP;
064: }
065:
066: @Override
067: public boolean isFactValid(StackDepth fact) {
068: int depth = fact.getDepth();
069: return depth != TOP && depth != BOTTOM;
070: }
071:
072: public void copy(StackDepth source, StackDepth dest) {
073: dest.setDepth(source.getDepth());
074: }
075:
076: public void initEntryFact(StackDepth entryFact) {
077: entryFact.setDepth(0); // stack depth == 0 at entry to CFG
078: }
079:
080: public boolean same(StackDepth fact1, StackDepth fact2) {
081: return fact1.getDepth() == fact2.getDepth();
082: }
083:
084: @Override
085: public void transferInstruction(InstructionHandle handle,
086: BasicBlock basicBlock, StackDepth fact)
087: throws DataflowAnalysisException {
088: Instruction ins = handle.getInstruction();
089: int produced = ins.produceStack(cpg);
090: int consumed = ins.consumeStack(cpg);
091: if (produced == Constants.UNPREDICTABLE
092: || consumed == Constants.UNPREDICTABLE)
093: throw new IllegalStateException(
094: "Unpredictable stack delta for instruction: "
095: + handle);
096: int depth = fact.getDepth();
097: depth += (produced - consumed);
098: if (depth < 0)
099: fact.setDepth(BOTTOM);
100: else
101: fact.setDepth(depth);
102: }
103:
104: public void meetInto(StackDepth fact, Edge edge, StackDepth result) {
105: int a = fact.getDepth();
106: int b = result.getDepth();
107: int combined;
108:
109: if (a == TOP)
110: combined = b;
111: else if (b == TOP)
112: combined = a;
113: else if (a == BOTTOM || b == BOTTOM || a != b)
114: combined = BOTTOM;
115: else
116: combined = a;
117:
118: result.setDepth(combined);
119: }
120:
121: /**
122: * Command line driver, for testing.
123: */
124: public static void main(String[] argv) throws Exception {
125: if (argv.length != 1) {
126: System.out.println("Usage: "
127: + StackDepthAnalysis.class.getName()
128: + " <class file>");
129: System.exit(1);
130: }
131:
132: DataflowTestDriver<StackDepth, StackDepthAnalysis> driver = new DataflowTestDriver<StackDepth, StackDepthAnalysis>() {
133: @Override
134: public Dataflow<StackDepth, StackDepthAnalysis> createDataflow(
135: ClassContext classContext, Method method)
136: throws CFGBuilderException,
137: DataflowAnalysisException {
138:
139: DepthFirstSearch dfs = classContext
140: .getDepthFirstSearch(method);
141: CFG cfg = classContext.getCFG(method);
142:
143: StackDepthAnalysis analysis = new StackDepthAnalysis(
144: classContext.getConstantPoolGen(), dfs);
145: Dataflow<StackDepth, StackDepthAnalysis> dataflow = new Dataflow<StackDepth, StackDepthAnalysis>(
146: cfg, analysis);
147: dataflow.execute();
148:
149: return dataflow;
150: }
151: };
152:
153: driver.execute(argv[0]);
154: }
155: }
156:
157: // vim:ts=4
|