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