001: /*
002: * Bytecode Analysis Framework
003: * Copyright (C) 2005, 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 java.util.BitSet;
023: import java.util.HashMap;
024:
025: import org.apache.bcel.Constants;
026: import org.apache.bcel.classfile.Method;
027:
028: import edu.umd.cs.findbugs.ba.vna.ValueNumber;
029: import edu.umd.cs.findbugs.ba.vna.ValueNumberDataflow;
030: import edu.umd.cs.findbugs.classfile.CheckedAnalysisException;
031: import edu.umd.cs.findbugs.classfile.Global;
032: import edu.umd.cs.findbugs.classfile.MethodDescriptor;
033:
034: /**
035: * Front-end for LockDataflow that can avoid doing unnecessary work
036: * (e.g., actually performing the lock dataflow)
037: * if the method analyzed does not contain explicit
038: * monitorenter/monitorexit instructions.
039: *
040: * <p>Note that because LockSets use value numbers, ValueNumberAnalysis
041: * must be performed for all methods that are synchronized or contain
042: * explicit monitorenter/monitorexit instructions.</p>
043: *
044: * @see LockSet
045: * @see LockDataflow
046: * @see LockAnalysis
047: * @author David Hovemeyer
048: */
049: public class LockChecker {
050: private MethodDescriptor methodDescriptor;
051: private Method method;
052: private LockDataflow lockDataflow;
053: private ValueNumberDataflow vnaDataflow;
054: private HashMap<Location, LockSet> cache;
055:
056: /**
057: * Constructor.
058: */
059: public LockChecker(MethodDescriptor methodDescriptor) {
060: this .cache = new HashMap<Location, LockSet>();
061: this .methodDescriptor = methodDescriptor;
062: }
063:
064: /**
065: * Execute dataflow analyses (only if required).
066: * @throws CheckedAnalysisException
067: */
068: public void execute() throws CheckedAnalysisException {
069: method = Global.getAnalysisCache().getMethodAnalysis(
070: Method.class, methodDescriptor);
071: ClassContext classContext = Global.getAnalysisCache()
072: .getClassAnalysis(ClassContext.class,
073: methodDescriptor.getClassDescriptor());
074:
075: BitSet bytecodeSet = classContext.getBytecodeSet(method);
076: if (bytecodeSet == null)
077: return;
078: if (bytecodeSet.get(Constants.MONITORENTER)
079: || bytecodeSet.get(Constants.MONITOREXIT)) {
080: this .lockDataflow = classContext.getLockDataflow(method);
081: } else if (method.isSynchronized()) {
082: this .vnaDataflow = classContext
083: .getValueNumberDataflow(method); // will need this later
084: }
085: }
086:
087: /**
088: * Get LockSet at given Location.
089: *
090: * @param location the Location
091: * @return the LockSet at that Location
092: * @throws DataflowAnalysisException
093: */
094: public LockSet getFactAtLocation(Location location)
095: throws DataflowAnalysisException {
096: if (lockDataflow != null)
097: return lockDataflow.getFactAtLocation(location);
098: else {
099: LockSet lockSet = cache.get(location);
100: if (lockSet == null) {
101: lockSet = new LockSet();
102: lockSet.setDefaultLockCount(0);
103: if (method.isSynchronized() && !method.isStatic()) {
104: // LockSet contains just the "this" reference
105: ValueNumber instance = vnaDataflow.getAnalysis()
106: .getThisValue();
107: lockSet.setLockCount(instance.getNumber(), 1);
108: } else {
109: // LockSet is completely empty - nothing to do
110: }
111: cache.put(location, lockSet);
112: }
113: return lockSet;
114: }
115: }
116: }
|