001: /*
002: * ProGuard -- shrinking, optimization, obfuscation, and preverification
003: * of Java bytecode.
004: *
005: * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu)
006: *
007: * This program is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU General Public License as published by the Free
009: * Software Foundation; either version 2 of the License, or (at your option)
010: * any later version.
011: *
012: * This program is distributed in the hope that it will be useful, but WITHOUT
013: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
014: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
015: * more details.
016: *
017: * You should have received a copy of the GNU General Public License along
018: * with this program; if not, write to the Free Software Foundation, Inc.,
019: * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020: */
021: package proguard.evaluation.value;
022:
023: import proguard.classfile.ClassConstants;
024:
025: /**
026: * This class represents a partially evaluated instruction offset. It can
027: * contain 0 or more specific instruction offsets.
028: *
029: * @author Eric Lafortune
030: */
031: public class InstructionOffsetValue extends Category1Value {
032: public static final InstructionOffsetValue EMPTY_VALUE = new InstructionOffsetValue();
033:
034: private int[] values;
035:
036: private InstructionOffsetValue() {
037: }
038:
039: public InstructionOffsetValue(int value) {
040: this .values = new int[] { value };
041: }
042:
043: public InstructionOffsetValue(int[] values) {
044: this .values = values;
045: }
046:
047: public int instructionOffsetCount() {
048: return values == null ? 0 : values.length;
049: }
050:
051: public int instructionOffset(int index) {
052: return values[index];
053: }
054:
055: /**
056: * Returns whether the given value is present in this list of instruction
057: * offsets.
058: */
059: public boolean contains(int value) {
060: if (values != null) {
061: for (int index = 0; index < values.length; index++) {
062: if (values[index] == value) {
063: return true;
064: }
065: }
066: }
067:
068: return false;
069: }
070:
071: /**
072: * Returns the minimum value from this list of instruction offsets.
073: * Returns <code>Integer.MAX_VALUE</code> if the list is empty.
074: */
075: public int minimumValue() {
076: int minimumValue = Integer.MAX_VALUE;
077:
078: if (values != null) {
079: for (int index = 0; index < values.length; index++) {
080: int value = values[index];
081:
082: if (minimumValue > value) {
083: minimumValue = value;
084: }
085: }
086: }
087:
088: return minimumValue;
089: }
090:
091: /**
092: * Returns the maximum value from this list of instruction offsets.
093: * Returns <code>Integer.MIN_VALUE</code> if the list is empty.
094: */
095: public int maximumValue() {
096: int maximumValue = Integer.MIN_VALUE;
097:
098: if (values != null) {
099: for (int index = 0; index < values.length; index++) {
100: int value = values[index];
101:
102: if (maximumValue < value) {
103: maximumValue = value;
104: }
105: }
106: }
107:
108: return maximumValue;
109: }
110:
111: /**
112: * Returns the generalization of this InstructionOffsetValue and the given
113: * other InstructionOffsetValue. The values of the other InstructionOffsetValue
114: * are guaranteed to remain at the end of the list, in the same order.
115: */
116: public final Value generalize(InstructionOffsetValue other) {
117: // If the values array of either is null, return the other one.
118: if (this .values == null) {
119: return other;
120: }
121:
122: if (other.values == null) {
123: return this ;
124: }
125:
126: // Compute the length of the union of the arrays.
127: int newLength = this .values.length;
128: for (int index = 0; index < other.values.length; index++) {
129: if (!this .contains(other.values[index])) {
130: newLength++;
131: }
132: }
133:
134: // If the length of the union array is equal to the length of the values
135: // array of either, return it.
136: if (newLength == other.values.length) {
137: return other;
138: }
139:
140: // The ordering of the this array may not be right, so we can't just
141: // use it.
142: //if (newLength == this.values.length)
143: //{
144: // return this;
145: //}
146:
147: // Create the union array.
148: int[] newValues = new int[newLength];
149:
150: int newIndex = 0;
151:
152: // Copy the values that are different from the other array.
153: for (int index = 0; index < this .values.length; index++) {
154: if (!other.contains(this .values[index])) {
155: newValues[newIndex++] = this .values[index];
156: }
157: }
158:
159: // Copy the values from the other array.
160: for (int index = 0; index < other.values.length; index++) {
161: newValues[newIndex++] = other.values[index];
162: }
163:
164: return new InstructionOffsetValue(newValues);
165: }
166:
167: // Implementations for Value.
168:
169: public final InstructionOffsetValue instructionOffsetValue() {
170: return this ;
171: }
172:
173: public final Value generalize(Value other) {
174: return this .generalize(other.instructionOffsetValue());
175: }
176:
177: public final int computationalType() {
178: return TYPE_INSTRUCTION_OFFSET;
179: }
180:
181: public final String internalType() {
182: return String.valueOf(ClassConstants.INTERNAL_TYPE_INT);
183: }
184:
185: // Implementations for Object.
186:
187: public boolean equals(Object object) {
188: if (object == null || this .getClass() != object.getClass()) {
189: return false;
190: }
191:
192: InstructionOffsetValue other = (InstructionOffsetValue) object;
193: if (this .values == other.values) {
194: return true;
195: }
196:
197: if (this .values == null || other.values == null
198: || this .values.length != other.values.length) {
199: return false;
200: }
201:
202: for (int index = 0; index < other.values.length; index++) {
203: if (!this .contains(other.values[index])) {
204: return false;
205: }
206: }
207:
208: return true;
209: }
210:
211: public int hashCode() {
212: int hashCode = this .getClass().hashCode();
213:
214: if (values != null) {
215: for (int index = 0; index < values.length; index++) {
216: hashCode ^= values[index];
217: }
218: }
219:
220: return hashCode;
221: }
222:
223: public String toString() {
224: StringBuffer buffer = new StringBuffer("o:");
225:
226: if (values != null) {
227: for (int index = 0; index < values.length; index++) {
228: if (index > 0) {
229: buffer.append(',');
230: }
231: buffer.append(values[index]);
232: }
233: }
234:
235: return buffer.toString();
236: }
237: }
|