1/* 2 * ProGuard -- shrinking, optimization, obfuscation, and preverification 3 * of Java bytecode. 4 * 5 * Copyright (c) 2002-2014 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.Clazz; 24import proguard.classfile.util.ClassUtil; 25import proguard.util.ArrayUtil; 26 27/** 28 * This IdentifiedArrayReferenceValue represents an identified array reference 29 * value with its elements. 30 * 31 * @author Eric Lafortune 32 */ 33class DetailedArrayReferenceValue extends IdentifiedArrayReferenceValue 34{ 35 private static final int MAXIMUM_STORED_ARRAY_LENGTH = 32; 36 37 38 private final Value[] values; 39 40 41 /** 42 * Creates a new array reference value with the given ID. 43 */ 44 public DetailedArrayReferenceValue(String type, 45 Clazz referencedClass, 46 IntegerValue arrayLength, 47 ValueFactory valuefactory, 48 int id) 49 { 50 super(type, referencedClass, arrayLength, valuefactory, id); 51 52 // Is the array short enough to analyze? 53 if (arrayLength.isParticular() && 54 arrayLength.value() <= MAXIMUM_STORED_ARRAY_LENGTH) 55 { 56 // Initialize the values of the array. 57 InitialValueFactory initialValueFactory = 58 new InitialValueFactory(valuefactory); 59 60 String elementType = ClassUtil.isInternalArrayType(type) ? 61 type.substring(1) : 62 type; 63 64 this.values = new Value[arrayLength.value()]; 65 66 for (int index = 0; index < values.length; index++) 67 { 68 values[index] = initialValueFactory.createValue(elementType); 69 } 70 } 71 else 72 { 73 // Just ignore the values of the array. 74 this.values = null; 75 } 76 } 77 78 79 // Implementations for ReferenceValue. 80 81 public IntegerValue integerArrayLoad(IntegerValue indexValue, ValueFactory valueFactory) 82 { 83 Value value = arrayLoad(indexValue, valueFactory); 84 return value != null ? 85 value.integerValue() : 86 super.integerArrayLoad(indexValue, valueFactory); 87 } 88 89 90 public LongValue longArrayLoad(IntegerValue indexValue, ValueFactory valueFactory) 91 { 92 Value value = arrayLoad(indexValue, valueFactory); 93 return value != null ? 94 value.longValue() : 95 super.longArrayLoad(indexValue, valueFactory); 96 } 97 98 99 public FloatValue floatArrayLoad(IntegerValue indexValue, ValueFactory valueFactory) 100 { 101 Value value = arrayLoad(indexValue, valueFactory); 102 return value != null ? 103 value.floatValue() : 104 super.floatArrayLoad(indexValue, valueFactory); 105 } 106 107 108 public DoubleValue doubleArrayLoad(IntegerValue indexValue, ValueFactory valueFactory) 109 { 110 Value value = arrayLoad(indexValue, valueFactory); 111 return value != null ? 112 value.doubleValue() : 113 super.doubleArrayLoad(indexValue, valueFactory); 114 } 115 116 117 public ReferenceValue referenceArrayLoad(IntegerValue indexValue, ValueFactory valueFactory) 118 { 119 Value value = arrayLoad(indexValue, valueFactory); 120 return value != null ? 121 value.referenceValue() : 122 super.referenceArrayLoad(indexValue, valueFactory); 123 } 124 125 126 /** 127 * Returns the specified untyped value from the given array, or null if it 128 * is unknown. 129 */ 130 private Value arrayLoad(IntegerValue indexValue, ValueFactory valueFactory) 131 { 132 if (values != null && 133 indexValue.isParticular()) 134 { 135 int index = indexValue.value(); 136 if (index >=0 && 137 index < values.length) 138 { 139 return values[index]; 140 } 141 } 142 143 return null; 144 } 145 146 147 public void arrayStore(IntegerValue indexValue, Value value) 148 { 149 if (values != null) 150 { 151 if (indexValue.isParticular()) 152 { 153 int index = indexValue.value(); 154 if (index >=0 && 155 index < values.length) 156 { 157 values[index] = value; 158 } 159 } 160 else 161 { 162 for (int index = 0; index < values.length; index++) 163 { 164 values[index].generalize(value); 165 } 166 } 167 } 168 } 169 170 171 // Implementations of binary methods of ReferenceValue. 172 173 public ReferenceValue generalize(ReferenceValue other) 174 { 175 return other.generalize(this); 176 } 177 178 179 public int equal(ReferenceValue other) 180 { 181 return other.equal(this); 182 } 183 184 185// // Implementations of binary ReferenceValue methods with 186// // IdentifiedReferenceValue arguments. 187// 188// public ReferenceValue generalize(IdentifiedReferenceValue other) 189// { 190// return generalize((TypedReferenceValue)other); 191// } 192// 193// 194// public int equal(IdentifiedReferenceValue other) 195// { 196// return equal((TypedReferenceValue)other); 197// } 198// 199// 200// // Implementations of binary ReferenceValue methods with 201// // ArrayReferenceValue arguments. 202// 203// public ReferenceValue generalize(ArrayReferenceValue other) 204// { 205// return generalize((TypedReferenceValue)other); 206// } 207// 208// 209// public int equal(ArrayReferenceValue other) 210// { 211// return equal((TypedReferenceValue)other); 212// } 213// 214// 215// // Implementations of binary ReferenceValue methods with 216// // IdentifiedArrayReferenceValue arguments. 217// 218// public ReferenceValue generalize(IdentifiedArrayReferenceValue other) 219// { 220// return generalize((ArrayReferenceValue)other); 221// } 222// 223// 224// public int equal(IdentifiedArrayReferenceValue other) 225// { 226// return equal((ArrayReferenceValue)other); 227// } 228// 229// 230// // Implementations of binary ReferenceValue methods with 231// // DetailedArrayReferenceValue arguments. 232// 233// public ReferenceValue generalize(DetailedArrayReferenceValue other) 234// { 235// return generalize((IdentifiedArrayReferenceValue)other); 236// } 237// 238// 239// public int equal(DetailedArrayReferenceValue other) 240// { 241// return equal((IdentifiedArrayReferenceValue)other); 242// } 243 244 245 // Implementations for Value. 246 247 public boolean isParticular() 248 { 249 if (values == null) 250 { 251 return false; 252 } 253 254 for (int index = 0; index < values.length; index++) 255 { 256 if (!values[index].isParticular()) 257 { 258 return false; 259 } 260 } 261 262 return true; 263 } 264 265 266 // Implementations for Object. 267 268 public boolean equals(Object object) 269 { 270 return this == object || 271 super.equals(object) && 272 ArrayUtil.equalOrNull(this.values, ((DetailedArrayReferenceValue)object).values); 273 } 274 275 276 public int hashCode() 277 { 278 return super.hashCode() ^ 279 ArrayUtil.hashCodeOrNull(values); 280 } 281 282 283 public String toString() 284 { 285 if (values == null) 286 { 287 return super.toString(); 288 } 289 290 StringBuffer buffer = new StringBuffer(super.toString()); 291 292 buffer.append('{'); 293 for (int index = 0; index < values.length; index++) 294 { 295 buffer.append(values[index]); 296 buffer.append(index < values.length-1 ? ',' : '}'); 297 } 298 299 return buffer.toString(); 300 } 301}