1/* 2 * ProGuard -- shrinking, optimization, obfuscation, and preverification 3 * of Java bytecode. 4 * 5 * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License as published by the Free 9 * Software Foundation; either version 2 of the License, or (at your option) 10 * any later version. 11 * 12 * This program is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15 * more details. 16 * 17 * You should have received a copy of the GNU General Public License along 18 * with this program; if not, write to the Free Software Foundation, Inc., 19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 */ 21package proguard.evaluation.value; 22 23import proguard.classfile.ClassConstants; 24 25/** 26 * This class represents a partially evaluated instruction offset. It can 27 * contain 0 or more specific instruction offsets. 28 * 29 * @author Eric Lafortune 30 */ 31public class InstructionOffsetValue extends Category1Value 32{ 33 public static final InstructionOffsetValue EMPTY_VALUE = new InstructionOffsetValue(); 34 35 36 private int[] values; 37 38 39 private InstructionOffsetValue() 40 { 41 } 42 43 44 public InstructionOffsetValue(int value) 45 { 46 this.values = new int[] { value }; 47 } 48 49 50 public InstructionOffsetValue(int[] values) 51 { 52 this.values = values; 53 } 54 55 56 public int instructionOffsetCount() 57 { 58 return values == null ? 0 : values.length; 59 } 60 61 62 public int instructionOffset(int index) 63 { 64 return values[index]; 65 } 66 67 68 /** 69 * Returns whether the given value is present in this list of instruction 70 * offsets. 71 */ 72 public boolean contains(int value) 73 { 74 if (values != null) 75 { 76 for (int index = 0; index < values.length; index++) 77 { 78 if (values[index] == value) 79 { 80 return true; 81 } 82 } 83 } 84 85 return false; 86 } 87 88 89 /** 90 * Returns the minimum value from this list of instruction offsets. 91 * Returns <code>Integer.MAX_VALUE</code> if the list is empty. 92 */ 93 public int minimumValue() 94 { 95 int minimumValue = Integer.MAX_VALUE; 96 97 if (values != null) 98 { 99 for (int index = 0; index < values.length; index++) 100 { 101 int value = values[index]; 102 103 if (minimumValue > value) 104 { 105 minimumValue = value; 106 } 107 } 108 } 109 110 return minimumValue; 111 } 112 113 114 /** 115 * Returns the maximum value from this list of instruction offsets. 116 * Returns <code>Integer.MIN_VALUE</code> if the list is empty. 117 */ 118 public int maximumValue() 119 { 120 int maximumValue = Integer.MIN_VALUE; 121 122 if (values != null) 123 { 124 for (int index = 0; index < values.length; index++) 125 { 126 int value = values[index]; 127 128 if (maximumValue < value) 129 { 130 maximumValue = value; 131 } 132 } 133 } 134 135 return maximumValue; 136 } 137 138 139 /** 140 * Returns the generalization of this InstructionOffsetValue and the given 141 * other InstructionOffsetValue. The values of the other InstructionOffsetValue 142 * are guaranteed to remain at the end of the list, in the same order. 143 */ 144 public final Value generalize(InstructionOffsetValue other) 145 { 146 // If the values array of either is null, return the other one. 147 if (this.values == null) 148 { 149 return other; 150 } 151 152 if (other.values == null) 153 { 154 return this; 155 } 156 157 // Compute the length of the union of the arrays. 158 int newLength = this.values.length; 159 for (int index = 0; index < other.values.length; index++) 160 { 161 if (!this.contains(other.values[index])) 162 { 163 newLength++; 164 } 165 } 166 167 // If the length of the union array is equal to the length of the values 168 // array of either, return it. 169 if (newLength == other.values.length) 170 { 171 return other; 172 } 173 174 // The ordering of the this array may not be right, so we can't just 175 // use it. 176 //if (newLength == this.values.length) 177 //{ 178 // return this; 179 //} 180 181 // Create the union array. 182 int[] newValues = new int[newLength]; 183 184 int newIndex = 0; 185 186 // Copy the values that are different from the other array. 187 for (int index = 0; index < this.values.length; index++) 188 { 189 if (!other.contains(this.values[index])) 190 { 191 newValues[newIndex++] = this.values[index]; 192 } 193 } 194 195 // Copy the values from the other array. 196 for (int index = 0; index < other.values.length; index++) 197 { 198 newValues[newIndex++] = other.values[index]; 199 } 200 201 return new InstructionOffsetValue(newValues); 202 } 203 204 205 // Implementations for Value. 206 207 public final InstructionOffsetValue instructionOffsetValue() 208 { 209 return this; 210 } 211 212 public boolean isSpecific() 213 { 214 return true; 215 } 216 217 public boolean isParticular() 218 { 219 return true; 220 } 221 222 public final Value generalize(Value other) 223 { 224 return this.generalize(other.instructionOffsetValue()); 225 } 226 227 public final int computationalType() 228 { 229 return TYPE_INSTRUCTION_OFFSET; 230 } 231 232 public final String internalType() 233 { 234 return String.valueOf(ClassConstants.INTERNAL_TYPE_INT); 235 } 236 237 238 // Implementations for Object. 239 240 public boolean equals(Object object) 241 { 242 if (object == null || 243 this.getClass() != object.getClass()) 244 { 245 return false; 246 } 247 248 InstructionOffsetValue other = (InstructionOffsetValue)object; 249 if (this.values == other.values) 250 { 251 return true; 252 } 253 254 if (this.values == null || 255 other.values == null || 256 this.values.length != other.values.length) 257 { 258 return false; 259 } 260 261 for (int index = 0; index < other.values.length; index++) 262 { 263 if (!this.contains(other.values[index])) 264 { 265 return false; 266 } 267 } 268 269 return true; 270 } 271 272 273 public int hashCode() 274 { 275 int hashCode = this.getClass().hashCode(); 276 277 if (values != null) 278 { 279 for (int index = 0; index < values.length; index++) 280 { 281 hashCode ^= values[index]; 282 } 283 } 284 285 return hashCode; 286 } 287 288 289 public String toString() 290 { 291 StringBuffer buffer = new StringBuffer(); 292 293 if (values != null) 294 { 295 for (int index = 0; index < values.length; index++) 296 { 297 if (index > 0) 298 { 299 buffer.append(','); 300 } 301 buffer.append(values[index]); 302 } 303 } 304 305 return buffer.append(':').toString(); 306 } 307} 308