TracedVariables.java revision db267bc191f906f55eaef21a27110cce2ec57fdf
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