Home | History | Annotate | Download | only in evaluation
      1 /*
      2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
      3  *             of Java bytecode.
      4  *
      5  * Copyright (c) 2002-2014 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;
     22 
     23 import proguard.evaluation.value.Value;
     24 
     25 /**
     26  * This Variables class saves additional information with variables, to keep
     27  * track of their origins.
     28  * <p>
     29  * The Variables class stores a given producer Value along with each Value it
     30  * stores. It then generalizes a given collected Value with the producer Value
     31  * of each Value it loads. The producer Value and the initial collected Value
     32  * can be set; the generalized collected Value can be retrieved.
     33  *
     34  * @author Eric Lafortune
     35  */
     36 public class TracedVariables extends Variables
     37 {
     38     public static final int NONE = -1;
     39 
     40 
     41     private Value     producerValue;
     42     private Variables producerVariables;
     43 
     44 
     45     /**
     46      * Creates a new TracedVariables with a given size.
     47      */
     48     public TracedVariables(int size)
     49     {
     50         super(size);
     51 
     52         producerVariables = new Variables(size);
     53     }
     54 
     55 
     56     /**
     57      * Creates a new TracedVariables that is a copy of the given TracedVariables.
     58      */
     59     public TracedVariables(TracedVariables tracedVariables)
     60     {
     61         super(tracedVariables);
     62 
     63         producerVariables = new Variables(tracedVariables.producerVariables);
     64     }
     65 
     66 
     67     /**
     68      * Sets the Value that will be stored along with all store instructions.
     69      */
     70     public void setProducerValue(Value producerValue)
     71     {
     72         this.producerValue = producerValue;
     73     }
     74 
     75 
     76     /**
     77      * Gets the producer Value for the specified variable, without disturbing it.
     78      * @param index the variable index.
     79      * @return the producer value of the given variable.
     80      */
     81     public Value getProducerValue(int index)
     82     {
     83         return producerVariables.getValue(index);
     84     }
     85 
     86 
     87     /**
     88      * Sets the given producer Value for the specified variable, without
     89      * disturbing it.
     90      * @param index the variable index.
     91      * @param value the producer value to set.
     92      */
     93     public void setProducerValue(int index, Value value)
     94     {
     95         producerVariables.store(index, value);
     96     }
     97 
     98 
     99     // Implementations for Variables.
    100 
    101     public void reset(int size)
    102     {
    103         super.reset(size);
    104 
    105         producerVariables.reset(size);
    106     }
    107 
    108     public void initialize(TracedVariables other)
    109     {
    110         super.initialize(other);
    111 
    112         producerVariables.initialize(other.producerVariables);
    113     }
    114 
    115     public boolean generalize(TracedVariables other,
    116                               boolean         clearConflictingOtherVariables)
    117     {
    118         boolean variablesChanged = super.generalize(other, clearConflictingOtherVariables);
    119         boolean producersChanged = producerVariables.generalize(other.producerVariables, clearConflictingOtherVariables);
    120         /* consumerVariables.generalize(other.consumerVariables)*/
    121 
    122         // Clear any traces if a variable has become null.
    123         if (variablesChanged)
    124         {
    125             for (int index = 0; index < size; index++)
    126             {
    127                 if (values[index] == null)
    128                 {
    129                     producerVariables.values[index] = null;
    130 
    131                     if (clearConflictingOtherVariables)
    132                     {
    133                         other.producerVariables.values[index] = null;
    134                     }
    135                 }
    136             }
    137         }
    138 
    139         return variablesChanged || producersChanged;
    140     }
    141 
    142 
    143     public void store(int index, Value value)
    144     {
    145         // Store the value itself in the variable.
    146         super.store(index, value);
    147 
    148         // Store the producer value in its producer variable.
    149         producerVariables.store(index, producerValue);
    150 
    151         // Account for the extra space required by Category 2 values.
    152         if (value.isCategory2())
    153         {
    154             producerVariables.store(index+1, producerValue);
    155         }
    156     }
    157 
    158 
    159     // Implementations for Object.
    160 
    161     public boolean equals(Object object)
    162     {
    163         if (object == null ||
    164             this.getClass() != object.getClass())
    165         {
    166             return false;
    167         }
    168 
    169         TracedVariables other = (TracedVariables)object;
    170 
    171         return super.equals(object) &&
    172                this.producerVariables.equals(other.producerVariables);
    173     }
    174 
    175 
    176     public int hashCode()
    177     {
    178         return super.hashCode() ^
    179                producerVariables.hashCode();
    180     }
    181 
    182 
    183     public String toString()
    184     {
    185         StringBuffer buffer = new StringBuffer();
    186 
    187         for (int index = 0; index < this.size(); index++)
    188         {
    189             Value value         = this.values[index];
    190             Value producerValue = producerVariables.getValue(index);
    191             buffer = buffer.append('[')
    192                            .append(producerValue == null ? "empty:" : producerValue.toString())
    193                            .append(value         == null ? "empty"  : value.toString())
    194                            .append(']');
    195         }
    196 
    197         return buffer.toString();
    198     }
    199 }
    200