Home | History | Annotate | Download | only in value
      1 /*
      2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
      3  *             of Java bytecode.
      4  *
      5  * Copyright (c) 2002-2009 Eric Lafortune (eric (at) 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 
     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