TracedStack.java revision 8a6199f0c36a778f22394364347a301b0b28e94b
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 */
21package proguard.evaluation;
22
23import 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 */
36public 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