TracedVariables.java revision 9f606f95f03a75961498803e24bee6799a7c0885
1/*
2 * ProGuard -- shrinking, optimization, obfuscation, and preverification
3 *             of Java bytecode.
4 *
5 * Copyright (c) 2002-2009 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 */
21package proguard.evaluation;
22
23import 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 * <p>
34 * In addition, an initialization index can be reset and retrieved, pointing
35 * to the most recent variable that has been initialized by a store operation.
36 *
37 * @author Eric Lafortune
38 */
39public class TracedVariables extends Variables
40{
41    public static final int NONE = -1;
42
43
44    private Value     producerValue;
45    private Variables producerVariables;
46    private int       initializationIndex;
47
48
49    /**
50     * Creates a new TracedVariables with a given size.
51     */
52    public TracedVariables(int size)
53    {
54        super(size);
55
56        producerVariables = new Variables(size);
57    }
58
59
60    /**
61     * Creates a new TracedVariables that is a copy of the given TracedVariables.
62     */
63    public TracedVariables(TracedVariables tracedVariables)
64    {
65        super(tracedVariables);
66
67        producerVariables = new Variables(tracedVariables.producerVariables);
68    }
69
70
71    /**
72     * Sets the Value that will be stored along with all store instructions.
73     */
74    public void setProducerValue(Value producerValue)
75    {
76        this.producerValue = producerValue;
77    }
78
79
80    /**
81     * Resets the initialization index.
82     */
83    public void resetInitialization()
84    {
85        initializationIndex = NONE;
86    }
87
88
89    /**
90     * Returns the most recent initialization index since it has been reset.
91     */
92    public int getInitializationIndex()
93    {
94        return initializationIndex;
95    }
96
97
98    /**
99     * Gets the producer Value for the specified variable, without disturbing it.
100     * @param index the variable index.
101     * @return the producer value of the given variable.
102     */
103    public Value getProducerValue(int index)
104    {
105        return producerVariables.getValue(index);
106    }
107
108
109    /**
110     * Sets the given producer Value for the specified variable, without
111     * disturbing it.
112     * @param index the variable index.
113     * @param value the producer value to set.
114     */
115    public void setProducerValue(int index, Value value)
116    {
117        producerVariables.store(index, value);
118    }
119
120
121    // Implementations for Variables.
122
123    public void reset(int size)
124    {
125        super.reset(size);
126
127        producerVariables.reset(size);
128    }
129
130    public void initialize(TracedVariables other)
131    {
132        super.initialize(other);
133
134        producerVariables.initialize(other.producerVariables);
135    }
136
137    public boolean generalize(TracedVariables other,
138                              boolean         clearConflictingOtherVariables)
139    {
140        boolean variablesChanged = super.generalize(other, clearConflictingOtherVariables);
141        boolean producersChanged = producerVariables.generalize(other.producerVariables, clearConflictingOtherVariables);
142        /* consumerVariables.generalize(other.consumerVariables)*/
143
144        // Clear any traces if a variable has become null.
145        if (variablesChanged)
146        {
147            for (int index = 0; index < size; index++)
148            {
149                if (values[index] == null)
150                {
151                    producerVariables.values[index] = null;
152
153                    if (clearConflictingOtherVariables)
154                    {
155                        other.producerVariables.values[index] = null;
156                    }
157                }
158            }
159        }
160
161        return variablesChanged || producersChanged;
162    }
163
164
165    public void store(int index, Value value)
166    {
167        // Is this store operation an initialization of the variable?
168        Value previousValue = super.load(index);
169        if (previousValue == null ||
170            previousValue.computationalType() != value.computationalType())
171        {
172            initializationIndex = index;
173        }
174
175        // Store the value itself in the variable.
176        super.store(index, value);
177
178        // Store the producer value in its producer variable.
179        producerVariables.store(index, producerValue);
180
181        // Account for the extra space required by Category 2 values.
182        if (value.isCategory2())
183        {
184            producerVariables.store(index+1, producerValue);
185        }
186    }
187
188
189    // Implementations for Object.
190
191    public boolean equals(Object object)
192    {
193        if (object == null ||
194            this.getClass() != object.getClass())
195        {
196            return false;
197        }
198
199        TracedVariables other = (TracedVariables)object;
200
201        return super.equals(object) &&
202               this.producerVariables.equals(other.producerVariables);
203    }
204
205
206    public int hashCode()
207    {
208        return super.hashCode() ^
209               producerVariables.hashCode();
210    }
211
212
213    public String toString()
214    {
215        StringBuffer buffer = new StringBuffer();
216
217        for (int index = 0; index < this.size(); index++)
218        {
219            Value value         = this.values[index];
220            Value producerValue = producerVariables.getValue(index);
221            buffer = buffer.append('[')
222                           .append(producerValue == null ? "empty:" : producerValue.toString())
223                           .append(value         == null ? "empty"  : value.toString())
224                           .append(']');
225        }
226
227        return buffer.toString();
228    }
229}
230