/* * 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.vna; import edu.umd.cs.findbugs.util.MapCache; import edu.umd.cs.findbugs.util.Util; /** * A "value number" is a value produced somewhere in a methods. We use value * numbers as dataflow values in Frames. When two frame slots have the same * value number, then the same value is in both of those slots. * <p/> * <p> * Instances of ValueNumbers produced by the same {@link ValueNumberFactory * ValueNumberFactory} are unique, so reference equality may be used to * determine whether or not two value numbers are the same. In general, * ValueNumbers from different factories cannot be compared. * * @author David Hovemeyer * @see ValueNumberAnalysis */ public class ValueNumber implements Comparable<ValueNumber> { static MapCache<ValueNumber, ValueNumber> cache = new MapCache<ValueNumber, ValueNumber>(200); static int valueNumbersCreated = 0; static int valueNumbersReused = 0; public static int mergeFlags(int flags1, int flags2) { if (flags1 == -1) return flags2; if (flags2 == -1) return flags1; return flags1 & flags2; } public static synchronized ValueNumber createValueNumber(int number, int flags) { ValueNumber probe = new ValueNumber(number, flags); ValueNumber result = cache.get(probe); if (result != null) { valueNumbersReused++; return result; } cache.put(probe, probe); valueNumbersCreated++; return probe; } public static ValueNumber createValueNumber(int number) { return createValueNumber(number, 0); } static { Util.runLogAtShutdown(new Runnable() { public void run() { System.out.println("Value number statistics: " + valueNumbersCreated + " created, " + valueNumbersReused + " reused"); } }); } /** * The value number. */ final int number; /** * Flags representing meta information about the value. When value numbers are merged, * their flags should be the flags common to both. */ final int flags; /** * Flag specifying that this value was the return value of a called method. */ public static final int RETURN_VALUE = 1; public static final int ARRAY_VALUE = 2; public static final int CONSTANT_CLASS_OBJECT = 4; public static final int PHI_NODE = 8; public static final int CONSTANT_VALUE = 16; /** * Constructor. * * @param number * the value number */ private ValueNumber(int number) { this.number = number; this.flags = 0; } private ValueNumber(int number, int flags) { this.number = number; this.flags = flags; } public int getNumber() { return number; } public int getFlags() { return flags; } public boolean hasFlag(int flag) { return (flags & flag) == flag; } @Override public String toString() { if (flags != 0) return number + "(" + flags + "),"; return number + ","; } @Override public int hashCode() { return number * 17 + flags; } @Override public boolean equals(Object o) { if (o instanceof ValueNumber) { return number == ((ValueNumber) o).number && flags == ((ValueNumber) o).flags; } return false; } public int compareTo(ValueNumber other) { int result = number - other.number; if (result != 0) return result; return flags - other.flags; } } // vim:ts=4