Home | History | Annotate | Download | only in evaluation
      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;
     22 
     23 import proguard.evaluation.value.Value;
     24 
     25 /**
     26  * This Stack saves additional information with stack elements, to keep track
     27  * of their origins and destinations.
     28  * <p>
     29  * The stack stores a given producer Value along with each Value it stores.
     30  * 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 TracedStack extends Stack
     37 {
     38     private Value producerValue;
     39     private Stack producerStack;
     40 
     41 
     42     /**
     43      * Creates a new TracedStack with a given maximum size.
     44      */
     45     public TracedStack(int maxSize)
     46     {
     47         super(maxSize);
     48 
     49         producerStack = new Stack(maxSize);
     50     }
     51 
     52 
     53     /**
     54      * Creates a new TracedStack that is a copy of the given TracedStack.
     55      */
     56     public TracedStack(TracedStack tracedStack)
     57     {
     58         super(tracedStack);
     59 
     60         producerStack = new Stack(tracedStack.producerStack);
     61     }
     62 
     63 
     64     /**
     65      * Sets the Value that will be stored along with all push and pop
     66      * instructions.
     67      */
     68     public void setProducerValue(Value producerValue)
     69     {
     70         this.producerValue = producerValue;
     71     }
     72 
     73 
     74     /**
     75      * Gets the specified producer Value from the stack, without disturbing it.
     76      * @param index the index of the stack element, counting from the bottom
     77      *              of the stack.
     78      * @return the producer value at the specified position.
     79      */
     80     public Value getBottomProducerValue(int index)
     81     {
     82         return producerStack.getBottom(index);
     83     }
     84 
     85 
     86     /**
     87      * Sets the specified producer Value on the stack, without disturbing it.
     88      * @param index the index of the stack element, counting from the bottom
     89      *              of the stack.
     90      * @param value the producer value to set.
     91      */
     92     public void setBottomProducerValue(int index, Value value)
     93     {
     94         producerStack.setBottom(index, value);
     95     }
     96 
     97 
     98     /**
     99      * Gets the specified producer Value from the stack, without disturbing it.
    100      * @param index the index of the stack element, counting from the top
    101      *              of the stack.
    102      * @return the producer value at the specified position.
    103      */
    104     public Value getTopProducerValue(int index)
    105     {
    106         return producerStack.getTop(index);
    107     }
    108 
    109 
    110     /**
    111      * Sets the specified producer Value on the stack, without disturbing it.
    112      * @param index the index of the stack element, counting from the top
    113      *              of the stack.
    114      * @param value the producer value to set.
    115      */
    116     public void setTopProducerValue(int index, Value value)
    117     {
    118         producerStack.setTop(index, value);
    119     }
    120 
    121 
    122     // Implementations for Stack.
    123 
    124     public void reset(int size)
    125     {
    126         super.reset(size);
    127 
    128         producerStack.reset(size);
    129     }
    130 
    131     public void copy(TracedStack other)
    132     {
    133         super.copy(other);
    134 
    135         producerStack.copy(other.producerStack);
    136     }
    137 
    138     public boolean generalize(TracedStack other)
    139     {
    140         return
    141             super.generalize(other) |
    142             producerStack.generalize(other.producerStack);
    143     }
    144 
    145     public void clear()
    146     {
    147         super.clear();
    148 
    149         producerStack.clear();
    150     }
    151 
    152     public void removeTop(int index)
    153     {
    154         super.removeTop(index);
    155 
    156         producerStack.removeTop(index);
    157     }
    158 
    159     public void push(Value value)
    160     {
    161         super.push(value);
    162 
    163         producerPush();
    164 
    165         // Account for the extra space required by Category 2 values.
    166         if (value.isCategory2())
    167         {
    168             producerPush();
    169         }
    170     }
    171 
    172     public Value pop()
    173     {
    174         Value value = super.pop();
    175 
    176         producerPop();
    177 
    178         // Account for the extra space required by Category 2 values.
    179         if (value.isCategory2())
    180         {
    181             producerPop();
    182         }
    183 
    184         return value;
    185     }
    186 
    187     public void pop1()
    188     {
    189         super.pop1();
    190 
    191         producerPop();
    192     }
    193 
    194     public void pop2()
    195     {
    196         super.pop2();
    197 
    198         producerPop();
    199         producerPop();
    200     }
    201 
    202     public void dup()
    203     {
    204         super.dup();
    205 
    206         producerPop();
    207         producerPush();
    208         producerPush();
    209     }
    210 
    211     public void dup_x1()
    212     {
    213         super.dup_x1();
    214 
    215         producerPop();
    216         producerPop();
    217         producerPush();
    218         producerPush();
    219         producerPush();
    220     }
    221 
    222     public void dup_x2()
    223     {
    224         super.dup_x2();
    225 
    226         producerPop();
    227         producerPop();
    228         producerPop();
    229         producerPush();
    230         producerPush();
    231         producerPush();
    232         producerPush();
    233     }
    234 
    235     public void dup2()
    236     {
    237         super.dup2();
    238 
    239         producerPop();
    240         producerPop();
    241         producerPush();
    242         producerPush();
    243         producerPush();
    244         producerPush();
    245     }
    246 
    247     public void dup2_x1()
    248     {
    249         super.dup2_x1();
    250 
    251         producerPop();
    252         producerPop();
    253         producerPop();
    254         producerPush();
    255         producerPush();
    256         producerPush();
    257         producerPush();
    258         producerPush();
    259     }
    260 
    261     public void dup2_x2()
    262     {
    263         super.dup2_x2();
    264 
    265         producerPop();
    266         producerPop();
    267         producerPop();
    268         producerPop();
    269         producerPush();
    270         producerPush();
    271         producerPush();
    272         producerPush();
    273         producerPush();
    274         producerPush();
    275     }
    276 
    277     public void swap()
    278     {
    279         super.swap();
    280 
    281         producerPop();
    282         producerPop();
    283         producerPush();
    284         producerPush();
    285     }
    286 
    287 
    288     // Implementations for Object.
    289 
    290     public boolean equals(Object object)
    291     {
    292         if (object == null ||
    293             this.getClass() != object.getClass())
    294         {
    295             return false;
    296         }
    297 
    298         TracedStack other = (TracedStack)object;
    299 
    300         return super.equals(object) &&
    301                this.producerStack.equals(other.producerStack);
    302     }
    303 
    304 
    305     public int hashCode()
    306     {
    307         return super.hashCode() ^
    308                producerStack.hashCode();
    309     }
    310 
    311 
    312     public String toString()
    313     {
    314         StringBuffer buffer = new StringBuffer();
    315 
    316         for (int index = 0; index < this.size(); index++)
    317         {
    318             Value value         = this.values[index];
    319             Value producerValue = producerStack.getBottom(index);
    320             buffer = buffer.append('[')
    321                            .append(producerValue == null ? "empty:" : producerValue.toString())
    322                            .append(value         == null ? "empty"  : value.toString())
    323                            .append(']');
    324         }
    325 
    326         return buffer.toString();
    327     }
    328 
    329 
    330     // Small utility methods.
    331 
    332     private void producerPush()
    333     {
    334         producerStack.push(producerValue);
    335     }
    336 
    337 
    338     private void producerPop()
    339     {
    340         producerStack.pop();
    341     }
    342 }
    343