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