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}