• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
3  *             of Java bytecode.
4  *
5  * Copyright (c) 2002-2013 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, 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 
instructionOffsetValue()207     public final InstructionOffsetValue instructionOffsetValue()
208     {
209         return this;
210     }
211 
isSpecific()212     public boolean isSpecific()
213     {
214         return true;
215     }
216 
isParticular()217     public boolean isParticular()
218     {
219         return true;
220     }
221 
generalize(Value other)222     public final Value generalize(Value other)
223     {
224         return this.generalize(other.instructionOffsetValue());
225     }
226 
computationalType()227     public final int computationalType()
228     {
229         return TYPE_INSTRUCTION_OFFSET;
230     }
231 
internalType()232     public final String internalType()
233     {
234         return String.valueOf(ClassConstants.INTERNAL_TYPE_INT);
235     }
236 
237 
238     // Implementations for Object.
239 
equals(Object object)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 
hashCode()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 
toString()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