• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
21 package proguard.evaluation.value;
22 
23 import 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  */
31 public class InstructionOffsetValue extends Category1Value
32 {
33     public static final InstructionOffsetValue EMPTY_VALUE = new InstructionOffsetValue();
34 
35 
36     private int[] values;
37 
38 
InstructionOffsetValue()39     private InstructionOffsetValue()
40     {
41     }
42 
43 
InstructionOffsetValue(int value)44     public InstructionOffsetValue(int value)
45     {
46         this.values = new int[] { value };
47     }
48 
49 
InstructionOffsetValue(int[] values)50     public InstructionOffsetValue(int[] values)
51     {
52         this.values = values;
53     }
54 
55 
instructionOffsetCount()56     public int instructionOffsetCount()
57     {
58         return values == null ? 0 : values.length;
59     }
60 
61 
instructionOffset(int index)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      */
contains(int value)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      */
minimumValue()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      */
maximumValue()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      */
generalize(InstructionOffsetValue other)144     public final Value generalize(InstructionOffsetValue other)
145     {
146         // If the values array of either is null, we can return the other one.
147         int[] thisValues = this.values;
148         if (thisValues == null)
149         {
150             return other;
151         }
152 
153         int[] otherValues = other.values;
154         if (otherValues == null)
155         {
156             return this;
157         }
158 
159         // Compute the length of the union of the arrays.
160         int newLength = thisValues.length;
161         for (int index = 0; index < otherValues.length; index++)
162         {
163             if (!this.contains(otherValues[index]))
164             {
165                 newLength++;
166             }
167         }
168 
169         // If the length of the union array is equal to the length of the other
170         // values array, we can return it.
171         if (newLength == otherValues.length)
172         {
173             return other;
174         }
175 
176         // If the length of the union array is equal to the length of this
177         // values array, we can return it. We have to make sure that the other
178         // values are at the end. We'll just test one special case, with a
179         // single other value.
180         if (newLength == this.values.length &&
181             otherValues.length == 1 &&
182             thisValues[thisValues.length-1] == otherValues[0])
183         {
184             return this;
185         }
186 
187         // Create the union array.
188         int newIndex = 0;
189         int[] newValues = new int[newLength];
190 
191         // Is the length of the union array is equal to the sum of the lengths?
192         if (newLength == thisValues.length + otherValues.length)
193         {
194             // We can just copy all values, because they are unique.
195             System.arraycopy(thisValues, 0, newValues, 0, thisValues.length);
196 
197             newIndex = thisValues.length;
198         }
199         else
200         {
201             // Copy the values that are different from the other array.
202             for (int index = 0; index < thisValues.length; index++)
203             {
204                 if (!other.contains(thisValues[index]))
205                 {
206                     newValues[newIndex++] = thisValues[index];
207                 }
208             }
209         }
210 
211         // Copy the values from the other array.
212         System.arraycopy(otherValues, 0, newValues, newIndex, otherValues.length);
213 
214         return new InstructionOffsetValue(newValues);
215     }
216 
217 
218     // Implementations for Value.
219 
instructionOffsetValue()220     public final InstructionOffsetValue instructionOffsetValue()
221     {
222         return this;
223     }
224 
isSpecific()225     public boolean isSpecific()
226     {
227         return true;
228     }
229 
isParticular()230     public boolean isParticular()
231     {
232         return true;
233     }
234 
generalize(Value other)235     public final Value generalize(Value other)
236     {
237         return this.generalize(other.instructionOffsetValue());
238     }
239 
computationalType()240     public final int computationalType()
241     {
242         return TYPE_INSTRUCTION_OFFSET;
243     }
244 
internalType()245     public final String internalType()
246     {
247         return String.valueOf(ClassConstants.TYPE_INT);
248     }
249 
250 
251     // Implementations for Object.
252 
equals(Object object)253     public boolean equals(Object object)
254     {
255         if (object == null ||
256             this.getClass() != object.getClass())
257         {
258             return false;
259         }
260 
261         InstructionOffsetValue other = (InstructionOffsetValue)object;
262         if (this.values == other.values)
263         {
264             return true;
265         }
266 
267         if (this.values  == null ||
268             other.values == null ||
269             this.values.length != other.values.length)
270         {
271             return false;
272         }
273 
274         for (int index = 0; index < other.values.length; index++)
275         {
276             if (!this.contains(other.values[index]))
277             {
278                 return false;
279             }
280         }
281 
282         return true;
283     }
284 
285 
hashCode()286     public int hashCode()
287     {
288         int hashCode = this.getClass().hashCode();
289 
290         if (values != null)
291         {
292             for (int index = 0; index < values.length; index++)
293             {
294                 hashCode ^= values[index];
295             }
296         }
297 
298         return hashCode;
299     }
300 
301 
toString()302     public String toString()
303     {
304         StringBuffer buffer = new StringBuffer();
305 
306         if (values != null)
307         {
308             for (int index = 0; index < values.length; index++)
309             {
310                 if (index > 0)
311                 {
312                     buffer.append(',');
313                 }
314                 buffer.append(values[index]);
315             }
316         }
317 
318         return buffer.append(':').toString();
319     }
320 }
321